From a197581bd383adebf591c12ac607c9b96fd02a48 Mon Sep 17 00:00:00 2001 From: marschap Date: Sun, 30 Nov 2008 14:22:01 +0000 Subject: [PATCH] cleanup&refactor sock.c a bit, change definition for client add/remove functions --- server/clients.c | 32 ++--- server/clients.h | 14 +- server/sock.c | 326 +++++++++++++++++++++++++++-------------------- server/sock.h | 13 +- 4 files changed, 218 insertions(+), 167 deletions(-) diff --git a/server/clients.c b/server/clients.c index c6d9e4d..64336aa 100644 --- a/server/clients.c +++ b/server/clients.c @@ -1,6 +1,9 @@ -/* - * clients.c - * This file is part of LCDd, the lcdproc server. +/** \file clients.c + * Manage the list of clients that are connected. + * Init/shut down client system, and search for clients in the list. + */ + +/* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. @@ -8,11 +11,6 @@ * Copyright (c) 1999, William Ferrell, Scott Scriven * 2002, Joris Robijn * - * - * Inits/shuts down client system, - * and searches for clients in the list. - * On short: manages the list of clients that are connected. - * */ #include @@ -77,18 +75,23 @@ clients_shutdown(void) return 0; } -int +/* Add the client to the clients list... */ +Client * clients_add_client(Client *c) { - /* Add the client to the clients list... */ - return LL_Push(clientlist, c); + if (LL_Push(clientlist, c) == 0) + return c; + + return NULL; } -int +/* Remove the client from the clients list... */ +Client * clients_remove_client(Client *c) { - /* Remove the client from the clients list... */ - return(LL_Remove(clientlist, c) == NULL)?-1:0; + Client *client = LL_Remove(clientlist, c); + + return client; } Client * @@ -113,7 +116,6 @@ clients_client_count(void) /* A client is identified by the file descriptor * associated with it. Find one. */ - Client * clients_find_client_by_sock(int sock) { diff --git a/server/clients.h b/server/clients.h index c52b331..6db22bd 100644 --- a/server/clients.h +++ b/server/clients.h @@ -1,6 +1,8 @@ -/* - * client.h - * This file is part of LCDd, the lcdproc server. +/** \file clients.h + * Manage the list of clients that are connected. + */ + +/* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. @@ -21,9 +23,9 @@ int clients_init(void); int clients_shutdown(void); -/* Add/remove clients (return -1 for error) */ -int clients_add_client(Client *c); -int clients_remove_client(Client *c); +/* Add/remove clients (return NULL for error) */ +Client *clients_add_client(Client *c); +Client *clients_remove_client(Client *c); /* List functions */ Client *clients_getfirst(void); diff --git a/server/sock.c b/server/sock.c index 7acf4b8..7428f70 100644 --- a/server/sock.c +++ b/server/sock.c @@ -10,7 +10,7 @@ * Copyright (c) 1999, William Ferrell, Scott Scriven * 2003, Benjamin Tse (blt@ieee.org) - Winsock port * 2004, F5 Networks, Inc. - IP-address input - * 2005, Peter Marschall - error checks, ... + * 2005-2008, Peter Marschall - error checks, ... * */ @@ -57,21 +57,25 @@ static int listening_fd; static LinkedList* openSocketList = NULL; static LinkedList* freeClientSocketList = NULL; -struct ClientSocketMap +/** Mapping between socket and associated client */ +typedef struct _ClientSocketMap { - int socket; - Client* client; -}; + int socket; /**< Socket for the client */ + Client *client; /**< Pointer to client representation */ +} ClientSocketMap; + + +/* The memory referenced from \c openSocketList and \c freeSocketList + * is obtained from the freeClientSocketPool array. */ +ClientSocketMap *freeClientSocketPool; -/* The memory referenced from clientSocketPoolList is obtained from the - * clientSocketPool array. */ -struct ClientSocketMap* freeClientSocketPool; /* Length of longest transmission allowed at once...*/ #define MAXMSG 8192 /**** Internal function declarations ****************************************/ -static int sock_read_from_client(struct ClientSocketMap* clientSocketMap); +static int sock_read_from_client(ClientSocketMap *clientSocketMap); +static void sock_destroy_socket(void); /** Initialize sockets. @@ -84,18 +88,17 @@ static int sock_read_from_client(struct ClientSocketMap* clientSocketMap); int sock_init(char* bind_addr, int bind_port) { - int i; + int i; #ifdef WINSOCK2 - /* Initialize the Winsock dll */ - WSADATA wsaData; - int startup = WSAStartup(MAKEWORD(2, 2), &wsaData); - if (startup != 0) - { - report(RPT_ERR, "%s: Could not start Winsock library - %s", - __FUNCTION__, sock_geterror()); - } - /* REVISIT: call WSACleanup(); */ + /* Initialize the Winsock dll */ + WSADATA wsaData; + int startup = WSAStartup(MAKEWORD(2, 2), &wsaData); + if (startup != 0) { + report(RPT_ERR, "%s: Could not start Winsock library - %s", + __FUNCTION__, sock_geterror()); + } + /* REVISIT: call WSACleanup(); */ #endif debug(RPT_DEBUG, "%s(bind_addr=\"%s\", port=%d)", __FUNCTION__, bind_addr, bind_port); @@ -103,44 +106,47 @@ sock_init(char* bind_addr, int bind_port) /* Create the socket and set it up to accept connections. */ listening_fd = sock_create_inet_socket(bind_addr, bind_port); if (listening_fd < 0) { - report(RPT_ERR, "%s: Error creating socket - %s", - __FUNCTION__, sock_geterror()); + report(RPT_ERR, "%s: error creating socket - %s", + __FUNCTION__, sock_geterror()); return -1; } - /* Create the socket -> Client mapping pool */ - /* How large can FD_SETSIZE be? Even if it is ~2000 this only uses a - few kilobytes of memory. Let's trade size for speed! */ - freeClientSocketPool = (struct ClientSocketMap*) - malloc(sizeof(struct ClientSocketMap) * FD_SETSIZE); - if (!freeClientSocketPool) - { - report(RPT_ERR, "%s: Error allocating memory for client sockets.", - __FUNCTION__); - return -1; - } + /* Create the socket -> Client mapping pool */ + /* How large can FD_SETSIZE be? Even if it is ~2000 this only uses a + few kilobytes of memory. Let's trade size for speed! */ + freeClientSocketPool = (ClientSocketMap *) + calloc(FD_SETSIZE, sizeof(ClientSocketMap)); + if (freeClientSocketPool == NULL) { + report(RPT_ERR, "%s: Error allocating client sockets.", + __FUNCTION__); + return -1; + } - freeClientSocketList = LL_new(); - for (i = 0; i < FD_SETSIZE; ++i) - { - LL_AddNode(freeClientSocketList, (void*) &freeClientSocketPool[i]); - } + freeClientSocketList = LL_new(); + if (freeClientSocketList == NULL) { + report(RPT_ERR, "%s: error allocating free socket list.", + __FUNCTION__); + return -1; + } + for (i = 0; i < FD_SETSIZE; ++i) { + LL_AddNode(freeClientSocketList, (void*) &freeClientSocketPool[i]); + } - /* Create and initialize the open socket list with the server socket */ - openSocketList = LL_new(); - if (!openSocketList) - { - report(RPT_ERR, "%s: Error allocating memory for the open socket " - "list.", __FUNCTION__); - return -1; - } else { - struct ClientSocketMap *entry; + /* Create and initialize the open socket list with the server socket */ + openSocketList = LL_new(); + if (openSocketList == NULL) { + report(RPT_ERR, "%s: error allocating open socket list.", + __FUNCTION__); + return -1; + } + else { + ClientSocketMap *entry; - entry = (struct ClientSocketMap*) LL_Pop(freeClientSocketList); - entry->socket = listening_fd; - entry->client = NULL; - LL_AddNode(openSocketList, (void*) entry); - } + entry = (ClientSocketMap*) LL_Pop(freeClientSocketList); + entry->socket = listening_fd; + entry->client = NULL; + LL_AddNode(openSocketList, (void*) entry); + } return 0; } @@ -169,17 +175,17 @@ This code gets the send and receive buffer sizes. int sock_shutdown(void) { - int retVal = 0; + int retVal = 0; debug(RPT_DEBUG, "%s()", __FUNCTION__); - /*struct ClientSocketMap* clientIt;*/ + /*ClientSocketMap* clientIt;*/ /* delete all clients */ /* This should be done by calling clients_shutdown */ /* LL_Rewind(openSocketList); - for (clientIt = (struct ClientSocketMap*) LL_Get(openSocketList); + for (clientIt = (ClientSocketMap*) LL_Get(openSocketList); clientIt; clientIt = LL_GetNext(openSocketList)) { @@ -193,19 +199,18 @@ sock_shutdown(void) LL_Destroy(openSocketList); */ close(listening_fd); - LL_Destroy(freeClientSocketList); - free(freeClientSocketPool); + LL_Destroy(freeClientSocketList); + free(freeClientSocketPool); #ifdef WINSOCK2 - if (WSACleanup() != 0) - { - report(RPT_ERR, "%s: Error closing Winsock library - %s", - __FUNCTION__, sock_geterror()); - retVal = -1; - } + if (WSACleanup() != 0) { + report(RPT_ERR, "%s: Error closing Winsock library - %s", + __FUNCTION__, sock_geterror()); + retVal = -1; + } #endif - return retVal; + return retVal; } @@ -219,26 +224,27 @@ int sock_create_inet_socket(char *addr, unsigned int port) { struct sockaddr_in name; - int sock, sockopt=1; + int sock; + int sockopt = 1; debug(RPT_DEBUG, "%s(addr=\"%s\", port=%i)", __FUNCTION__, addr, port); /* Create the socket. */ sock = socket(PF_INET, SOCK_STREAM, 0); #ifdef WINSOCK2 - if (sock == INVALID_SOCKET) + if (sock == INVALID_SOCKET) #else if (sock < 0) #endif - { - report(RPT_ERR, "%s: Could not create socket - %s", - __FUNCTION__, sock_geterror()); + { + report(RPT_ERR, "%s: cannot create socket - %s", + __FUNCTION__, sock_geterror()); return -1; } /* Set the socket so we can re-use it*/ - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void*)&sockopt, sizeof(sockopt)) < 0) { - report(RPT_ERR, "%s: Error setting socket option SO_REUSEADDR - %s", - __FUNCTION__, sock_geterror()); + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (void *) &sockopt, sizeof(sockopt)) < 0) { + report(RPT_ERR, "%s: error setting socket option SO_REUSEADDR - %s", + __FUNCTION__, sock_geterror()); return -1; } @@ -247,28 +253,27 @@ sock_create_inet_socket(char *addr, unsigned int port) name.sin_family = AF_INET; name.sin_port = htons(port); #ifndef WINSOCK2 - /* REVISIT: can probably use the same code as under winsock */ + /* REVISIT: can probably use the same code as under winsock */ inet_aton(addr, &name.sin_addr); #else - name.sin_addr.S_un.S_addr = inet_addr(addr); + name.sin_addr.S_un.S_addr = inet_addr(addr); #endif if (bind(sock, (struct sockaddr *) &name, sizeof(name)) < 0) { - report(RPT_ERR, "%s: Could not bind to port %d at address %s - %s", + report(RPT_ERR, "%s: cannot bind to port %d at address %s - %s", __FUNCTION__, port, addr, sock_geterror()); return -1; } - else { - report(RPT_NOTICE, "Listening for queries on %s:%d", addr, port); - } if (listen(sock, 1) < 0) { report(RPT_ERR, "%s: error in attempting to listen to port " - "%d at %s - %s", - __FUNCTION__, port, addr, sock_geterror()); + "%d at %s - %s", + __FUNCTION__, port, addr, sock_geterror()); return -1; } + report(RPT_NOTICE, "Listening for queries on %s:%d", addr, port); + /* Initialize the set of active sockets. */ FD_ZERO(&active_fd_set); FD_SET(sock, &active_fd_set); @@ -285,7 +290,7 @@ int sock_poll_clients(void) { struct timeval t; - struct ClientSocketMap* clientSocket; + ClientSocketMap* clientSocket; debug(RPT_DEBUG, "%s()", __FUNCTION__); @@ -297,33 +302,32 @@ sock_poll_clients(void) if (select(FD_SETSIZE, &read_fd_set, NULL, NULL, &t) < 0) { report(RPT_ERR, "%s: Select error - %s", - __FUNCTION__, sock_geterror()); + __FUNCTION__, sock_geterror()); return -1; } /* Service all the sockets with input pending. */ - LL_Rewind(openSocketList); - for (clientSocket = (struct ClientSocketMap *) LL_Get(openSocketList); - clientSocket != NULL; - clientSocket = LL_GetNext(openSocketList)) { + LL_Rewind(openSocketList); + for (clientSocket = (ClientSocketMap *) LL_Get(openSocketList); + clientSocket != NULL; + clientSocket = LL_GetNext(openSocketList)) { if (FD_ISSET(clientSocket->socket, &read_fd_set)) { if (clientSocket->socket == listening_fd) { /* Connection request on original socket. */ - Client *c; + Client *c; int new_sock; struct sockaddr_in clientname; socklen_t size = sizeof(clientname); new_sock = accept(listening_fd, (struct sockaddr *) &clientname, &size); #ifdef WINSOCK2 - if (new_sock == INVALID_SOCKET) + if (new_sock == INVALID_SOCKET) { #else - if (new_sock < 0) + if (new_sock < 0) { #endif - { report(RPT_ERR, "%s: Accept error - %s", - __FUNCTION__, sock_geterror()); + __FUNCTION__, sock_geterror()); return -1; } report(RPT_NOTICE, "Connect from host %s:%hu on socket %i", @@ -331,10 +335,10 @@ sock_poll_clients(void) FD_SET(new_sock, &active_fd_set); #ifdef WINSOCK2 - { - unsigned long tmp; - ioctlsocket(new_sock, FIONBIO, &tmp); - } + { + unsigned long tmp; + ioctlsocket(new_sock, FIONBIO, &tmp); + } #else fcntl(new_sock, F_SETFL, O_NONBLOCK); #endif @@ -342,28 +346,29 @@ sock_poll_clients(void) /* Create new client */ if ((c = client_create(new_sock)) == NULL) { report(RPT_ERR, "%s: Error creating client on socket %i - %s", - __FUNCTION__, clientSocket->socket, sock_geterror()); + __FUNCTION__, clientSocket->socket, sock_geterror()); return -1; } else { - /* add new_sock */ - struct ClientSocketMap *newClientSocket; - newClientSocket = (struct ClientSocketMap *) LL_Pop(freeClientSocketList); - if (newClientSocket != NULL) { - newClientSocket->socket = new_sock; - newClientSocket->client = c; - LL_InsertNode(openSocketList, (void*) newClientSocket); - /* advance past the new node - check it on the next pass */ - LL_Next(openSocketList); - } + /* add new_sock */ + ClientSocketMap *newClientSocket; + newClientSocket = (ClientSocketMap *) LL_Pop(freeClientSocketList); + if (newClientSocket != NULL) { + newClientSocket->socket = new_sock; + newClientSocket->client = c; + LL_InsertNode(openSocketList, (void *) newClientSocket); + /* advance past the new node - check it on the next pass */ + LL_Next(openSocketList); + } else { - report(RPT_ERR, "%s: Error - free client socket list exhausted - %d clients.", - __FUNCTION__, FD_SETSIZE); - return -1; - } - } - if (clients_add_client(c) != 0) { - report(RPT_ERR, "%s: Could not add client on socket %i", __FUNCTION__, clientSocket->socket); + report(RPT_ERR, "%s: Error - free client socket list exhausted - %d clients.", + __FUNCTION__, FD_SETSIZE); + return -1; + } + } + if (clients_add_client(c) == NULL) { + report(RPT_ERR, "%s: Could not add client on socket %i", + __FUNCTION__, clientSocket->socket); return -1; } } @@ -374,27 +379,8 @@ sock_poll_clients(void) debug(RPT_DEBUG, "%s: reading...", __FUNCTION__); err = sock_read_from_client(clientSocket); debug(RPT_DEBUG, "%s: ...done", __FUNCTION__); - if (err < 0) { - /* Client disconnected, destroy client data */ - if (clientSocket->client) { - struct ClientSocketMap *entry; - - /*sock_send_string(i, "bye\n");*/ - report(RPT_NOTICE, "Client on socket %i disconnected", - clientSocket->socket); - client_destroy(clientSocket->client); - clients_remove_client(clientSocket->client); - FD_CLR(clientSocket->socket, &active_fd_set); - close(clientSocket->socket); - - entry = (struct ClientSocketMap *) LL_DeleteNode(openSocketList); - LL_Push(freeClientSocketList, (void*) entry); - } - else { - report(RPT_ERR, "%s: Can't find client of socket %i", - __FUNCTION__, clientSocket->socket); - } - } + if (err < 0) + sock_destroy_socket(); } while (err > 0); } } @@ -408,7 +394,7 @@ sock_poll_clients(void) * \retval 0 success */ static int -sock_read_from_client(struct ClientSocketMap *clientSocketMap) +sock_read_from_client(ClientSocketMap *clientSocketMap) { char buffer[MAXMSG]; int nbytes, i; @@ -420,17 +406,17 @@ sock_read_from_client(struct ClientSocketMap *clientSocketMap) if (nbytes < 0) { if (errno != EAGAIN) report(RPT_DEBUG, "%s: Error on socket %d - %s", - __FUNCTION__, clientSocketMap->socket, sock_geterror()); + __FUNCTION__, clientSocketMap->socket, sock_geterror()); return 0; } - else if (nbytes == 0) { /* EOF*/ + else if (nbytes == 0) { /* EOF*/ return -1; } else if (nbytes > (MAXMSG - (MAXMSG / 8))) { /* Very noisy client...*/ sock_send_error(clientSocketMap->socket, "Too much data received... quiet down!\n"); return -1; } - else { /* Data Read */ + else { /* Data Read */ buffer[nbytes] = '\0'; /* Now, replace zeros with linefeeds...*/ for (i = 0; i < nbytes; i++) @@ -441,17 +427,75 @@ sock_read_from_client(struct ClientSocketMap *clientSocketMap) client_add_message(clientSocketMap->client, buffer); } else { report(RPT_DEBUG, "%s: Can't find client %d", - __FUNCTION__, clientSocketMap->socket); - } + __FUNCTION__, clientSocketMap->socket); + } report(RPT_DEBUG, "%s: got message from client %d: \"%s\"", - __FUNCTION__, clientSocketMap->socket, buffer); + __FUNCTION__, clientSocketMap->socket, buffer); return nbytes; } return nbytes; } +/* comparison function to find a ClientsocketMap entry by client */ +int byClient(void *csm, void *client) +{ + return (((ClientSocketMap *) csm)->client == (Client *) client) ? 0 : -1; +} + + +/** Close an open socket for a given client. + * \param client Client whose socket shall be closed. + * \retval <0 error + * \retval 0 success. + */ +int +sock_destroy_client_socket(Client *client) +{ + ClientSocketMap *entry; + + LL_Rewind(openSocketList); + entry = LL_Find(openSocketList, byClient, client); + + if (entry != NULL) { + sock_destroy_socket(); + return 0; + } + return -1; +} + + +/** Close the socket the openSocketList's \c current pointer points to. + */ +static void +sock_destroy_socket(void) +{ + ClientSocketMap *entry = LL_Get(openSocketList); + + if (entry != NULL) { + if (entry->client != NULL) { + report(RPT_NOTICE, "Client on socket %i disconnected", + entry->socket); + client_destroy(entry->client); + clients_remove_client(entry->client); + entry->client = NULL; + } + else { + report(RPT_ERR, "%s: Can't find client of socket %i", + __FUNCTION__, entry->socket); + } + /* close socket and remove it from select()'s mask of active sockets */ + FD_CLR(entry->socket, &active_fd_set); + close(entry->socket); + + /* re-add socket to the free socket pool */ + entry = (ClientSocketMap *) LL_DeleteNode(openSocketList); + LL_Push(freeClientSocketList, (void*) entry); + } +} + + /* return 1 if addr is valid IPv4 */ int verify_ipv4(const char *addr) { @@ -476,7 +520,7 @@ int verify_ipv6(const char *addr) /* inet_pton returns positive value if it worked */ result = inet_pton(AF_INET6, addr, &a); - } + } return (result > 0) ? 1 : 0; } diff --git a/server/sock.h b/server/sock.h index eeef28a..76c6fed 100644 --- a/server/sock.h +++ b/server/sock.h @@ -1,13 +1,15 @@ -/* - * sock.h - * This file is part of LCDd, the lcdproc server. +/** \file sock.h + * function declarations for LCDproc sockets code + */ + +/* This file is part of LCDd, the lcdproc server. * * This file is released under the GNU General Public License. Refer to the * COPYING file distributed with this package. * * Copyright (c) 1999, William Ferrell, Scott Scriven * 2004, F5 Networks, Inc. - IP-address verification - * + * 2008, Peter Marschall */ #ifndef SOCK_H @@ -15,13 +17,14 @@ #include "shared/sockets.h" -typedef struct sockaddr_in sockaddr_in; +#include "client.h" /* Server functions...*/ int sock_init(char* bind_addr, int bind_port); int sock_shutdown(void); int sock_create_inet_socket(char* bind_addr, unsigned int port); int sock_poll_clients(void); +int sock_destroy_client_socket(Client *client); int verify_ipv4(const char *addr); int verify_ipv6(const char *addr);