1// ServerConnection.cpp 2 3#include <ByteOrder.h> 4#include <SupportDefs.h> 5 6#include "AutoDeleter.h" 7#include "Connection.h" 8#include "ConnectionFactory.h" 9#include "Debug.h" 10#include "ExtendedServerInfo.h" 11#include "HashMap.h" 12#include "RequestConnection.h" 13#include "ServerConnection.h" 14#include "ShareVolume.h" 15#include "VolumeEvent.h" 16#include "VolumeManager.h" 17 18// VolumeMap 19struct ServerConnection::VolumeMap : HashMap<HashKey32<int32>, ShareVolume*> { 20}; 21 22 23// constructor 24ServerConnection::ServerConnection(VolumeManager* volumeManager, 25 ExtendedServerInfo* serverInfo) 26 : Referencable(true), 27 RequestHandler(), 28 fLock("server connection"), 29 fVolumeManager(volumeManager), 30 fServerInfo(serverInfo), 31 fConnection(NULL), 32 fVolumes(NULL), 33 fConnectionBrokenEvent(NULL), 34 fConnected(false) 35{ 36 if (fServerInfo) 37 fServerInfo->AddReference(); 38} 39 40// destructor 41ServerConnection::~ServerConnection() 42{ 43PRINT(("ServerConnection::~ServerConnection()\n")) 44 Close(); 45 delete fConnection; 46 delete fVolumes; 47 if (fConnectionBrokenEvent) 48 fConnectionBrokenEvent->RemoveReference(); 49 if (fServerInfo) 50 fServerInfo->RemoveReference(); 51} 52 53// Init 54status_t 55ServerConnection::Init(vnode_id connectionBrokenTarget) 56{ 57 if (!fServerInfo) 58 RETURN_ERROR(B_BAD_VALUE); 59 60 // create a connection broken event 61 fConnectionBrokenEvent 62 = new(nothrow) ConnectionBrokenEvent(connectionBrokenTarget); 63 if (!fConnectionBrokenEvent) 64 return B_NO_MEMORY; 65 66 // get the server address 67 const char* connectionMethod = fServerInfo->GetConnectionMethod(); 68 String server; 69 status_t error = fServerInfo->GetAddress().GetString(&server, false); 70 if (error != B_OK) 71 RETURN_ERROR(error); 72 73 // create the volume map 74 fVolumes = new(nothrow) VolumeMap; 75 if (!fVolumes) 76 RETURN_ERROR(B_NO_MEMORY); 77 error = fVolumes->InitCheck(); 78 if (error != B_OK) 79 RETURN_ERROR(error); 80 81 // establish the connection 82 Connection* connection; 83 ConnectionFactory factory; 84 error = factory.CreateConnection(connectionMethod, server.GetString(), 85 &connection); 86 if (error != B_OK) 87 RETURN_ERROR(error); 88 89 // create a request connection 90 fConnection = new(nothrow) RequestConnection(connection, this); 91 if (!fConnection) { 92 delete connection; 93 RETURN_ERROR(B_NO_MEMORY); 94 } 95 error = fConnection->Init(); 96 if (error != B_OK) 97 return error; 98 99 // send an `init connection request' 100 101 // prepare the request 102 InitConnectionRequest request; 103 request.bigEndian = B_HOST_IS_BENDIAN; 104 105 // send the request 106 Request* _reply; 107 error = fConnection->SendRequest(&request, &_reply); 108 if (error != B_OK) 109 return error; 110 ObjectDeleter<Request> replyDeleter(_reply); 111 112 // everything OK? 113 InitConnectionReply* reply = dynamic_cast<InitConnectionReply*>(_reply); 114 if (!reply) 115 return B_BAD_DATA; 116 if (reply->error != B_OK) 117 return reply->error; 118 119 fConnected = true; 120 return B_OK; 121} 122 123// Close 124void 125ServerConnection::Close() 126{ 127 // mark the connection closed (events won't be delivered anymore) 128 { 129 AutoLocker<Locker> locker(fLock); 130 fConnected = false; 131 } 132 133 if (fConnection) 134 fConnection->Close(); 135} 136 137// IsConnected 138bool 139ServerConnection::IsConnected() 140{ 141 return fConnected; 142} 143 144// GetRequestConnection 145RequestConnection* 146ServerConnection::GetRequestConnection() const 147{ 148 return fConnection; 149} 150 151// AddVolume 152status_t 153ServerConnection::AddVolume(ShareVolume* volume) 154{ 155 if (!volume) 156 return B_BAD_VALUE; 157 158 AutoLocker<Locker> _(fLock); 159 return fVolumes->Put(volume->GetID(), volume); 160} 161 162// RemoveVolume 163void 164ServerConnection::RemoveVolume(ShareVolume* volume) 165{ 166 if (!volume) 167 return; 168 169 AutoLocker<Locker> _(fLock); 170 fVolumes->Remove(volume->GetID()); 171} 172 173// GetVolume 174ShareVolume* 175ServerConnection::GetVolume(int32 volumeID) 176{ 177 AutoLocker<Locker> _(fLock); 178 return fVolumes->Get(volumeID); 179} 180 181// VisitConnectionBrokenRequest 182status_t 183ServerConnection::VisitConnectionBrokenRequest(ConnectionBrokenRequest* request) 184{ 185 AutoLocker<Locker> locker(fLock); 186 if (fConnected) { 187 fConnected = false; 188 fVolumeManager->SendVolumeEvent(fConnectionBrokenEvent); 189 } 190 return B_OK; 191} 192 193// VisitNodeMonitoringRequest 194status_t 195ServerConnection::VisitNodeMonitoringRequest(NodeMonitoringRequest* request) 196{ 197 AutoLocker<Locker> locker(fLock); 198 if (fConnected) { 199 if (ShareVolume* volume = GetVolume(request->volumeID)) { 200 if (fVolumeManager->GetVolume(volume->GetRootID())) { 201 locker.Unlock(); 202 if (request->opcode == B_DEVICE_UNMOUNTED) 203 volume->SetUnmounting(true); 204 else 205 volume->ProcessNodeMonitoringRequest(request); 206 volume->PutVolume(); 207 } 208 } 209 } 210 return B_OK; 211} 212 213