| 550 | namespace HttpServer { |
| 551 | |
| 552 | bool Start(const std::string& blobRoot, uint32_t accountId) { |
| 553 | g_blobRoot = blobRoot; |
| 554 | g_accountId = accountId; |
| 555 | |
| 556 | g_listenFd = socket(AF_INET, SOCK_STREAM, 0); |
| 557 | if (g_listenFd < 0) { |
| 558 | LOG("[HttpServer] Failed to create socket"); |
| 559 | return false; |
| 560 | } |
| 561 | |
| 562 | int opt = 1; |
| 563 | setsockopt(g_listenFd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); |
| 564 | |
| 565 | struct sockaddr_in addr{}; |
| 566 | addr.sin_family = AF_INET; |
| 567 | addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK); |
| 568 | addr.sin_port = 0; // OS assigns port |
| 569 | |
| 570 | if (bind(g_listenFd, (struct sockaddr*)&addr, sizeof(addr)) < 0) { |
| 571 | LOG("[HttpServer] Failed to bind"); |
| 572 | close(g_listenFd); |
| 573 | g_listenFd = -1; |
| 574 | return false; |
| 575 | } |
| 576 | |
| 577 | socklen_t addrLen = sizeof(addr); |
| 578 | getsockname(g_listenFd, (struct sockaddr*)&addr, &addrLen); |
| 579 | g_port = ntohs(addr.sin_port); |
| 580 | |
| 581 | if (listen(g_listenFd, 16) < 0) { |
| 582 | LOG("[HttpServer] Failed to listen"); |
| 583 | close(g_listenFd); |
| 584 | g_listenFd = -1; |
| 585 | return false; |
| 586 | } |
| 587 | |
| 588 | g_running = true; |
| 589 | g_serverThread = std::thread([]() { |
| 590 | while (g_running) { |
| 591 | struct sockaddr_in clientAddr{}; |
| 592 | socklen_t clientLen = sizeof(clientAddr); |
| 593 | int clientFd = accept(g_listenFd, (struct sockaddr*)&clientAddr, &clientLen); |
| 594 | if (clientFd < 0) { |
| 595 | if (g_running) LOG("[HttpServer] accept() failed"); |
| 596 | continue; |
| 597 | } |
| 598 | // Reject connections from other processes |
| 599 | if (!IsConnectionFromSteam(clientFd)) { |
| 600 | close(clientFd); |
| 601 | continue; |
| 602 | } |
| 603 | // Set socket timeouts to prevent stalled clients from blocking threads |
| 604 | struct timeval tv = { .tv_sec = 30, .tv_usec = 0 }; |
| 605 | setsockopt(clientFd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(tv)); |
| 606 | setsockopt(clientFd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(tv)); |
| 607 | // At the cap: backpressure before giving up, so large download bursts |
| 608 | // (high-file-count manifests) drain instead of failing the sync. |
| 609 | int backpressureMs = 0; |
no test coverage detected