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