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