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