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