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
ServerConnection(VolumeManager * volumeManager,ExtendedServerInfo * serverInfo)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
~ServerConnection()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
Init(vnode_id connectionBrokenTarget)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
Close()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
IsConnected()140 ServerConnection::IsConnected()
141 {
142 return fConnected;
143 }
144
145 // GetRequestConnection
146 RequestConnection*
GetRequestConnection() const147 ServerConnection::GetRequestConnection() const
148 {
149 return fConnection;
150 }
151
152 // AddVolume
153 status_t
AddVolume(ShareVolume * volume)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
RemoveVolume(ShareVolume * volume)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*
GetVolume(int32 volumeID)176 ServerConnection::GetVolume(int32 volumeID)
177 {
178 AutoLocker<Locker> _(fLock);
179 return fVolumes->Get(volumeID);
180 }
181
182 // VisitConnectionBrokenRequest
183 status_t
VisitConnectionBrokenRequest(ConnectionBrokenRequest * request)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
VisitNodeMonitoringRequest(NodeMonitoringRequest * request)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