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