xref: /haiku/src/add-ons/kernel/file_systems/netfs/client/ServerManager.cpp (revision 9760dcae2038d47442f4658c2575844c6cf92c40)
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:
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->AddReference();
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->RemoveReference();
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 
137 private:
138 	ServerManager*		fServerManager;
139 	ExtendedServerInfo*	fOldServerInfo;
140 	ExtendedServerInfo*	fServerInfo;
141 	vint32				fFD;
142 	bool				fUpdate;
143 	bool				fSuccess;
144 };
145 
146 
147 // #pragma mark -
148 
149 // constructor
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
160 ServerManager::~ServerManager()
161 {
162 	Uninit();
163 }
164 
165 // Init
166 status_t
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
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->RemoveReference();
199 	}
200 	fServerInfos->Clear();
201 }
202 
203 // Run
204 void
205 ServerManager::Run()
206 {
207 	// start the broadcast listener
208 	resume_thread(fBroadcastListener);
209 }
210 
211 // GetServerInfo
212 ExtendedServerInfo*
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->AddReference();
223 	return serverInfo;
224 }
225 
226 // AddServer
227 status_t
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 	Reference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
243 	status_t error = fServerInfos->Put(address, serverInfo);
244 	if (error != B_OK)
245 		return error;
246 	serverInfo->AddReference();
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
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 		Reference<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
282 ServerManager::_BroadcastListenerEntry(void* data)
283 {
284 	return ((ServerManager*)data)->_BroadcastListener();
285 }
286 
287 // _BroadcastListener
288 int32
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() failed: %s\n",
307 				strerror(errno)));
308 			continue;
309 		}
310 
311 		// check message size, magic, and protocol version
312 		if (bytesRead != sizeof(BroadcastMessage)) {
313 			PRINT(("ServerManager::_BroadcastListener(): received %ld bytes, but "
314 				"it should be %lu\n", bytesRead, sizeof(BroadcastMessage)));
315 			continue;
316 		}
317 		if (message.magic != B_HOST_TO_BENDIAN_INT32(BROADCAST_MESSAGE_MAGIC)) {
318 			PRINT(("ServerManager::_BroadcastListener(): message has bad "
319 				"magic.\n"));
320 			continue;
321 		}
322 		if (message.protocolVersion
323 			!= (int32)B_HOST_TO_BENDIAN_INT32(NETFS_PROTOCOL_VERSION)) {
324 			PRINT(("ServerManager::_BroadcastListener(): protocol version "
325 				"does not match: %lu vs. %d.\n",
326 				B_BENDIAN_TO_HOST_INT32(message.protocolVersion),
327 				NETFS_PROTOCOL_VERSION));
328 			continue;
329 		}
330 
331 		// check, if the server is local
332 		NetAddress netAddress(addr);
333 		#ifndef ADD_SERVER_LOCALHOST
334 			if (netAddress.IsLocal())
335 				continue;
336 		#endif	// ADD_SERVER_LOCALHOST
337 
338 		AutoLocker<Locker> locker(fLock);
339 		ExtendedServerInfo* oldServerInfo = fServerInfos->Get(netAddress);
340 
341 		// examine the message
342 		switch (B_BENDIAN_TO_HOST_INT32(message.message)) {
343 			case BROADCAST_MESSAGE_SERVER_TICK:
344 //				PRINT(("ServerManager::_BroadcastListener(): "
345 //					"BROADCAST_MESSAGE_SERVER_TICK.\n"));
346 				if (oldServerInfo)
347 					continue;
348 				break;
349 			case BROADCAST_MESSAGE_SERVER_UPDATE:
350 //				PRINT(("ServerManager::_BroadcastListener(): "
351 //					"BROADCAST_MESSAGE_SERVER_UPDATE.\n"));
352 				break;
353 			case BROADCAST_MESSAGE_CLIENT_HELLO:
354 //				PRINT(("ServerManager::_BroadcastListener(): "
355 //					"BROADCAST_MESSAGE_CLIENT_HELLO. Ignoring.\n"));
356 				continue;
357 				break;
358 		}
359 
360 		if (oldServerInfo && oldServerInfo->GetState() != STATE_READY)
361 			continue;
362 
363 		// create a new server info and add it
364 		ExtendedServerInfo* serverInfo
365 			= new(std::nothrow) ExtendedServerInfo(netAddress);
366 		if (!serverInfo)
367 			return B_NO_MEMORY;
368 		serverInfo->SetState(STATE_ADDING);
369 		Reference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
370 		if (oldServerInfo) {
371 			oldServerInfo->SetState(STATE_UPDATING);
372 		} else {
373 			status_t error = fServerInfos->Put(netAddress, serverInfo);
374 			if (error != B_OK)
375 				continue;
376 			serverInfo->AddReference();
377 		}
378 
379 		// create a task to add/update the server info
380 		ServerInfoTask* task = new(std::nothrow) ServerInfoTask(this, oldServerInfo,
381 			serverInfo);
382 		if (!task) {
383 			if (oldServerInfo) {
384 				oldServerInfo->SetState(STATE_READY);
385 			} else {
386 				fServerInfos->Remove(serverInfo->GetAddress());
387 				serverInfo->RemoveReference();
388 			}
389 			continue;
390 		}
391 		// now the task has all info and will call the respective cleanup
392 		// method when being deleted
393 		if (task->Init() != B_OK) {
394 			delete task;
395 			continue;
396 		}
397 		status_t error = taskManager.RunTask(task);
398 		if (error != B_OK) {
399 			ERROR("ServerManager::_BroadcastListener(): Failed to start server "
400 				"info task: %s\n", strerror(error));
401 			continue;
402 		}
403 	}
404 	return B_OK;
405 }
406 
407 // _InitBroadcastListener
408 status_t
409 ServerManager::_InitBroadcastListener()
410 {
411 	// create a socket
412 	fBroadcastListenerSocket = socket(AF_INET, SOCK_DGRAM, 0);
413 	if (fBroadcastListenerSocket < 0)
414 		return errno;
415 	// bind it to the port
416 	sockaddr_in addr;
417 	addr.sin_family = AF_INET;
418 	addr.sin_port = htons(kDefaultBroadcastPort);
419 	addr.sin_addr.s_addr = INADDR_ANY;
420 	if (bind(fBroadcastListenerSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
421 		ERROR("ServerManager::_InitBroadcastListener(): ERROR: bind()ing the "
422 			"broadcasting socket failed: %s\n", strerror(errno));
423 		safe_closesocket(fBroadcastListenerSocket);
424 		return errno;
425 	}
426 	// spawn the thread
427 	#if USER
428 		fBroadcastListener = spawn_thread(&_BroadcastListenerEntry,
429 			"broadcast listener", B_NORMAL_PRIORITY, this);
430 	#else
431 		fBroadcastListener = spawn_kernel_thread(&_BroadcastListenerEntry,
432 			"broadcast listener", B_NORMAL_PRIORITY, this);
433 	#endif
434 	if (fBroadcastListener < 0)
435 		return fBroadcastListener;
436 	return B_OK;
437 }
438 
439 // _TerminateBroadcastListener
440 void
441 ServerManager::_TerminateBroadcastListener()
442 {
443 	safe_closesocket(fBroadcastListenerSocket);
444 	if (fBroadcastListener >= 0) {
445 		int32 result;
446 		wait_for_thread(fBroadcastListener, &result);
447 	}
448 }
449 
450 // _ServerAdded
451 void
452 ServerManager::_ServerAdded(ExtendedServerInfo* serverInfo)
453 {
454 	AutoLocker<Locker> locker(fLock);
455 	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
456 		// check whether someone told us to remove the server in the meantime
457 		if (serverInfo->GetState() == STATE_REMOVING) {
458 			_RemoveServer(serverInfo);
459 			if (fListener) {
460 				locker.Unlock();
461 				fListener->ServerRemoved(serverInfo);
462 			}
463 			return;
464 		}
465 
466 		// no, everything is fine: go on...
467 		serverInfo->SetState(STATE_READY);
468 		if (fListener) {
469 			locker.Unlock();
470 			fListener->ServerAdded(serverInfo);
471 		}
472 	} else {
473 		WARN("ServerManager::_ServerAdded(%p): WARNING: Unexpected server "
474 			"info.\n", serverInfo);
475 	}
476 }
477 
478 // _ServerUpdated
479 void
480 ServerManager::_ServerUpdated(ExtendedServerInfo* serverInfo)
481 {
482 	AutoLocker<Locker> locker(fLock);
483 	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
484 	if (serverInfo != oldInfo) {
485 		// check whether someone told us to remove the server in the meantime
486 		if (oldInfo->GetState() == STATE_REMOVING) {
487 			oldInfo->AddReference();
488 			_RemoveServer(oldInfo);
489 			if (fListener) {
490 				locker.Unlock();
491 				fListener->ServerRemoved(oldInfo);
492 			}
493 			oldInfo->RemoveReference();
494 			return;
495 		}
496 
497 		// no, everything is fine: go on...
498 		fServerInfos->Put(serverInfo->GetAddress(), serverInfo);
499 		serverInfo->AddReference();
500 		serverInfo->SetState(STATE_READY);
501 		oldInfo->SetState(STATE_OBSOLETE);
502 		if (fListener) {
503 			locker.Unlock();
504 			fListener->ServerUpdated(oldInfo, serverInfo);
505 		}
506 		oldInfo->RemoveReference();
507 	} else {
508 		WARN("ServerManager::_ServerUpdated(%p): WARNING: Unexpected server "
509 			"info.\n", serverInfo);
510 	}
511 }
512 
513 // _AddingServerFailed
514 void
515 ServerManager::_AddingServerFailed(ExtendedServerInfo* serverInfo)
516 {
517 	AutoLocker<Locker> locker(fLock);
518 	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
519 		bool removing = (serverInfo->GetState() == STATE_REMOVING);
520 		fServerInfos->Remove(serverInfo->GetAddress());
521 		serverInfo->RemoveReference();
522 		serverInfo->SetState(STATE_OBSOLETE);
523 
524 		// notify the listener, if someone told us in the meantime to remove
525 		// the server
526 		if (removing) {
527 			locker.Unlock();
528 			fListener->ServerRemoved(serverInfo);
529 		}
530 	} else {
531 		WARN("ServerManager::_AddingServerFailed(%p): WARNING: Unexpected "
532 			"server info.\n", serverInfo);
533 	}
534 }
535 
536 // _UpdatingServerFailed
537 void
538 ServerManager::_UpdatingServerFailed(ExtendedServerInfo* serverInfo)
539 {
540 	AutoLocker<Locker> locker(fLock);
541 	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
542 	if (serverInfo != oldInfo) {
543 		// check whether someone told us to remove the server in the meantime
544 		if (oldInfo->GetState() == STATE_REMOVING) {
545 			oldInfo->AddReference();
546 			_RemoveServer(oldInfo);
547 			if (fListener) {
548 				locker.Unlock();
549 				fListener->ServerRemoved(oldInfo);
550 			}
551 			oldInfo->RemoveReference();
552 			serverInfo->SetState(STATE_OBSOLETE);
553 			return;
554 		}
555 
556 		// no, everything is fine: go on...
557 		serverInfo->SetState(STATE_OBSOLETE);
558 		oldInfo->SetState(STATE_READY);
559 	} else {
560 		WARN("ServerManager::_UpdatingServerFailed(%p): WARNING: Unexpected "
561 			"server info.\n", serverInfo);
562 	}
563 }
564 
565 // _RemoveServer
566 //
567 // fLock must be held.
568 void
569 ServerManager::_RemoveServer(ExtendedServerInfo* serverInfo)
570 {
571 	if (!serverInfo)
572 		return;
573 
574 	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
575 	if (oldInfo) {
576 		fServerInfos->Remove(oldInfo->GetAddress());
577 		oldInfo->SetState(STATE_OBSOLETE);
578 		oldInfo->RemoveReference();
579 	}
580 }
581 
582 
583 // #pragma mark -
584 
585 // destructor
586 ServerManager::Listener::~Listener()
587 {
588 }
589 
590