| 276 | }; |
| 277 | |
| 278 | UniqueSocket bind_listen_socket(const std::string & host, int port) { |
| 279 | UniqueSocket socket_handle(socket(AF_INET, SOCK_STREAM, 0)); |
| 280 | if (socket_handle.get() == kInvalidSocket) { |
| 281 | throw std::runtime_error("could not create listen socket"); |
| 282 | } |
| 283 | int yes = 1; |
| 284 | #ifdef _WIN32 |
| 285 | setsockopt(socket_handle.get(), SOL_SOCKET, SO_REUSEADDR, reinterpret_cast<const char *>(&yes), sizeof(yes)); |
| 286 | #else |
| 287 | setsockopt(socket_handle.get(), SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)); |
| 288 | #endif |
| 289 | sockaddr_in addr{}; |
| 290 | addr.sin_family = AF_INET; |
| 291 | addr.sin_port = htons(static_cast<uint16_t>(port)); |
| 292 | if (inet_pton(AF_INET, host.c_str(), &addr.sin_addr) != 1) { |
| 293 | throw std::runtime_error("server host must be an IPv4 address: " + host); |
| 294 | } |
| 295 | if (bind(socket_handle.get(), reinterpret_cast<sockaddr *>(&addr), sizeof(addr)) != 0) { |
| 296 | throw std::runtime_error("could not bind " + host + ":" + std::to_string(port)); |
| 297 | } |
| 298 | if (listen(socket_handle.get(), 16) != 0) { |
| 299 | throw std::runtime_error("could not listen on " + host + ":" + std::to_string(port)); |
| 300 | } |
| 301 | return socket_handle; |
| 302 | } |
| 303 | |
| 304 | void handle_client(SocketHandle client, IHttpHandler & handler) { |
| 305 | UniqueSocket socket(client); |
| 306 | try { |
| 307 | const auto request = read_http_request(socket.get()); |
| 308 | const auto response = handler.handle(request); |