rendered paste body#include <stdlib.h>#include <stdio.h>#include <stdint.h>#include <string.h>#include <sys/socket.h>#include <sys/select.h>#include <sys/types.h>#include <netdb.h>#include <unistd.h>typedef enum CONN_STATE_{ CONN_STATE_INACTIVE = 0, CONN_STATE_CONNECTED, CONN_STATE_LISTENING} CONN_STATE;typedef struct connection_{ struct connection_* next; int sd; int client_num; CONN_STATE state; struct addrinfo* peer_addr;} connection;connection* conn_create(connection** list){ connection* new = NULL; int ret; do { if (new = malloc(sizeof(connection))) { struct addrinfo hints = {}; hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_PASSIVE; if (0 == (ret = getaddrinfo("localhost", NULL, &hints, &(new->peer_addr)))) { if (0 <= (new->sd = socket(AF_INET, SOCK_STREAM, 0))) { new->next = NULL; new->state = CONN_STATE_INACTIVE; new->client_num = 0; if (list) { if (!*list) *list = new; else { new->next = *list; *list = new; } } break; close(new->sd); } else perror("socket: "); freeaddrinfo(new->peer_addr); } else printf("gai: %s\n", gai_strerror(ret)); free(new); new = NULL; } } while (0); return new;}void conn_destroy(connection* c){ if (c) { close(c->sd); freeaddrinfo(c->peer_addr); free(c); c = NULL; }}connection* create_listener(uint16_t port, connection** list){ connection* listener = NULL; struct addrinfo hints = {}; char szPort[6] = {}; if (listener = conn_create(list)) { hints.ai_family = AF_INET; hints.ai_socktype = SOCK_STREAM; sprintf(szPort, "%hu", port); printf("port: %s\n" , szPort); do { freeaddrinfo(listener->peer_addr); if (0 == getaddrinfo("localhost", szPort, &hints, &(listener->peer_addr))) if (0 == bind(listener->sd, listener->peer_addr->ai_addr, listener->peer_addr->ai_addrlen)) if (0 == listen(listener->sd, 50)) { listener->state = CONN_STATE_LISTENING; break; } conn_destroy(listener); } while (0); } return listener;}int main(int argc, char* argv[]){ connection* connections = NULL; connection* new_conn = NULL; int run = 1; if ((new_conn = create_listener(9090, &connections))) { int ccount = 0; connection* ptr; printf("listen sd %d\n", new_conn->sd); while (run) { int max_fd = 0; fd_set rfds; struct timeval to = {5, 0}; FD_ZERO(&rfds); for (ptr = connections; ptr; ptr = ptr->next) if (ptr->state != CONN_STATE_INACTIVE) { printf("select on %d\n", ptr->sd); FD_SET(ptr->sd, &rfds); if (ptr->sd > max_fd) max_fd = ptr->sd; } switch (select(max_fd+1, &rfds, NULL, NULL, &to)) { case -1: perror("select: "); run = 0; break; case 0: printf("select timeout\n"); continue; default: { for (ptr = connections; ptr; ptr = ptr->next) { if (FD_ISSET(ptr->sd, &rfds)) { switch (ptr->state) { case CONN_STATE_CONNECTED: { char buf[512] = {}; int nread = 0; while (0 < (nread = recv(ptr->sd, &buf, 512, 0))) { printf("recieved %d bytes from client %d (%*s)\n", nread, ptr->client_num, nread, buf); if (nread < 512) break; } if (nread <= 0) { printf("client %d disconnected (%d)\n", ptr->client_num, nread); ptr->state = CONN_STATE_INACTIVE; } break; } case CONN_STATE_LISTENING: { connection* new = conn_create(&connections); printf("someone trying to connect\n"); if (new) { int new_sd; ptr->peer_addr->ai_addrlen = sizeof(struct sockaddr); if (0 <= (new_sd = accept(ptr->sd, new->peer_addr->ai_addr, &(new->peer_addr->ai_addrlen)))) { new->client_num = ++ccount; close(new->sd); new->sd = new_sd; new->state = CONN_STATE_CONNECTED; printf("new client: %d\n", ccount); } } break; } default: continue; } } } } } } for (ptr = connections; ptr;) { connection* del = ptr; ptr = ptr->next; conn_destroy(del); } } return 0;}