xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ServerManager.cpp (revision 4cfa5b2dd6ce2bf9f9e0fea6dd00f08c8847dfbd)
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
32 enum {
33 	STATE_ADDING,
34 	STATE_REMOVING,
35 	STATE_UPDATING,
36 	STATE_READY,
37 	STATE_OBSOLETE
38 };
39 
40 
41 // ServerInfoMap
42 struct ServerManager::ServerInfoMap : HashMap<NetAddress, ExtendedServerInfo*> {
43 };
44 
45 // ServerInfoTask
46 class ServerManager::ServerInfoTask : public Task {
47 public:
ServerInfoTask(ServerManager * manager,ExtendedServerInfo * oldServerInfo,ExtendedServerInfo * serverInfo)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 
~ServerInfoTask()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 
Init()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 
Execute()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 
Stop()132 	virtual void Stop()
133 	{
134 		safe_closesocket(fFD);
135 	}
136 
137 private:
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
ServerManager(Listener * listener)150 ServerManager::ServerManager(Listener* listener)
151 	: fLock("server manager"),
152 	  fBroadcastListener(-1),
153 	  fBroadcastListenerSocket(-1),
154 	  fListener(listener),
155 	  fTerminating(false)
156 {
157 }
158 
159 // destructor
~ServerManager()160 ServerManager::~ServerManager()
161 {
162 	Uninit();
163 }
164 
165 // Init
166 status_t
Init()167 ServerManager::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
186 void
Uninit()187 ServerManager::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
204 void
Run()205 ServerManager::Run()
206 {
207 	// start the broadcast listener
208 	resume_thread(fBroadcastListener);
209 }
210 
211 // GetServerInfo
212 ExtendedServerInfo*
GetServerInfo(const NetAddress & address)213 ServerManager::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
227 status_t
AddServer(const NetAddress & address)228 ServerManager::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
259 void
RemoveServer(const NetAddress & address)260 ServerManager::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
281 int32
_BroadcastListenerEntry(void * data)282 ServerManager::_BroadcastListenerEntry(void* data)
283 {
284 	return ((ServerManager*)data)->_BroadcastListener();
285 }
286 
287 // _BroadcastListener
288 int32
_BroadcastListener()289 ServerManager::_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
410 status_t
_InitBroadcastListener()411 ServerManager::_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
442 void
_TerminateBroadcastListener()443 ServerManager::_TerminateBroadcastListener()
444 {
445 	safe_closesocket(fBroadcastListenerSocket);
446 	if (fBroadcastListener >= 0) {
447 		int32 result;
448 		wait_for_thread(fBroadcastListener, &result);
449 	}
450 }
451 
452 // _ServerAdded
453 void
_ServerAdded(ExtendedServerInfo * serverInfo)454 ServerManager::_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
481 void
_ServerUpdated(ExtendedServerInfo * serverInfo)482 ServerManager::_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
516 void
_AddingServerFailed(ExtendedServerInfo * serverInfo)517 ServerManager::_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
539 void
_UpdatingServerFailed(ExtendedServerInfo * serverInfo)540 ServerManager::_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.
570 void
_RemoveServer(ExtendedServerInfo * serverInfo)571 ServerManager::_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
~Listener()588 ServerManager::Listener::~Listener()
589 {
590 }
591 
592