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 19 struct ServerConnection::VolumeMap : HashMap<HashKey32<int32>, ShareVolume*> { 20 }; 21 22 23 // constructor 24 ServerConnection::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 42 ServerConnection::~ServerConnection() 43 { 44 PRINT(("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 55 status_t 56 ServerConnection::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 125 void 126 ServerConnection::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 139 bool 140 ServerConnection::IsConnected() 141 { 142 return fConnected; 143 } 144 145 // GetRequestConnection 146 RequestConnection* 147 ServerConnection::GetRequestConnection() const 148 { 149 return fConnection; 150 } 151 152 // AddVolume 153 status_t 154 ServerConnection::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 164 void 165 ServerConnection::RemoveVolume(ShareVolume* volume) 166 { 167 if (!volume) 168 return; 169 170 AutoLocker<Locker> _(fLock); 171 fVolumes->Remove(volume->GetID()); 172 } 173 174 // GetVolume 175 ShareVolume* 176 ServerConnection::GetVolume(int32 volumeID) 177 { 178 AutoLocker<Locker> _(fLock); 179 return fVolumes->Get(volumeID); 180 } 181 182 // VisitConnectionBrokenRequest 183 status_t 184 ServerConnection::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 195 status_t 196 ServerConnection::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