15a1d355fSStephan Aßmus// ServerManager.cpp
25a1d355fSStephan Aßmus
35a1d355fSStephan Aßmus#include "ServerManager.h"
45a1d355fSStephan Aßmus
55a1d355fSStephan Aßmus#include <errno.h>
65a1d355fSStephan Aßmus#include <unistd.h>
75a1d355fSStephan Aßmus
85a1d355fSStephan Aßmus#ifdef HAIKU_TARGET_PLATFORM_BEOS
95a1d355fSStephan Aßmus#	include <socket.h>
105a1d355fSStephan Aßmus#else
115a1d355fSStephan Aßmus#	include <netinet/in.h>
125a1d355fSStephan Aßmus#	include <sys/socket.h>
135a1d355fSStephan Aßmus#endif
145a1d355fSStephan Aßmus
155a1d355fSStephan Aßmus#include <AutoDeleter.h>
165a1d355fSStephan Aßmus#include <AutoLocker.h>
175a1d355fSStephan Aßmus#include <ByteOrder.h>
185a1d355fSStephan Aßmus#include <HashMap.h>
195a1d355fSStephan Aßmus
205a1d355fSStephan Aßmus#include "Compatibility.h"
215a1d355fSStephan Aßmus#include "DebugSupport.h"
225a1d355fSStephan Aßmus#include "ExtendedServerInfo.h"
235a1d355fSStephan Aßmus#include "InsecureChannel.h"
245a1d355fSStephan Aßmus#include "NetAddress.h"
255a1d355fSStephan Aßmus#include "NetFSDefs.h"
265a1d355fSStephan Aßmus#include "RequestChannel.h"
275a1d355fSStephan Aßmus#include "Requests.h"
285a1d355fSStephan Aßmus#include "TaskManager.h"
295a1d355fSStephan Aßmus#include "Utils.h"
305a1d355fSStephan Aßmus
315a1d355fSStephan Aßmus// server info states
325a1d355fSStephan Aßmusenum {
335a1d355fSStephan Aßmus	STATE_ADDING,
345a1d355fSStephan Aßmus	STATE_REMOVING,
355a1d355fSStephan Aßmus	STATE_UPDATING,
365a1d355fSStephan Aßmus	STATE_READY,
375a1d355fSStephan Aßmus	STATE_OBSOLETE
385a1d355fSStephan Aßmus};
395a1d355fSStephan Aßmus
405a1d355fSStephan Aßmus
415a1d355fSStephan Aßmus// ServerInfoMap
425a1d355fSStephan Aßmusstruct ServerManager::ServerInfoMap : HashMap<NetAddress, ExtendedServerInfo*> {
435a1d355fSStephan Aßmus};
445a1d355fSStephan Aßmus
455a1d355fSStephan Aßmus// ServerInfoTask
465a1d355fSStephan Aßmusclass ServerManager::ServerInfoTask : public Task {
475a1d355fSStephan Aßmuspublic:
485a1d355fSStephan Aßmus	ServerInfoTask(ServerManager* manager, ExtendedServerInfo* oldServerInfo,
495a1d355fSStephan Aßmus		ExtendedServerInfo* serverInfo)
505a1d355fSStephan Aßmus		: Task("server info task"),
515a1d355fSStephan Aßmus		  fServerManager(manager),
525a1d355fSStephan Aßmus		  fOldServerInfo(oldServerInfo),
535a1d355fSStephan Aßmus		  fServerInfo(serverInfo),
545a1d355fSStephan Aßmus		  fFD(-1),
555a1d355fSStephan Aßmus		  fSuccess(false)
565a1d355fSStephan Aßmus	{
575a1d355fSStephan Aßmus		if (fServerInfo)
5888e38c17SIngo Weinhold			fServerInfo->AcquireReference();
595a1d355fSStephan Aßmus	}
605a1d355fSStephan Aßmus
615a1d355fSStephan Aßmus	virtual ~ServerInfoTask()
625a1d355fSStephan Aßmus	{
635a1d355fSStephan Aßmus		Stop();
645a1d355fSStephan Aßmus		if (!fSuccess) {
655a1d355fSStephan Aßmus			if (fOldServerInfo)
665a1d355fSStephan Aßmus				fServerManager->_UpdatingServerFailed(fServerInfo);
675a1d355fSStephan Aßmus			else
685a1d355fSStephan Aßmus				fServerManager->_AddingServerFailed(fServerInfo);
695a1d355fSStephan Aßmus		}
705a1d355fSStephan Aßmus		if (fServerInfo)
7188e38c17SIngo Weinhold			fServerInfo->ReleaseReference();
725a1d355fSStephan Aßmus	}
735a1d355fSStephan Aßmus
745a1d355fSStephan Aßmus	status_t Init()
755a1d355fSStephan Aßmus	{
765a1d355fSStephan Aßmus		// create a socket
775a1d355fSStephan Aßmus		fFD = socket(AF_INET, SOCK_STREAM, 0);
785a1d355fSStephan Aßmus		if (fFD < 0) {
795a1d355fSStephan Aßmus			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to create "
805a1d355fSStephan Aßmus				"socket: %s\n", strerror(errno));
815a1d355fSStephan Aßmus			return errno;
825a1d355fSStephan Aßmus		}
835a1d355fSStephan Aßmus		return B_OK;
845a1d355fSStephan Aßmus	}
855a1d355fSStephan Aßmus
865a1d355fSStephan Aßmus	virtual status_t Execute()
875a1d355fSStephan Aßmus	{
885a1d355fSStephan Aßmus		// connect to the server info port
895a1d355fSStephan Aßmus		sockaddr_in addr = fServerInfo->GetAddress().GetAddress();
905a1d355fSStephan Aßmus		addr.sin_port = htons(kDefaultServerInfoPort);
915a1d355fSStephan Aßmus		if (connect(fFD, (sockaddr*)&addr, sizeof(addr)) < 0) {
925a1d355fSStephan Aßmus			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to connect "
935a1d355fSStephan Aßmus				"to server info port: %s\n", strerror(errno));
945a1d355fSStephan Aßmus			return errno;
955a1d355fSStephan Aßmus		}
965a1d355fSStephan Aßmus
975a1d355fSStephan Aßmus		// create a channel
985a1d355fSStephan Aßmus		InsecureChannel channel(fFD);
995a1d355fSStephan Aßmus
1005a1d355fSStephan Aßmus		// receive a request
1015a1d355fSStephan Aßmus		RequestChannel requestChannel(&channel);
1025a1d355fSStephan Aßmus		Request* _request;
1035a1d355fSStephan Aßmus		status_t error = requestChannel.ReceiveRequest(&_request);
1045a1d355fSStephan Aßmus		if (error != B_OK) {
1055a1d355fSStephan Aßmus			ERROR("ServerManager::ServerInfoTask: ERROR: Failed to receive "
1065a1d355fSStephan Aßmus				"server info request: %s\n", strerror(errno));
1075a1d355fSStephan Aßmus			return error;
1085a1d355fSStephan Aßmus		}
1095a1d355fSStephan Aßmus		ObjectDeleter<Request> requestDeleter(_request);
1105a1d355fSStephan Aßmus		ServerInfoRequest* request = dynamic_cast<ServerInfoRequest*>(_request);
1115a1d355fSStephan Aßmus		if (!request) {
1125a1d355fSStephan Aßmus			ERROR("ServerManager::ServerInfoTask: ERROR: Received request "
1135a1d355fSStephan Aßmus				"is not a server info request.\n");
1145a1d355fSStephan Aßmus			return B_BAD_DATA;
1155a1d355fSStephan Aßmus		}
1165a1d355fSStephan Aßmus
1175a1d355fSStephan Aßmus		// get the info
1185a1d355fSStephan Aßmus		error = fServerInfo->SetTo(&request->serverInfo);
1195a1d355fSStephan Aßmus		if (error != B_OK)
1205a1d355fSStephan Aßmus			return error;
1215a1d355fSStephan Aßmus
1225a1d355fSStephan Aßmus		// notify the manager
1235a1d355fSStephan Aßmus		if (fOldServerInfo)
1245a1d355fSStephan Aßmus			fServerManager->_ServerUpdated(fServerInfo);
1255a1d355fSStephan Aßmus		else
1265a1d355fSStephan Aßmus			fServerManager->_ServerAdded(fServerInfo);
1275a1d355fSStephan Aßmus
1285a1d355fSStephan Aßmus		fSuccess = true;
1295a1d355fSStephan Aßmus		return B_OK;
1305a1d355fSStephan Aßmus	}
1315a1d355fSStephan Aßmus
1325a1d355fSStephan Aßmus	virtual void Stop()
1335a1d355fSStephan Aßmus	{
1345a1d355fSStephan Aßmus		safe_closesocket(fFD);
1355a1d355fSStephan Aßmus	}
1365a1d355fSStephan Aßmus
1375a1d355fSStephan Aßmusprivate:
1385a1d355fSStephan Aßmus	ServerManager*		fServerManager;
1395a1d355fSStephan Aßmus	ExtendedServerInfo*	fOldServerInfo;
1405a1d355fSStephan Aßmus	ExtendedServerInfo*	fServerInfo;
141f0d46bd8SAdrien Destugues	int32				fFD;
1425a1d355fSStephan Aßmus	bool				fUpdate;
1435a1d355fSStephan Aßmus	bool				fSuccess;
1445a1d355fSStephan Aßmus};
1455a1d355fSStephan Aßmus
1465a1d355fSStephan Aßmus
1475a1d355fSStephan Aßmus// #pragma mark -
1485a1d355fSStephan Aßmus
1495a1d355fSStephan Aßmus// constructor
1505a1d355fSStephan AßmusServerManager::ServerManager(Listener* listener)
1515a1d355fSStephan Aßmus	: fLock("server manager"),
1525a1d355fSStephan Aßmus	  fBroadcastListener(-1),
1535a1d355fSStephan Aßmus	  fBroadcastListenerSocket(-1),
1545a1d355fSStephan Aßmus	  fListener(listener),
1555a1d355fSStephan Aßmus	  fTerminating(false)
1565a1d355fSStephan Aßmus{
1575a1d355fSStephan Aßmus}
1585a1d355fSStephan Aßmus
1595a1d355fSStephan Aßmus// destructor
1605a1d355fSStephan AßmusServerManager::~ServerManager()
1615a1d355fSStephan Aßmus{
1625a1d355fSStephan Aßmus	Uninit();
1635a1d355fSStephan Aßmus}
1645a1d355fSStephan Aßmus
1655a1d355fSStephan Aßmus// Init
1665a1d355fSStephan Aßmusstatus_t
1675a1d355fSStephan AßmusServerManager::Init()
1685a1d355fSStephan Aßmus{
1695a1d355fSStephan Aßmus	// create the server info map
1705a1d355fSStephan Aßmus	fServerInfos = new(std::nothrow) ServerInfoMap();
1715a1d355fSStephan Aßmus	if (!fServerInfos)
1725a1d355fSStephan Aßmus		RETURN_ERROR(B_NO_MEMORY);
1735a1d355fSStephan Aßmus	status_t error = fServerInfos->InitCheck();
1745a1d355fSStephan Aßmus	if (error != B_OK)
1755a1d355fSStephan Aßmus		RETURN_ERROR(error);
1765a1d355fSStephan Aßmus
1775a1d355fSStephan Aßmus	// init the broadcast listener
1785a1d355fSStephan Aßmus	error = _InitBroadcastListener();
1795a1d355fSStephan Aßmus	if (error != B_OK)
1805a1d355fSStephan Aßmus		RETURN_ERROR(error);
1815a1d355fSStephan Aßmus
1825a1d355fSStephan Aßmus	return B_OK;
1835a1d355fSStephan Aßmus}
1845a1d355fSStephan Aßmus
1855a1d355fSStephan Aßmus// Uninit
1865a1d355fSStephan Aßmusvoid
1875a1d355fSStephan AßmusServerManager::Uninit()
1885a1d355fSStephan Aßmus{
1895a1d355fSStephan Aßmus	// stop the broadcast listener
1905a1d355fSStephan Aßmus	fTerminating = true;
1915a1d355fSStephan Aßmus	_TerminateBroadcastListener();
1925a1d355fSStephan Aßmus
1935a1d355fSStephan Aßmus	// remove all server infos
1945a1d355fSStephan Aßmus	AutoLocker<Locker> _(fLock);
1955a1d355fSStephan Aßmus	for (ServerInfoMap::Iterator it = fServerInfos->GetIterator();
1965a1d355fSStephan Aßmus		 it.HasNext();) {
1975a1d355fSStephan Aßmus		ExtendedServerInfo* serverInfo = it.Next().value;
19888e38c17SIngo Weinhold		serverInfo->ReleaseReference();
1995a1d355fSStephan Aßmus	}
2005a1d355fSStephan Aßmus	fServerInfos->Clear();
2015a1d355fSStephan Aßmus}
2025a1d355fSStephan Aßmus
2035a1d355fSStephan Aßmus// Run
2045a1d355fSStephan Aßmusvoid
2055a1d355fSStephan AßmusServerManager::Run()
2065a1d355fSStephan Aßmus{
2075a1d355fSStephan Aßmus	// start the broadcast listener
2085a1d355fSStephan Aßmus	resume_thread(fBroadcastListener);
2095a1d355fSStephan Aßmus}
2105a1d355fSStephan Aßmus
2115a1d355fSStephan Aßmus// GetServerInfo
2125a1d355fSStephan AßmusExtendedServerInfo*
2135a1d355fSStephan AßmusServerManager::GetServerInfo(const NetAddress& address)
2145a1d355fSStephan Aßmus{
2155a1d355fSStephan Aßmus	AutoLocker<Locker> _(fLock);
2165a1d355fSStephan Aßmus	ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
2175a1d355fSStephan Aßmus	if (!serverInfo
2185a1d355fSStephan Aßmus		|| (serverInfo->GetState() != STATE_READY
2195a1d355fSStephan Aßmus			&& serverInfo->GetState() != STATE_UPDATING)) {
2205a1d355fSStephan Aßmus		return NULL;
2215a1d355fSStephan Aßmus	}
22288e38c17SIngo Weinhold	serverInfo->AcquireReference();
2235a1d355fSStephan Aßmus	return serverInfo;
2245a1d355fSStephan Aßmus}
2255a1d355fSStephan Aßmus
2265a1d355fSStephan Aßmus// AddServer
2275a1d355fSStephan Aßmusstatus_t
2285a1d355fSStephan AßmusServerManager::AddServer(const NetAddress& address)
2295a1d355fSStephan Aßmus{
2305a1d355fSStephan Aßmus	// check, if the server is already known
2315a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
2325a1d355fSStephan Aßmus	ExtendedServerInfo* oldInfo = fServerInfos->Get(address);
2335a1d355fSStephan Aßmus	if (oldInfo)
2345a1d355fSStephan Aßmus		return B_OK;
2355a1d355fSStephan Aßmus
2365a1d355fSStephan Aßmus	// create a new server info and add it
2375a1d355fSStephan Aßmus	ExtendedServerInfo* serverInfo
2385a1d355fSStephan Aßmus		= new(std::nothrow) ExtendedServerInfo(address);
2395a1d355fSStephan Aßmus	if (!serverInfo)
2405a1d355fSStephan Aßmus		return B_NO_MEMORY;
2415a1d355fSStephan Aßmus	serverInfo->SetState(STATE_ADDING);
24288e38c17SIngo Weinhold	BReference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
2435a1d355fSStephan Aßmus	status_t error = fServerInfos->Put(address, serverInfo);
2445a1d355fSStephan Aßmus	if (error != B_OK)
2455a1d355fSStephan Aßmus		return error;
24688e38c17SIngo Weinhold	serverInfo->AcquireReference();
2475a1d355fSStephan Aßmus
2485a1d355fSStephan Aßmus	// create and execute the task -- it will do what is necessary
2495a1d355fSStephan Aßmus	ServerInfoTask task(this, NULL, serverInfo);
2505a1d355fSStephan Aßmus	error = task.Init();
2515a1d355fSStephan Aßmus	if (error != B_OK)
2525a1d355fSStephan Aßmus		return error;
2535a1d355fSStephan Aßmus
2545a1d355fSStephan Aßmus	locker.Unlock();
2555a1d355fSStephan Aßmus	return task.Execute();
2565a1d355fSStephan Aßmus}
2575a1d355fSStephan Aßmus
2585a1d355fSStephan Aßmus// RemoveServer
2595a1d355fSStephan Aßmusvoid
2605a1d355fSStephan AßmusServerManager::RemoveServer(const NetAddress& address)
2615a1d355fSStephan Aßmus{
2625a1d355fSStephan Aßmus	// check, if the server is known at all
2635a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
2645a1d355fSStephan Aßmus	ExtendedServerInfo* serverInfo = fServerInfos->Get(address);
2655a1d355fSStephan Aßmus	if (!serverInfo)
2665a1d355fSStephan Aßmus		return;
2675a1d355fSStephan Aßmus
2685a1d355fSStephan Aßmus	// If its current state is not STATE_READY, then an info thread is currently
2695a1d355fSStephan Aßmus	// trying to add/update it. We mark the info STATE_REMOVING, which will
2705a1d355fSStephan Aßmus	// remove the info as soon as possible.
2715a1d355fSStephan Aßmus	if (serverInfo->GetState() == STATE_READY) {
27288e38c17SIngo Weinhold		BReference<ExtendedServerInfo> _(serverInfo);
2735a1d355fSStephan Aßmus		_RemoveServer(serverInfo);
2745a1d355fSStephan Aßmus		locker.Unlock();
2755a1d355fSStephan Aßmus		fListener->ServerRemoved(serverInfo);
2765a1d355fSStephan Aßmus	} else
2775a1d355fSStephan Aßmus		serverInfo->SetState(STATE_REMOVING);
2785a1d355fSStephan Aßmus}
2795a1d355fSStephan Aßmus
2805a1d355fSStephan Aßmus// _BroadcastListenerEntry
2815a1d355fSStephan Aßmusint32
2825a1d355fSStephan AßmusServerManager::_BroadcastListenerEntry(void* data)
2835a1d355fSStephan Aßmus{
2845a1d355fSStephan Aßmus	return ((ServerManager*)data)->_BroadcastListener();
2855a1d355fSStephan Aßmus}
2865a1d355fSStephan Aßmus
2875a1d355fSStephan Aßmus// _BroadcastListener
2885a1d355fSStephan Aßmusint32
2895a1d355fSStephan AßmusServerManager::_BroadcastListener()
2905a1d355fSStephan Aßmus{
2915a1d355fSStephan Aßmus	TaskManager taskManager;
2925a1d355fSStephan Aßmus	while (!fTerminating) {
2935a1d355fSStephan Aßmus		taskManager.RemoveDoneTasks();
2945a1d355fSStephan Aßmus
2955a1d355fSStephan Aßmus		// receive
2965a1d355fSStephan Aßmus		sockaddr_in addr;
2975a1d355fSStephan Aßmus		addr.sin_family = AF_INET;
2985a1d355fSStephan Aßmus		addr.sin_port = htons(kDefaultBroadcastPort);
2995a1d355fSStephan Aßmus		addr.sin_addr.s_addr = INADDR_ANY;
3005a1d355fSStephan Aßmus		socklen_t addrSize = sizeof(addr);
3015a1d355fSStephan Aßmus		BroadcastMessage message;
3025a1d355fSStephan Aßmus//PRINT(("ServerManager::_BroadcastListener(): recvfrom()...\n"));
3035a1d355fSStephan Aßmus		ssize_t bytesRead = recvfrom(fBroadcastListenerSocket, &message,
3045a1d355fSStephan Aßmus			sizeof(message), 0, (sockaddr*)&addr, &addrSize);
3055a1d355fSStephan Aßmus		if (bytesRead < 0) {
3063c1afd35SPawel Dziepak			PRINT("ServerManager::_BroadcastListener(): recvfrom() "
3073c1afd35SPawel Dziepak				"failed: %s\n", strerror(errno));
3085a1d355fSStephan Aßmus			continue;
3095a1d355fSStephan Aßmus		}
3105a1d355fSStephan Aßmus
3115a1d355fSStephan Aßmus		// check message size, magic, and protocol version
3125a1d355fSStephan Aßmus		if (bytesRead != sizeof(BroadcastMessage)) {
3133c1afd35SPawel Dziepak			PRINT("ServerManager::_BroadcastListener(): received "
3143c1afd35SPawel Dziepak				"%ld bytes, but it should be %lu\n", bytesRead,
3153c1afd35SPawel Dziepak				sizeof(BroadcastMessage));
3165a1d355fSStephan Aßmus			continue;
3175a1d355fSStephan Aßmus		}
3185a1d355fSStephan Aßmus		if (message.magic != B_HOST_TO_BENDIAN_INT32(BROADCAST_MESSAGE_MAGIC)) {
3193c1afd35SPawel Dziepak			PRINT("ServerManager::_BroadcastListener(): message has"
3203c1afd35SPawel Dziepak				" bad magic.\n");
3215a1d355fSStephan Aßmus			continue;
3225a1d355fSStephan Aßmus		}
3235a1d355fSStephan Aßmus		if (message.protocolVersion
3245a1d355fSStephan Aßmus			!= (int32)B_HOST_TO_BENDIAN_INT32(NETFS_PROTOCOL_VERSION)) {
3253c1afd35SPawel Dziepak			PRINT("ServerManager::_BroadcastListener(): protocol "
3264cfa5b2dSJérôme Duval				"version does not match: %" B_PRId32 " vs. %d.\n",
3274cfa5b2dSJérôme Duval				(int32)B_BENDIAN_TO_HOST_INT32(
3283c1afd35SPawel Dziepak					message.protocolVersion),
3293c1afd35SPawel Dziepak				NETFS_PROTOCOL_VERSION);
3305a1d355fSStephan Aßmus			continue;
3315a1d355fSStephan Aßmus		}
3325a1d355fSStephan Aßmus
3335a1d355fSStephan Aßmus		// check, if the server is local
3345a1d355fSStephan Aßmus		NetAddress netAddress(addr);
3355a1d355fSStephan Aßmus		#ifndef ADD_SERVER_LOCALHOST
3365a1d355fSStephan Aßmus			if (netAddress.IsLocal())
3375a1d355fSStephan Aßmus				continue;
3385a1d355fSStephan Aßmus		#endif	// ADD_SERVER_LOCALHOST
3395a1d355fSStephan Aßmus
3405a1d355fSStephan Aßmus		AutoLocker<Locker> locker(fLock);
3415a1d355fSStephan Aßmus		ExtendedServerInfo* oldServerInfo = fServerInfos->Get(netAddress);
3425a1d355fSStephan Aßmus
3435a1d355fSStephan Aßmus		// examine the message
3445a1d355fSStephan Aßmus		switch (B_BENDIAN_TO_HOST_INT32(message.message)) {
3455a1d355fSStephan Aßmus			case BROADCAST_MESSAGE_SERVER_TICK:
3465a1d355fSStephan Aßmus//				PRINT(("ServerManager::_BroadcastListener(): "
3475a1d355fSStephan Aßmus//					"BROADCAST_MESSAGE_SERVER_TICK.\n"));
3485a1d355fSStephan Aßmus				if (oldServerInfo)
3495a1d355fSStephan Aßmus					continue;
3505a1d355fSStephan Aßmus				break;
3515a1d355fSStephan Aßmus			case BROADCAST_MESSAGE_SERVER_UPDATE:
3525a1d355fSStephan Aßmus//				PRINT(("ServerManager::_BroadcastListener(): "
3535a1d355fSStephan Aßmus//					"BROADCAST_MESSAGE_SERVER_UPDATE.\n"));
3545a1d355fSStephan Aßmus				break;
3555a1d355fSStephan Aßmus			case BROADCAST_MESSAGE_CLIENT_HELLO:
3565a1d355fSStephan Aßmus//				PRINT(("ServerManager::_BroadcastListener(): "
3575a1d355fSStephan Aßmus//					"BROADCAST_MESSAGE_CLIENT_HELLO. Ignoring.\n"));
3585a1d355fSStephan Aßmus				continue;
3595a1d355fSStephan Aßmus				break;
3605a1d355fSStephan Aßmus		}
3615a1d355fSStephan Aßmus
3625a1d355fSStephan Aßmus		if (oldServerInfo && oldServerInfo->GetState() != STATE_READY)
3635a1d355fSStephan Aßmus			continue;
3645a1d355fSStephan Aßmus
3655a1d355fSStephan Aßmus		// create a new server info and add it
3665a1d355fSStephan Aßmus		ExtendedServerInfo* serverInfo
3675a1d355fSStephan Aßmus			= new(std::nothrow) ExtendedServerInfo(netAddress);
3685a1d355fSStephan Aßmus		if (!serverInfo)
3695a1d355fSStephan Aßmus			return B_NO_MEMORY;
3705a1d355fSStephan Aßmus		serverInfo->SetState(STATE_ADDING);
37188e38c17SIngo Weinhold		BReference<ExtendedServerInfo> serverInfoReference(serverInfo, true);
3725a1d355fSStephan Aßmus		if (oldServerInfo) {
3735a1d355fSStephan Aßmus			oldServerInfo->SetState(STATE_UPDATING);
3745a1d355fSStephan Aßmus		} else {
3755a1d355fSStephan Aßmus			status_t error = fServerInfos->Put(netAddress, serverInfo);
3765a1d355fSStephan Aßmus			if (error != B_OK)
3775a1d355fSStephan Aßmus				continue;
37888e38c17SIngo Weinhold			serverInfo->AcquireReference();
3795a1d355fSStephan Aßmus		}
3805a1d355fSStephan Aßmus
3815a1d355fSStephan Aßmus		// create a task to add/update the server info
3825a1d355fSStephan Aßmus		ServerInfoTask* task = new(std::nothrow) ServerInfoTask(this, oldServerInfo,
3835a1d355fSStephan Aßmus			serverInfo);
3845a1d355fSStephan Aßmus		if (!task) {
3855a1d355fSStephan Aßmus			if (oldServerInfo) {
3865a1d355fSStephan Aßmus				oldServerInfo->SetState(STATE_READY);
3875a1d355fSStephan Aßmus			} else {
3885a1d355fSStephan Aßmus				fServerInfos->Remove(serverInfo->GetAddress());
38988e38c17SIngo Weinhold				serverInfo->ReleaseReference();
3905a1d355fSStephan Aßmus			}
3915a1d355fSStephan Aßmus			continue;
3925a1d355fSStephan Aßmus		}
3935a1d355fSStephan Aßmus		// now the task has all info and will call the respective cleanup
3945a1d355fSStephan Aßmus		// method when being deleted
3955a1d355fSStephan Aßmus		if (task->Init() != B_OK) {
3965a1d355fSStephan Aßmus			delete task;
3975a1d355fSStephan Aßmus			continue;
3985a1d355fSStephan Aßmus		}
3995a1d355fSStephan Aßmus		status_t error = taskManager.RunTask(task);
4005a1d355fSStephan Aßmus		if (error != B_OK) {
4015a1d355fSStephan Aßmus			ERROR("ServerManager::_BroadcastListener(): Failed to start server "
4025a1d355fSStephan Aßmus				"info task: %s\n", strerror(error));
4035a1d355fSStephan Aßmus			continue;
4045a1d355fSStephan Aßmus		}
4055a1d355fSStephan Aßmus	}
4065a1d355fSStephan Aßmus	return B_OK;
4075a1d355fSStephan Aßmus}
4085a1d355fSStephan Aßmus
4095a1d355fSStephan Aßmus// _InitBroadcastListener
4105a1d355fSStephan Aßmusstatus_t
4115a1d355fSStephan AßmusServerManager::_InitBroadcastListener()
4125a1d355fSStephan Aßmus{
4135a1d355fSStephan Aßmus	// create a socket
4145a1d355fSStephan Aßmus	fBroadcastListenerSocket = socket(AF_INET, SOCK_DGRAM, 0);
4155a1d355fSStephan Aßmus	if (fBroadcastListenerSocket < 0)
4165a1d355fSStephan Aßmus		return errno;
4175a1d355fSStephan Aßmus	// bind it to the port
4185a1d355fSStephan Aßmus	sockaddr_in addr;
4195a1d355fSStephan Aßmus	addr.sin_family = AF_INET;
4205a1d355fSStephan Aßmus	addr.sin_port = htons(kDefaultBroadcastPort);
4215a1d355fSStephan Aßmus	addr.sin_addr.s_addr = INADDR_ANY;
4225a1d355fSStephan Aßmus	if (bind(fBroadcastListenerSocket, (sockaddr*)&addr, sizeof(addr)) < 0) {
4235a1d355fSStephan Aßmus		ERROR("ServerManager::_InitBroadcastListener(): ERROR: bind()ing the "
4245a1d355fSStephan Aßmus			"broadcasting socket failed: %s\n", strerror(errno));
4255a1d355fSStephan Aßmus		safe_closesocket(fBroadcastListenerSocket);
4265a1d355fSStephan Aßmus		return errno;
4275a1d355fSStephan Aßmus	}
4285a1d355fSStephan Aßmus	// spawn the thread
4295a1d355fSStephan Aßmus	#if USER
4305a1d355fSStephan Aßmus		fBroadcastListener = spawn_thread(&_BroadcastListenerEntry,
4315a1d355fSStephan Aßmus			"broadcast listener", B_NORMAL_PRIORITY, this);
4325a1d355fSStephan Aßmus	#else
4335a1d355fSStephan Aßmus		fBroadcastListener = spawn_kernel_thread(&_BroadcastListenerEntry,
4345a1d355fSStephan Aßmus			"broadcast listener", B_NORMAL_PRIORITY, this);
4355a1d355fSStephan Aßmus	#endif
4365a1d355fSStephan Aßmus	if (fBroadcastListener < 0)
4375a1d355fSStephan Aßmus		return fBroadcastListener;
4385a1d355fSStephan Aßmus	return B_OK;
4395a1d355fSStephan Aßmus}
4405a1d355fSStephan Aßmus
4415a1d355fSStephan Aßmus// _TerminateBroadcastListener
4425a1d355fSStephan Aßmusvoid
4435a1d355fSStephan AßmusServerManager::_TerminateBroadcastListener()
4445a1d355fSStephan Aßmus{
4455a1d355fSStephan Aßmus	safe_closesocket(fBroadcastListenerSocket);
4465a1d355fSStephan Aßmus	if (fBroadcastListener >= 0) {
4475a1d355fSStephan Aßmus		int32 result;
4485a1d355fSStephan Aßmus		wait_for_thread(fBroadcastListener, &result);
4495a1d355fSStephan Aßmus	}
4505a1d355fSStephan Aßmus}
4515a1d355fSStephan Aßmus
4525a1d355fSStephan Aßmus// _ServerAdded
4535a1d355fSStephan Aßmusvoid
4545a1d355fSStephan AßmusServerManager::_ServerAdded(ExtendedServerInfo* serverInfo)
4555a1d355fSStephan Aßmus{
4565a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
4575a1d355fSStephan Aßmus	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
4585a1d355fSStephan Aßmus		// check whether someone told us to remove the server in the meantime
4595a1d355fSStephan Aßmus		if (serverInfo->GetState() == STATE_REMOVING) {
4605a1d355fSStephan Aßmus			_RemoveServer(serverInfo);
4615a1d355fSStephan Aßmus			if (fListener) {
4625a1d355fSStephan Aßmus				locker.Unlock();
4635a1d355fSStephan Aßmus				fListener->ServerRemoved(serverInfo);
4645a1d355fSStephan Aßmus			}
4655a1d355fSStephan Aßmus			return;
4665a1d355fSStephan Aßmus		}
4675a1d355fSStephan Aßmus
4685a1d355fSStephan Aßmus		// no, everything is fine: go on...
4695a1d355fSStephan Aßmus		serverInfo->SetState(STATE_READY);
4705a1d355fSStephan Aßmus		if (fListener) {
4715a1d355fSStephan Aßmus			locker.Unlock();
4725a1d355fSStephan Aßmus			fListener->ServerAdded(serverInfo);
4735a1d355fSStephan Aßmus		}
4745a1d355fSStephan Aßmus	} else {
4755a1d355fSStephan Aßmus		WARN("ServerManager::_ServerAdded(%p): WARNING: Unexpected server "
4765a1d355fSStephan Aßmus			"info.\n", serverInfo);
4775a1d355fSStephan Aßmus	}
4785a1d355fSStephan Aßmus}
4795a1d355fSStephan Aßmus
4805a1d355fSStephan Aßmus// _ServerUpdated
4815a1d355fSStephan Aßmusvoid
4825a1d355fSStephan AßmusServerManager::_ServerUpdated(ExtendedServerInfo* serverInfo)
4835a1d355fSStephan Aßmus{
4845a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
4855a1d355fSStephan Aßmus	ExtendedServerInfo* oldInfo = fServerInfos->Get(serverInfo->GetAddress());
4865a1d355fSStephan Aßmus	if (serverInfo != oldInfo) {
4875a1d355fSStephan Aßmus		// check whether someone told us to remove the server in the meantime
4885a1d355fSStephan Aßmus		if (oldInfo->GetState() == STATE_REMOVING) {
48988e38c17SIngo Weinhold			oldInfo->AcquireReference();
4905a1d355fSStephan Aßmus			_RemoveServer(oldInfo);
4915a1d355fSStephan Aßmus			if (fListener) {
4925a1d355fSStephan Aßmus				locker.Unlock();
4935a1d355fSStephan Aßmus				fListener->ServerRemoved(oldInfo);
4945a1d355fSStephan Aßmus			}
49588e38c17SIngo Weinhold			oldInfo->ReleaseReference();
4965a1d355fSStephan Aßmus			return;
4975a1d355fSStephan Aßmus		}
4985a1d355fSStephan Aßmus
4995a1d355fSStephan Aßmus		// no, everything is fine: go on...
5005a1d355fSStephan Aßmus		fServerInfos->Put(serverInfo->GetAddress(), serverInfo);
50188e38c17SIngo Weinhold		serverInfo->AcquireReference();
5025a1d355fSStephan Aßmus		serverInfo->SetState(STATE_READY);
5035a1d355fSStephan Aßmus		oldInfo->SetState(STATE_OBSOLETE);
5045a1d355fSStephan Aßmus		if (fListener) {
5055a1d355fSStephan Aßmus			locker.Unlock();
5065a1d355fSStephan Aßmus			fListener->ServerUpdated(oldInfo, serverInfo);
5075a1d355fSStephan Aßmus		}
50888e38c17SIngo Weinhold		oldInfo->ReleaseReference();
5095a1d355fSStephan Aßmus	} else {
5105a1d355fSStephan Aßmus		WARN("ServerManager::_ServerUpdated(%p): WARNING: Unexpected server "
5115a1d355fSStephan Aßmus			"info.\n", serverInfo);
5125a1d355fSStephan Aßmus	}
5135a1d355fSStephan Aßmus}
5145a1d355fSStephan Aßmus
5155a1d355fSStephan Aßmus// _AddingServerFailed
5165a1d355fSStephan Aßmusvoid
5175a1d355fSStephan AßmusServerManager::_AddingServerFailed(ExtendedServerInfo* serverInfo)
5185a1d355fSStephan Aßmus{
5195a1d355fSStephan Aßmus	AutoLocker<Locker> locker(fLock);
5205a1d355fSStephan Aßmus	if (fServerInfos->Get(serverInfo->GetAddress()) == serverInfo) {
5215a1d355fSStephan Aßmus		bool removing = (serverInfo->GetState() == STATE_REMOVING);
5225a1d355fSStephan Aßmus		fServerInfos->Remove(serverInfo->GetAddress());
52388e38c17SIngo Weinhold		serverInfo->ReleaseReference();
5245a1d355fSStephan Aßmus		serverInfo->SetState(STATE_OBSOLETE);
5255a1d355fSStephan Aßmus
5265a1d355fSStephan Aßmus		// notify the listener, if someone told us in the meantime to remove
5275a1d355fSStephan Aßmus		// the server
5285a1d355fSStephan Aßmus		if (removing) {
5295a1d355fSStephan Aßmus			locker.Unlock();
5305a1d355fSStephan Aßmus			fListener->ServerRemoved(serverInfo);
5315a1d355fSStephan Aßmus		}
5325a1d355fSStephan Aßmus	} else {
5335a1d355fSStephan Aßmus		WARN("ServerManager::_AddingServerFailed(%p): WARNING: Unexpected "
5345a1d355fSStephan Aßmus			"server info.\n", serverInfo);
5355a1d355fSStephan Aßmus	}
5365a1d355fSStephan Aßmus}
5375a1d355fSStephan Aßmus
5385a1d355fSStephan Aßmus// _UpdatingServerFailed
5395a1d355fSStephan Aßmusvoid
5405a1d355fSStephan AßmusServerManager::_UpdatingServerFailed(ExtendedServerInfo* serverInfo)
541