#include "ServerConnection.h"
#include <AutoDeleter.h>
#include <ByteOrder.h>
#include <HashMap.h>
#include "Connection.h"
#include "ConnectionFactory.h"
#include "DebugSupport.h"
#include "ExtendedServerInfo.h"
#include "RequestConnection.h"
#include "ShareVolume.h"
#include "VolumeEvent.h"
#include "VolumeManager.h"
struct ServerConnection::VolumeMap : HashMap<HashKey32<int32>, ShareVolume*> {
};
ServerConnection::ServerConnection(VolumeManager* volumeManager,
ExtendedServerInfo* serverInfo)
:
BReferenceable(),
RequestHandler(),
fLock("server connection"),
fVolumeManager(volumeManager),
fServerInfo(serverInfo),
fConnection(NULL),
fVolumes(NULL),
fConnectionBrokenEvent(NULL),
fConnected(false)
{
if (fServerInfo)
fServerInfo->AcquireReference();
}
ServerConnection::~ServerConnection()
{
PRINT(("ServerConnection::~ServerConnection()\n"))
Close();
delete fConnection;
delete fVolumes;
if (fConnectionBrokenEvent)
fConnectionBrokenEvent->ReleaseReference();
if (fServerInfo)
fServerInfo->ReleaseReference();
}
status_t
ServerConnection::Init(vnode_id connectionBrokenTarget)
{
if (!fServerInfo)
RETURN_ERROR(B_BAD_VALUE);
fConnectionBrokenEvent
= new(std::nothrow) ConnectionBrokenEvent(connectionBrokenTarget);
if (!fConnectionBrokenEvent)
return B_NO_MEMORY;
const char* connectionMethod = fServerInfo->GetConnectionMethod();
HashString server;
status_t error = fServerInfo->GetAddress().GetString(&server, false);
if (error != B_OK)
RETURN_ERROR(error);
fVolumes = new(std::nothrow) VolumeMap;
if (!fVolumes)
RETURN_ERROR(B_NO_MEMORY);
error = fVolumes->InitCheck();
if (error != B_OK)
RETURN_ERROR(error);
Connection* connection;
ConnectionFactory factory;
error = factory.CreateConnection(connectionMethod, server.GetString(),
&connection);
if (error != B_OK)
RETURN_ERROR(error);
fConnection = new(std::nothrow) RequestConnection(connection, this);
if (!fConnection) {
delete connection;
RETURN_ERROR(B_NO_MEMORY);
}
error = fConnection->Init();
if (error != B_OK)
return error;
InitConnectionRequest request;
request.bigEndian = B_HOST_IS_BENDIAN;
Request* _reply;
error = fConnection->SendRequest(&request, &_reply);
if (error != B_OK)
return error;
ObjectDeleter<Request> replyDeleter(_reply);
InitConnectionReply* reply = dynamic_cast<InitConnectionReply*>(_reply);
if (!reply)
return B_BAD_DATA;
if (reply->error != B_OK)
return reply->error;
fConnected = true;
return B_OK;
}
void
ServerConnection::Close()
{
{
AutoLocker<Locker> locker(fLock);
fConnected = false;
}
if (fConnection)
fConnection->Close();
}
bool
ServerConnection::IsConnected()
{
return fConnected;
}
RequestConnection*
ServerConnection::GetRequestConnection() const
{
return fConnection;
}
status_t
ServerConnection::AddVolume(ShareVolume* volume)
{
if (!volume)
return B_BAD_VALUE;
AutoLocker<Locker> _(fLock);
return fVolumes->Put(volume->GetID(), volume);
}
void
ServerConnection::RemoveVolume(ShareVolume* volume)
{
if (!volume)
return;
AutoLocker<Locker> _(fLock);
fVolumes->Remove(volume->GetID());
}
ShareVolume*
ServerConnection::GetVolume(int32 volumeID)
{
AutoLocker<Locker> _(fLock);
return fVolumes->Get(volumeID);
}
status_t
ServerConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request)
{
AutoLocker<Locker> locker(fLock);
if (fConnected) {
fConnected = false;
fVolumeManager->SendVolumeEvent(fConnectionBrokenEvent);
}
return B_OK;
}
status_t
ServerConnection::VisitNodeMonitoringRequest(NodeMonitoringRequest* request)
{
AutoLocker<Locker> locker(fLock);
if (fConnected) {
if (ShareVolume* volume = GetVolume(request->volumeID)) {
if (fVolumeManager->GetVolume(volume->GetRootID())) {
locker.Unlock();
if (request->opcode == B_DEVICE_UNMOUNTED)
volume->SetUnmounting(true);
else
volume->ProcessNodeMonitoringRequest(request);
volume->PutVolume();
}
}
}
return B_OK;
}