#include "./server.h" #include "common.h" const uint32_t CONNECTION_QUEUE_LEN = 10U; server_t* server_init_tcp(const char* addr, const char* port) { server_t* srv = calloc(1, sizeof(*srv)); srv->listen_socket_fd = socket(AF_INET, SOCK_STREAM | SOCK_NONBLOCK, 0); if (srv->listen_socket_fd == -1) { fprintf(stderr, "[server_init_tcp] Unable to create socket!\n"); exit(EXIT_FAILURE); } int setsockopt_yes = 1; if (setsockopt(srv->listen_socket_fd, SOL_SOCKET, SO_REUSEADDR, &setsockopt_yes, sizeof(setsockopt_yes)) == -1) { fprintf(stderr, "[server_init_tcp] Unable to set SO_REUSEADDR socket option\n"); exit(EXIT_FAILURE); } struct sockaddr_in* listen_addr = get_addr(addr, port); if (bind(srv->listen_socket_fd, (struct sockaddr*) listen_addr, sizeof(*listen_addr)) == -1) { free(listen_addr); fprintf(stderr, "[server_init_tcp] Unable to bind\n"); exit(EXIT_FAILURE); } free(listen_addr); if (listen(srv->listen_socket_fd, CONNECTION_QUEUE_LEN) == -1) { fprintf(stderr, "[server_init_tcp] Unable to listen() on a socket\n"); exit(EXIT_FAILURE); } struct linger linger_params = {.l_onoff = 1, .l_linger = 1}; if (setsockopt(srv->listen_socket_fd, SOL_SOCKET, SO_LINGER, &linger_params, sizeof(linger_params)) == -1) { fprintf(stderr, "[server_init_tcp] Unable to modify SO_LINGER socket option\n"); exit(EXIT_FAILURE); } return srv; } void server_shutdown(server_t* srv) { if (close(srv->listen_socket_fd) == -1) { fprintf(stderr, "[server_shutdown] Unable to close listen socket\n"); exit(EXIT_FAILURE); } } conn_t* server_try_accept(server_t* srv) { int client_socket_fd = accept(srv->listen_socket_fd, NULL, NULL); if (client_socket_fd == -1) { if (errno == EAGAIN || errno == EWOULDBLOCK) { return NULL; } fprintf(stderr, "[conn_try_accept] Unable to accept() connection on a socket\n"); exit(EXIT_FAILURE); } conn_t* conn = calloc(1, sizeof(*conn)); conn->conn_socket_fd = client_socket_fd; // Разрешаем "зависания сокета" для доотправки данных. // Disable Nagle's algorithm: int setsockopt_arg = 1; if (setsockopt(conn->conn_socket_fd, IPPROTO_TCP, TCP_NODELAY, &setsockopt_arg, sizeof(setsockopt_arg)) == -1) { fprintf(stderr, "[conn_try_accept] Unable to enable TCP_NODELAY socket option\n"); exit(EXIT_FAILURE); } // Disable corking: setsockopt_arg = 0; if (setsockopt(conn->conn_socket_fd, IPPROTO_TCP, TCP_CORK, &setsockopt_arg, sizeof(setsockopt_arg)) == -1) { fprintf(stderr, "[conn_try_accept] Unable to disable TCP_CORK socket option\n"); exit(EXIT_FAILURE); } if (conn_configure_tcpalive(conn) == -1) { fprintf(stderr, "[conn_try_accept] Unable to enable TCPALIVE\n"); exit(EXIT_FAILURE); } printf("[conn_accept] new connection!\n"); return conn; }