diff options
author | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-10 16:12:07 -0700 |
---|---|---|
committer | Ben Longbons <b.r.longbons@gmail.com> | 2011-09-10 16:12:07 -0700 |
commit | f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1 (patch) | |
tree | d9b013ab252968ec1e90e721f7b2ab819af0acb0 /src/common/socket.c | |
parent | 5939e1bec75f2550d3ce109b9cd9a5d22c0626c2 (diff) | |
parent | 723fb5d3431b847526c433a13aa74485cfb564a3 (diff) | |
download | tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.gz tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.bz2 tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.tar.xz tmwa-f841b6fdcc802e73d52da0e67ee192c0c2c1c7e1.zip |
Merge commit '723fb5d3431b847526c433a13aa74485cfb564a3'
Diffstat (limited to 'src/common/socket.c')
-rw-r--r-- | src/common/socket.c | 420 |
1 files changed, 137 insertions, 283 deletions
diff --git a/src/common/socket.c b/src/common/socket.c index dbf19c1..7c86b1a 100644 --- a/src/common/socket.c +++ b/src/common/socket.c @@ -6,17 +6,11 @@ #include <sys/types.h> #include <errno.h> -#ifdef LCCWIN32 -#define WIN32_LEAN_AND_MEAN -#include <windows.h> -#include <winsock2.h> -#else #include <sys/socket.h> #include <netinet/in.h> #include <netinet/tcp.h> #include <sys/time.h> #include <unistd.h> -#endif #include <fcntl.h> #include <string.h> @@ -25,191 +19,115 @@ #include "socket.h" #include "utils.h" -#ifdef MEMWATCH -#include "memwatch.h" -#endif - fd_set readfds; int fd_max; int currentuse; -int rfifo_size = 65536; -int wfifo_size = 65536; +const uint32_t rfifo_size = 65536; +const uint32_t wfifo_size = 65536; struct socket_data *session[FD_SETSIZE]; -static int null_parse (int fd); -static int (*default_func_parse) (int) = null_parse; +/// Discard all input +static void null_parse (int fd); +/// Default parser for new connections +static void (*default_func_parse) (int) = null_parse; -/*====================================== - * CORE : Set function - *-------------------------------------- - */ -void set_defaultparse (int (*defaultparse) (int)) +void set_defaultparse (void (*defaultparse) (int)) { default_func_parse = defaultparse; } -/*====================================== - * CORE : Socket Sub Function - *-------------------------------------- - */ - -static int recv_to_fifo (int fd) +/// Read from socket to the queue +static void recv_to_fifo (int fd) { - int len; - - //printf("recv_to_fifo : %d %d\n",fd,session[fd]->eof); if (session[fd]->eof) - return -1; - -#ifdef LCCWIN32 - len = - recv (fd, session[fd]->rdata + session[fd]->rdata_size, - RFIFOSPACE (fd), 0); -#else - len = - read (fd, session[fd]->rdata + session[fd]->rdata_size, - RFIFOSPACE (fd)); -#endif + return; -// printf (":::RECEIVE:::\n"); -// dump(session[fd]->rdata, len); printf ("\n"); + ssize_t len = read (fd, session[fd]->rdata + session[fd]->rdata_size, + RFIFOSPACE (fd)); - //{ int i; printf("recv %d : ",fd); for(i=0;i<len;i++){ printf("%02x ",RFIFOB(fd,session[fd]->rdata_size+i)); } printf("\n");} if (len > 0) { session[fd]->rdata_size += len; - if (!session[fd]->connected) - session[fd]->connected = 1; + session[fd]->connected = 1; } - else if (len <= 0) + else { - // value of connection is not necessary the same -// if (fd == 4) // Removed [Yor] -// printf("Char-Server Has Disconnected.\n"); -// else if (fd == 5) // Removed [Yor] -// printf("Attempt To Log In Successful.\n"); -// else if (fd == 7) // Removed [Yor] -// printf("Char-Server Has Disconnected.\n"); -// else if (fd == 8) // Removed [Valaris] -// printf("%s has logged off your server.\n",RFIFOP(fd,6)); // Removed [Valaris] - -// else if (fd != 8) // [Valaris] - printf ("set eof : connection #%d\n", fd); session[fd]->eof = 1; } - return 0; } -static int send_from_fifo (int fd) +static void send_from_fifo (int fd) { - int len; - - //printf("send_from_fifo : %d\n",fd); if (session[fd]->eof) - return -1; - -#ifdef LCCWIN32 - len = send (fd, session[fd]->wdata, session[fd]->wdata_size, 0); -#else - len = write (fd, session[fd]->wdata, session[fd]->wdata_size); -#endif + return; -// printf (":::SEND:::\n"); -// dump(session[fd]->wdata, len); printf ("\n"); + ssize_t len = write (fd, session[fd]->wdata, session[fd]->wdata_size); - //{ int i; printf("send %d : ",fd); for(i=0;i<len;i++){ printf("%02x ",session[fd]->wdata[i]); } printf("\n");} if (len > 0) { - if (len < session[fd]->wdata_size) + session[fd]->wdata_size -= len; + if (len < (ssize_t)session[fd]->wdata_size) { memmove (session[fd]->wdata, session[fd]->wdata + len, - session[fd]->wdata_size - len); - session[fd]->wdata_size -= len; + session[fd]->wdata_size); } - else - { - session[fd]->wdata_size = 0; - } - if (!session[fd]->connected) - session[fd]->connected = 1; + session[fd]->connected = 1; } else { - printf ("set eof :%d\n", fd); session[fd]->eof = 1; } - return 0; } -static int null_parse (int fd) +static void null_parse (int fd) { printf ("null_parse : %d\n", fd); RFIFOSKIP (fd, RFIFOREST (fd)); - return 0; } -/*====================================== - * CORE : Socket Function - *-------------------------------------- - */ -static int connect_client (int listen_fd) +static void connect_client (int listen_fd) { - int fd; struct sockaddr_in client_address; - unsigned int len; - int result; - int yes = 1; // reuse fix - - //printf("connect_client : %d\n",listen_fd); - - printf ("used: %d, max FDs: %d, SOFT: %d\n", currentuse, FD_SETSIZE, - SOFT_LIMIT); - - len = sizeof (client_address); + socklen_t len = sizeof (client_address); - fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); - if (fd_max <= fd) + int fd = accept (listen_fd, (struct sockaddr *) &client_address, &len); + if (fd == -1) { - fd_max = fd + 1; + perror ("accept"); + return; } - else if (fd == -1) + if (fd_max <= fd) { - perror ("accept"); - return -1; + fd_max = fd + 1; } if (!free_fds ()) - { // gracefully end the connecting if no free FD - printf ("softlimit reached, disconnecting : %d\n", fd); + { + fprintf (stderr, "softlimit reached, disconnecting : %d\n", fd); delete_session (fd); - return -1; + return; } -// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof yes); // reuse fix -#ifdef SO_REUSEPORT -// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (char *) &yes, sizeof yes); //reuse fix -#endif -// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof yes); // reuse fix + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); FD_SET (fd, &readfds); -#ifdef LCCWIN32 - { - unsigned long val = 1; - ioctlsocket (fd, FIONBIO, &val); - } -#else - result = fcntl (fd, F_SETFL, O_NONBLOCK); -#endif + fcntl (fd, F_SETFL, O_NONBLOCK); CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, unsigned char, rfifo_size); - CREATE (session[fd]->wdata, unsigned char, wfifo_size); + CREATE (session[fd]->rdata, uint8_t, rfifo_size); + CREATE (session[fd]->wdata, uint8_t, wfifo_size); session[fd]->max_rdata = rfifo_size; session[fd]->max_wdata = wfifo_size; @@ -221,59 +139,44 @@ static int connect_client (int listen_fd) session[fd]->connected = 0; currentuse++; - - //printf("new_session : %d %d\n",fd,session[fd]->eof); - return fd; } -int make_listen_port (int port) +int make_listen_port (uint16_t port) { struct sockaddr_in server_address; - int fd; - int result; - int yes = 1; // reuse fix - - fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd_max <= fd) - fd_max = fd + 1; - else if (fd == -1) + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) { - perror ("connect"); + perror ("socket"); return -1; } + if (fd_max <= fd) + fd_max = fd + 1; -#ifdef LCCWIN32 - { - unsigned long val = 1; - ioctlsocket (fd, FIONBIO, &val); - } -#else - result = fcntl (fd, F_SETFL, O_NONBLOCK); -#endif - -// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof yes); // reuse fix -#ifdef SO_REUSEPORT -// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (char *) &yes, sizeof yes); //reuse fix -#endif -// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof yes); // reuse fix + fcntl (fd, F_SETFL, O_NONBLOCK); + + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = htonl (INADDR_ANY); server_address.sin_port = htons (port); - result = - bind (fd, (struct sockaddr *) &server_address, - sizeof (server_address)); - if (result == -1) + if (bind (fd, (struct sockaddr *) &server_address, + sizeof (server_address)) == -1) { perror ("bind"); exit (1); } - result = listen (fd, 5); - if (result == -1) + if (listen (fd, 5) == -1) { /* error */ perror ("listen"); exit (1); @@ -283,12 +186,6 @@ int make_listen_port (int port) CREATE (session[fd], struct socket_data, 1); - if (session[fd] == NULL) - { - printf ("out of memory : make_listen_port\n"); - exit (1); - } - memset (session[fd], 0, sizeof (*session[fd])); session[fd]->func_recv = connect_client; session[fd]->created = time (NULL); session[fd]->connected = 1; @@ -297,53 +194,45 @@ int make_listen_port (int port) return fd; } -int make_connection (long ip, int port) +int make_connection (uint32_t ip, uint16_t port) { struct sockaddr_in server_address; - int fd; - int result; - int yes = 1; // reuse fix - - fd = socket (AF_INET, SOCK_STREAM, 0); - if (fd_max <= fd) - fd_max = fd + 1; - else if (fd == -1) + int fd = socket (AF_INET, SOCK_STREAM, 0); + if (fd == -1) { perror ("socket"); return -1; } + if (fd_max <= fd) + fd_max = fd + 1; -// setsockopt(fd,SOL_SOCKET,SO_REUSEADDR,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (char *) &yes, sizeof yes); // reuse fix -#ifdef SO_REUSEPORT -// setsockopt(fd,SOL_SOCKET,SO_REUSEPORT,NULL,0); - setsockopt (fd, SOL_SOCKET, SO_REUSEPORT, (char *) &yes, sizeof yes); //reuse fix -#endif -// setsockopt(fd,IPPROTO_TCP,TCP_NODELAY,NULL,0); - setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, (char *) &yes, sizeof yes); // reuse fix + const int yes = 1; + /// Allow to bind() again after the server restarts. + // Since the socket is still in the TIME_WAIT, there's a possibility + // that formerly lost packets might be delivered and confuse the server. + setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes); + /// Send packets as soon as possible + /// even if the kernel thinks there is too little for it to be worth it! + // I'm not convinced this is a good idea; although in minimizes the + // latency for an individual write, it increases traffic in general. + setsockopt (fd, IPPROTO_TCP, TCP_NODELAY, &yes, sizeof yes); server_address.sin_family = AF_INET; server_address.sin_addr.s_addr = ip; server_address.sin_port = htons (port); -#ifdef LCCWIN32 - { - unsigned long val = 1; - ioctlsocket (fd, FIONBIO, &val); - } -#else - result = fcntl (fd, F_SETFL, O_NONBLOCK); -#endif + fcntl (fd, F_SETFL, O_NONBLOCK); - result = - connect (fd, (struct sockaddr *) (&server_address), - sizeof (struct sockaddr_in)); + /// Errors not caught - we must not block + /// Let the main select() loop detect when we know the state + connect (fd, (struct sockaddr *) &server_address, + sizeof (struct sockaddr_in)); FD_SET (fd, &readfds); CREATE (session[fd], struct socket_data, 1); - CREATE (session[fd]->rdata, unsigned char, rfifo_size); - CREATE (session[fd]->wdata, unsigned char, wfifo_size); + CREATE (session[fd]->rdata, uint8_t, rfifo_size); + CREATE (session[fd]->wdata, uint8_t, wfifo_size); session[fd]->max_rdata = rfifo_size; session[fd]->max_wdata = wfifo_size; @@ -357,51 +246,53 @@ int make_connection (long ip, int port) return fd; } -int delete_session (int fd) +void delete_session (int fd) { if (fd < 0 || fd >= FD_SETSIZE) - return -1; + return; + // If this was the highest fd, decrease it + // We could add a loop to decrement fd_max further for every null session, + // but this is cheap and good enough for the typical case + if (fd == fd_max - 1) + fd_max--; FD_CLR (fd, &readfds); if (session[fd]) { - if (session[fd]->rdata) - free (session[fd]->rdata); - if (session[fd]->wdata) - free (session[fd]->wdata); - if (session[fd]->session_data) - free (session[fd]->session_data); + free (session[fd]->rdata); + free (session[fd]->wdata); + free (session[fd]->session_data); free (session[fd]); } session[fd] = NULL; + + // just close() would try to keep sending buffers shutdown (fd, SHUT_RDWR); close (fd); currentuse--; if (currentuse < 0) { - printf ("delete_session: current sessions negative!\n"); + fprintf (stderr, "delete_session: current sessions negative!\n"); currentuse = 0; } - //printf("delete_session:%d\n",fd); - return 0; + return; } -int realloc_fifo (int fd, int rfifo_size, int wfifo_size) +void realloc_fifo (int fd, size_t rfifo_size, size_t wfifo_size) { struct socket_data *s = session[fd]; if (s->max_rdata != rfifo_size && s->rdata_size < rfifo_size) { - RECREATE (s->rdata, unsigned char, rfifo_size); + RECREATE (s->rdata, uint8_t, rfifo_size); s->max_rdata = rfifo_size; } if (s->max_wdata != wfifo_size && s->wdata_size < wfifo_size) { - RECREATE (s->wdata, unsigned char, wfifo_size); + RECREATE (s->wdata, uint8_t, wfifo_size); s->max_wdata = wfifo_size; } - return 0; } -int WFIFOSET (int fd, int len) +void WFIFOSET (int fd, size_t len) { struct socket_data *s = session[fd]; if (s->wdata_size + len + 16384 > s->max_wdata) @@ -409,64 +300,49 @@ int WFIFOSET (int fd, int len) realloc_fifo (fd, s->max_rdata, s->max_wdata << 1); printf ("socket: %d wdata expanded to %d bytes.\n", fd, s->max_wdata); } - s->wdata_size = (s->wdata_size + (len) + 2048 < s->max_wdata) ? - s->wdata_size + len : (printf ("socket: %d wdata lost !!\n", fd), - s->wdata_size); - return 0; + if (s->wdata_size + len + 2048 < s->max_wdata) + s->wdata_size += len; + else + fprintf (stderr, "socket: %d wdata lost !!\n", fd), abort (); } -int do_sendrecv (int next) +void do_sendrecv (uint32_t next) { - fd_set rfd, wfd; - struct timeval timeout; - int ret, i; - - rfd = readfds; + fd_set rfd = readfds, wfd; FD_ZERO (&wfd); - for (i = 0; i < fd_max; i++) + for (int i = 0; i < fd_max; i++) { - if (!session[i] && FD_ISSET (i, &readfds)) - { - printf ("force clr fds %d\n", i); - FD_CLR (i, &readfds); - continue; - } - if (!session[i]) - continue; - if (session[i]->wdata_size) + if (session[i] && session[i]->wdata_size) FD_SET (i, &wfd); } + struct timeval timeout; timeout.tv_sec = next / 1000; timeout.tv_usec = next % 1000 * 1000; - ret = select (fd_max, &rfd, &wfd, NULL, &timeout); - if (ret <= 0) - return 0; - for (i = 0; i < fd_max; i++) + if (select (fd_max, &rfd, &wfd, NULL, &timeout) <= 0) + return; + for (int i = 0; i < fd_max; i++) { if (!session[i]) continue; if (FD_ISSET (i, &wfd)) { - //printf("write:%d\n",i); if (session[i]->func_send) //send_from_fifo(i); session[i]->func_send (i); } if (FD_ISSET (i, &rfd)) { - //printf("read:%d\n",i); if (session[i]->func_recv) //recv_to_fifo(i); + //or connect_client(i); session[i]->func_recv (i); } } - return 0; } -int do_parsepacket (void) +void do_parsepacket (void) { - int i; - for (i = 0; i < fd_max; i++) + for (int i = 0; i < fd_max; i++) { if (!session[i]) continue; @@ -476,76 +352,54 @@ int do_parsepacket (void) printf ("Session #%d timed out\n", i); session[i]->eof = 1; } - if (session[i]->rdata_size == 0 && session[i]->eof == 0) + if (!session[i]->rdata_size && !session[i]->eof) continue; if (session[i]->func_parse) { session[i]->func_parse (i); + /// some func_parse may call delete_session if (!session[i]) continue; } + /// Reclaim buffer space for what was read RFIFOFLUSH (i); } - return 0; } void do_socket (void) { FD_ZERO (&readfds); - currentuse = 2; + currentuse = 3; } -int RFIFOSKIP (int fd, int len) +void RFIFOSKIP (int fd, size_t len) { struct socket_data *s = session[fd]; + s->rdata_pos += len; - if (s->rdata_size - s->rdata_pos - len < 0) + if (s->rdata_size < s->rdata_pos) { fprintf (stderr, "too many skip\n"); - exit (1); + abort (); } - - s->rdata_pos = s->rdata_pos + len; - - return 0; } -int Net_Init (void) +void fclose_ (FILE * fp) { -#ifdef LCCWIN32 - /* Start up the windows networking */ - WORD version_wanted = MAKEWORD (1, 1); - WSADATA wsaData; - - if (WSAStartup (version_wanted, &wsaData) != 0) - { - printf ("SYSERR: WinSock not available!\n"); - exit (1); - } -#endif - - return (0); -} - -int fclose_ (FILE * fp) -{ - int res = fclose (fp); - if (res == 0) - currentuse--; -// printf("file closed: used: %d\n",currentuse); - return res; + if (fclose (fp)) + perror ("fclose"), abort (); + currentuse--; } FILE *fopen_ (const char *path, const char *mode) { FILE *f = fopen (path, mode); - if (f != NULL) + if (f) currentuse++; -// printf("file opened: used: %d\n",currentuse); return f; } -int free_fds () +bool free_fds () { - return (currentuse + 1 < SOFT_LIMIT) ? 1 : 0; + return currentuse < SOFT_LIMIT; } |