#include // socket functions #include // sockaddr_in #include // exit() and EXIT_FAILURE #include // cout #include // read #include #include // buffered stream #include using SOCKET_FD = int; constexpr uint16_t LISTEN_PORT = 42069; const int yes = 1; SOCKET_FD listener = -1, connection = -1; void handle_client(SOCKET_FD client_fd, bool (*handler)(std::istream&, std::ostream&, void*), void* ctx) { using Filebuf = __gnu_cxx::stdio_filebuf; // setup input stream FILE* fin = fdopen(client_fd, "r"); Filebuf in_buf(fin, std::ios::in); std::istream is(&in_buf); // setup output stream FILE* fout = fdopen(client_fd, "w"); Filebuf out_buf(fout, std::ios::out); std::ostream os(&out_buf); signal(SIGPIPE, SIG_IGN); // ignore pipe signal if (handler(is, os, ctx)) { shutdown(listener, SHUT_RD); } fclose(fin); fclose(fout); close(client_fd); } void serve(bool (*handler)(std::istream&, std::ostream&, void*), void* ctx) { sockaddr_in addr{ .sin_family = AF_INET, .sin_port = htons(LISTEN_PORT), .sin_addr = in_addr{ .s_addr = INADDR_ANY } }; if ((listener = socket(AF_INET, SOCK_STREAM, 0)) < 0 || setsockopt(listener, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof(yes)) < 0 || bind(listener, (const sockaddr*) &addr, sizeof(addr)) < 0 || listen(listener, 10) < 0) { goto cleanup; } while ((connection = accept(listener, nullptr, nullptr)) > 0) { std::thread(handle_client, connection, handler, ctx).detach(); } cleanup: std::cout << "Server shutting down..." << std::endl; if (connection != -1) close(connection); if (listener != -1) close(listener); } bool h(std::istream& is, std::ostream& os, void* ctx) { std::string s; os << "hello from " << std::this_thread::get_id() <<"! are you there?" << std::endl; is >> s; os << s << " to you too!" << std::endl; return true; }