1// ServerManager.cpp
2
3#include "ServerManager.h"
4
5#include <errno.h>
6#include <unistd.h>
7
8#ifdef HAIKU_TARGET_PLATFORM_BEOS
9#	include <socket.h>
10#else
11#	include <netinet/in.h>
12#	include <sys/socket.h>
13#endif
14
15#include <AutoDeleter.h>
16#include <AutoLocker.h>
17#include <ByteOrder.h>
18#include <HashMap.h>
19
20#include "Compatibility.h"
21#include "DebugSupport.h"
22#include "ExtendedServerInfo.h"
23#include "InsecureChannel.h"
24#include "NetAddress.h"
25#include "NetFSDefs.h"
26#include "RequestChannel.h"
27#include "Requests.h"
28#include "TaskManager.h"
29#include "Utils.h"
30
31// server info states
32enum {
33	STATE_ADDING,
34	STATE_REMOVING,
35	STATE_UPDATING,
36	STATE_READY,
37	STATE_OBSOLETE
38};
39
40
41// ServerInfoMap
42struct ServerManager::ServerInfoMap : HashMap<NetAddress, ExtendedServerInfo*> {
43};
44
45// ServerInfoTask
46class ServerManager::ServerInfoTask : public Task {
47public:
48	ServerInfoTask(ServerManager* manager, ExtendedServerInfo* oldServerInfo,
49		ExtendedServerInfo* serverInfo)
50		: Task("server info task"),
51		  fServerManager(manager),
52		  fOldServerInfo(oldServerInfo),
53		  fServerInfo(serverInfo),
54		  fFD(-1),
55		  fSuccess(false)
56	{
57		if (fServerInfo)
58			fServerInfo->AcquireReference();
59	}
60
61	virtual ~ServerInfoTask()
62	{
63		Stop();
64		if (!fSuccess) {
65			if (fOldServerInfo)
66				fServerManager->_UpdatingServerFailed(fServerInfo);
67			else
68				fServerManager->_AddingServerFailed(fServerInfo);
69		}
70		if (fServerInfo)
71			fServerInfo->ReleaseReference();
72	}
73
74	status_t Init()
75	{
76		// create a socket
77		fFD = socket(AF_INET, SOCK_STREAM, 0);
78		if (fFD < 0) {
79			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to create "
80				"socket: %s\n", strerror(errno));
81			return errno;
82		}
83		return B_OK;
84	}
85
86	virtual status_t Execute()
87	{
88		// connect to the server info port
89		sockaddr_in addr = fServerInfo->GetAddress().GetAddress();
90		addr.sin_port = htons(kDefaultServerInfoPort);
91		if (connect(fFD, (sockaddr*)&addr, sizeof(addr)) < 0) {
92			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to connect "
93				"to server info port: %s\n", strerror(errno));
94			return errno;
95		}
96
97		// create a channel
98		InsecureChannel channel(fFD);
99
100		// receive a request
101		RequestChannel requestChannel(&channel);
102		Request* _request;
103		status_t error = requestChannel.ReceiveRequest(&_request);
104		if (error != B_OK) {
105			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to receive "
106				"server info request: %s\n", strerror(errno));
107			return error;
108		}
109		ObjectDeleter<Request> requestDeleter(_request);
110		ServerInfoRequest* request = dynamic_cast<ServerInfoRequest*>(_request);
111		if (!request) {
112			ERROR("ServerManager::ServerInfoTask: ERROR: Received request "
113				"is not a server info request.\n");
114			return B_BAD_DATA;
115		}
116
117		// get the info
118		error = fServerInfo->SetTo(&request->serverInfo);
119		if (error != B_OK)
120			return error;
121
122		// notify the manager
123		if (fOldServerInfo)
124			fServerManager->_ServerUpdated(fServerInfo);
125		else
126			fServerManager->_ServerAdded(fServerInfo);
127
128		fSuccess = true;
129		return B_OK;
130	}
131
132	virtual void Stop()
133	{
134		safe_closesocket(fFD);
135	}
136
137private:
138	ServerManager*		fServerManager;
139	ExtendedServerInfo*	fOldServerInfo;
140	ExtendedServerInfo*	fServerInfo;
141	int32				fFD;
142	bool				fUpdate;
143	bool				fSuccess;
144};
145
146
147// #pragma mark -
148
149// constructor
150ServerManager::ServerManager(Listener* listener)
151	: fLock("server manager"),
152	  fBroadcastListener(-1),
153	  fBroadcastListenerSocket(-1),
154	  fListener(listener),
155	  fTerminating(false)
156{
157}
158
159// destructor
160ServerManager::~ServerManager()
161{
162	Uninit();
163}
164
165// Init
166status_t
167ServerManager::Init()
168{
169	// create the server info map
170	fServerInfos = new(std::nothrow) ServerInfoMap();
171	if (!fServerInfos)
172		RETURN_ERROR(B_NO_MEMORY);
173	status_t error = fServerInfos->InitCheck();
174	if (error != B_OK)
175		RETURN_ERROR(error);
176
177	// init the broadcast listener
178	error = _InitBroadcastListener();
179	if (error != B_OK)
180		RETURN_ERROR(error);
181
182	return B_OK;
183}
184
185// Uninit
186void
187ServerManager::Uninit()
188{
189	// stop the broadcast listener
190	fTerminating = true;
191	_TerminateBroadcastListener();
192
193	// remove all server infos
194	AutoLocker<Locker> _(fLock);
195	for (ServerInfoMap::Iterator it = fServerInfos->GetIterator();
196		 it.HasNext();) {
197		ExtendedServerInfo* serverInfo = it.Next().value;
198		serverInfo->ReleaseReference();
199	}
200	fServerInfos->Clear();
201}
202
203// Run
204void
205ServerManager::Run()
206{
207	// start the broadcast listener
208	resume_thread(fBroadcastListener);
209}
210
211// GetServerInfo
212ExtendedServerInfo*
213ServerManager::GetServerInfo(const NetAddress& address)
214{
215	AutoLocker<Locker> _(fLock);
216	ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
217	if (!serverInfo
218		|| (serverInfo->GetState() != STATE_READY
219			&& serverInfo->GetState() != STATE_UPDATING)) {
220		return NULL;
221	}
222	serverInfo->AcquireReference();
223	return serverInfo;
224}
225
226// AddServer
227status_t
228ServerManager::AddServer(const NetAddress& address)
229{
230	// check, if the server is already known
231	AutoLocker<Locker> locker(fLock);
232	ExtendedServerInfo* oldInfo = fServerInfos->Get(address);
233	if (oldInfo)
234		return B_OK;
235
236	// create a new server info and add it
237	ExtendedServerInfo* serverInfo
238		= new(std::nothrow) ExtendedServerInfo(address);
239	if (!serverInfo)
240		return B_NO_MEMORY;
241	serverInfo->SetState(STATE_ADDING);
242	BReference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
243	status_t error = fServerInfos->Put(address, serverInfo);
244	if (error != B_OK)
245		return error;
246	serverInfo->AcquireReference();
247
248	// create and execute the task -- it will do what is necessary
249	ServerInfoTask task(this, NULL, serverInfo);
250	error = task.Init();
251	if (error != B_OK)
252		return error;
253
254	locker.Unlock();
255	return task.Execute();
256}
257
258// RemoveServer
259void
260ServerManager::RemoveServer(const NetAddress& address)
261{
262	// check, if the server is known at all
263	AutoLocker<Locker> locker(fLock);
264	ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
265	if (!serverInfo)
266		return;
267
268	// If its current state is not STATE_READY, then an info thread is currently
269	// trying to add/update it. We mark the info STATE_REMOVING, which will
270	// remove the info as soon as possible.
271	if (serverInfo->GetState() == STATE_READY) {
272		BReference<ExtendedServerInfo> _(serverInfo);
273		_RemoveServer(serverInfo);
274		locker.Unlock();
275		fListener->ServerRemoved(serverInfo);
276	} else
277		serverInfo->SetState(STATE_REMOVING);
278}
279
280// _BroadcastListenerEntry
281int32
282ServerManager::_BroadcastListenerEntry(void* data)
283{
284	return ((ServerManager*)data)->_BroadcastListener();
285}
286
287// _BroadcastListener
288int32
289ServerManager::_BroadcastListener()
290{
291	TaskManager taskManager;
292	while (!fTerminating) {
293		taskManager.RemoveDoneTasks();
294
295		// receive
296		sockaddr_in addr;
297		addr.sin_family = AF_INET;
298		addr.sin_port = htons(kDefaultBroadcastPort);
299		addr.sin_addr.s_addr = INADDR_ANY;
300		socklen_t addrSize = sizeof(addr);
301		BroadcastMessage message;
302//PRINT(("ServerManager::_BroadcastListener(): recvfrom()...\n"));
303		ssize_t bytesRead = recvfrom(fBroadcastListenerSocket, &message,
304			sizeof(message), 0, (sockaddr*)&addr, &addrSize);
305		if (bytesRead < 0) {
306			PRINT("ServerManager::_BroadcastListener(): recvfrom() "
307				"failed: %s\n", strerror(errno));
308			continue;
309		}
310
311		// check message size, magic, and protocol version
312		if (bytesRead != sizeof(BroadcastMessage)) {
313			PRINT("ServerManager::_BroadcastListener(): received "
314				"%ld bytes, but it should be %lu\n", bytesRead,
315				sizeof(BroadcastMessage));
316			continue;
317		}
318		if (message.magic != B_HOST_TO_BENDIAN_INT32(BROADCAST_MESSAGE_MAGIC)) {
319			PRINT("ServerManager::_BroadcastListener(): message has"
320				" bad magic.\n");
321			continue;
322		}
323		if (message.protocolVersion
324			!= (int32)B_HOST_TO_BENDIAN_INT32(NETFS_PROTOCOL_VERSION)) {
325			PRINT("ServerManager::_BroadcastListener(): protocol "
326				"version does not match: %" B_PRId32 " vs. %d.\n",
327				(int32)B_BENDIAN_TO_HOST_INT32(
328					message.protocolVersion),
329				NETFS_PROTOCOL_VERSION);
330			continue;
331		}
332
333		// check, if the server is local
334		NetAddress netAddress(addr);
335		#ifndef ADD_SERVER_LOCALHOST
336			if (netAddress.IsLocal())
337				continue;
338		#endif	// ADD_SERVER_LOCALHOST
339
340		AutoLocker<Locker> locker(fLock);
341		ExtendedServerInfo* oldServerInfo = fServerInfos->Get(netAddress);
342
343		// examine the message
344		switch (B_BENDIAN_TO_HOST_INT32(message.message)) {
345			case BROADCAST_MESSAGE_SERVER_TICK:
346//				PRINT(("ServerManager::_BroadcastListener(): "
347//					"BROADCAST_MESSAGE_SERVER_TICK.\n"));
348				if (oldServerInfo)
349					continue;
350				break;
351			case BROADCAST_MESSAGE_SERVER_UPDATE:
352//				PRINT(("ServerManager::_BroadcastListener(): "
353//					"BROADCAST_MESSAGE_SERVER_UPDATE.\n"));
354				break;
355			case BROADCAST_MESSAGE_CLIENT_HELLO:
356//				PRINT(("ServerManager::_BroadcastListener(): "
357//					"BROADCAST_MESSAGE_CLIENT_HELLO. Ignoring.\n"));
358				continue;
359				break;
360		}
361
362		if (oldServerInfo && oldServerInfo->GetState() != STATE_READY)
363			continue;
364
365		// create a new server info and add it
366		ExtendedServerInfo* serverInfo
367			= new(std::nothrow) ExtendedServerInfo(netAddress);
368		if (!serverInfo)
369			return B_NO_MEMORY;
370		serverInfo->SetState(STATE_ADDING);
371		BReference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
372		if (oldServerInfo) {
373			oldServerInfo->SetState(STATE_UPDATING);
374		} else {
375			status_t error = fServerInfos->Put(netAddress, serverInfo);
376			if (error != B_OK)
377				continue;
378			serverInfo->AcquireReference();
379		}
380
381		// create a task to add/update the server info
382		ServerInfoTask* task = new(std::nothrow) ServerInfoTask(this, oldServerInfo,
383			serverInfo);
384		if (!task) {
385			if (oldServerInfo) {
386				oldServerInfo->SetState(STATE_READY);
387			} else {
388				fServerInfos->Remove(serverInfo->GetAddress());
389				serverInfo->ReleaseReference();
390			}
391			continue;
392		}
393		// now the task has all info and will call the respective cleanup
394		// method when being deleted
395		if (task->Init() != B_OK) {
396			delete task;
397			continue;
398		}
399		status_t error = taskManager.RunTask(task);
400		if (error != B_OK) {
401			ERROR("ServerManager::_BroadcastListener(): Failed to start server "
402				"info task: %s\n", strerror(error));
403			continue;
404		}
405	}
406	return B_OK;
407}
408
409// _InitBroadcastListener
410status_t
411ServerManager::_InitBroadcastListener()
412{
413	// create a socket
414	fBroadcastListenerSocket = socket(AF_INET, SOCK_DGRAM, 0);
415	if (fBroadcastListenerSocket < 0)
416		return errno;
417	// bind it to the port
418	sockaddr_in addr;
419	addr.sin_family = AF_INET;
420	addr.sin_port = htons(kDefaultBroadcastPort);
421	addr.sin_addr.s_addr = INADDR_ANY;
422	if (bind(fBroadcastListenerSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
423		ERROR("ServerManager::_InitBroadcastListener(): ERROR: bind()ing the "
424			"broadcasting socket failed: %s\n", strerror(errno));
425		safe_closesocket(fBroadcastListenerSocket);
426		return errno;
427	}
428	// spawn the thread
429	#if USER
430		fBroadcastListener = spawn_thread(&_BroadcastListenerEntry,
431			"broadcast listener", B_NORMAL_PRIORITY, this);
432	#else
433		fBroadcastListener = spawn_kernel_thread(&_BroadcastListenerEntry,
434			"broadcast listener", B_NORMAL_PRIORITY, this);
435	#endif
436	if (fBroadcastListener < 0)
437		return fBroadcastListener;
438	return B_OK;
439}
440
441// _TerminateBroadcastListener
442void
443ServerManager::_TerminateBroadcastListener()
444{
445	safe_closesocket(fBroadcastListenerSocket);
446	if (fBroadcastListener >= 0) {
447		int32 result;
448		wait_for_thread(fBroadcastListener, &result);
449	}
450}
451
452// _ServerAdded
453void
454ServerManager::_ServerAdded(ExtendedServerInfo* serverInfo)
455{
456	AutoLocker<Locker> locker(fLock);
457	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
458		// check whether someone told us to remove the server in the meantime
459		if (serverInfo->GetState() == STATE_REMOVING) {
460			_RemoveServer(serverInfo);
461			if (fListener) {
462				locker.Unlock();
463				fListener->ServerRemoved(serverInfo);
464			}
465			return;
466		}
467
468		// no, everything is fine: go on...
469		serverInfo->SetState(STATE_READY);
470		if (fListener) {
471			locker.Unlock();
472			fListener->ServerAdded(serverInfo);
473		}
474	} else {
475		WARN("ServerManager::_ServerAdded(%p): WARNING: Unexpected server "
476			"info.\n", serverInfo);
477	}
478}
479
480// _ServerUpdated
481void
482ServerManager::_ServerUpdated(ExtendedServerInfo* serverInfo)
483{
484	AutoLocker<Locker> locker(fLock);
485	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
486	if (serverInfo != oldInfo) {
487		// check whether someone told us to remove the server in the meantime
488		if (oldInfo->GetState() == STATE_REMOVING) {
489			oldInfo->AcquireReference();
490			_RemoveServer(oldInfo);
491			if (fListener) {
492				locker.Unlock();
493				fListener->ServerRemoved(oldInfo);
494			}
495			oldInfo->ReleaseReference();
496			return;
497		}
498
499		// no, everything is fine: go on...
500		fServerInfos->Put(serverInfo->GetAddress(), serverInfo);
501		serverInfo->AcquireReference();
502		serverInfo->SetState(STATE_READY);
503		oldInfo->SetState(STATE_OBSOLETE);
504		if (fListener) {
505			locker.Unlock();
506			fListener->ServerUpdated(oldInfo, serverInfo);
507		}
508		oldInfo->ReleaseReference();
509	} else {
510		WARN("ServerManager::_ServerUpdated(%p): WARNING: Unexpected server "
511			"info.\n", serverInfo);
512	}
513}
514
515// _AddingServerFailed
516void
517ServerManager::_AddingServerFailed(ExtendedServerInfo* serverInfo)
518{
519	AutoLocker<Locker> locker(fLock);
520	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
521		bool removing = (serverInfo->GetState() == STATE_REMOVING);
522		fServerInfos->Remove(serverInfo->GetAddress());
523		serverInfo->ReleaseReference();
524		serverInfo->SetState(STATE_OBSOLETE);
525
526		// notify the listener, if someone told us in the meantime to remove
527		// the server
528		if (removing) {
529			locker.Unlock();
530			fListener->ServerRemoved(serverInfo);
531		}
532	} else {
533		WARN("ServerManager::_AddingServerFailed(%p): WARNING: Unexpected "
534			"server info.\n", serverInfo);
535	}
536}
537
538// _UpdatingServerFailed
539void
540ServerManager::_UpdatingServerFailed(ExtendedServerInfo* serverInfo)
541{
542	AutoLocker<Locker> locker(fLock);
543	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
544	if (serverInfo != oldInfo) {
545		// check whether someone told us to remove the server in the meantime
546		if (oldInfo->GetState() == STATE_REMOVING) {
547			oldInfo->AcquireReference();
548			_RemoveServer(oldInfo);
549			if (fListener) {
550				locker.Unlock();
551				fListener->ServerRemoved(oldInfo);
552			}
553			oldInfo->ReleaseReference();
554			serverInfo->SetState(STATE_OBSOLETE);
555			return;
556		}
557
558		// no, everything is fine: go on...
559		serverInfo->SetState(STATE_OBSOLETE);
560		oldInfo->SetState(STATE_READY);
561	} else {
562		WARN("ServerManager::_UpdatingServerFailed(%p): WARNING: Unexpected "
563			"server info.\n", serverInfo);
564	}
565}
566
567// _RemoveServer
568//
569// fLock must be held.
570void
571ServerManager::_RemoveServer(ExtendedServerInfo* serverInfo)
572{
573	if (!serverInfo)
574		return;
575
576	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
577	if (oldInfo) {
578		fServerInfos->Remove(oldInfo->GetAddress());
579		oldInfo->SetState(STATE_OBSOLETE);
580		oldInfo->ReleaseReference();
581	}
582}
583
584
585// #pragma mark -
586
587// destructor
588ServerManager::Listener::~Listener()
589{
590}
591
592