From bef9bf3bc6c29ede244fea24201c6ab37a37371f Mon Sep 17 00:00:00 2001
From: Travis Glenn Hansen <travisghansen@yahoo.com>
Date: Wed, 17 Oct 2012 10:20:08 -0600
Subject: [PATCH] some experimental changes trying to resolve infinite loop
 issues with the merged ipv6 code

---
 fanout.c | 70 ++++++++++++++++++++++++++++++++++++++++++++------------
 1 file changed, 56 insertions(+), 14 deletions(-)

diff --git a/fanout.c b/fanout.c
index a02271d..cf60920 100644
--- a/fanout.c
+++ b/fanout.c
@@ -63,9 +63,10 @@ int strcpos (const char *haystack, const char c);
 char *substr (const char *s, int start, int stop);
 void str_swap_free (char **target, char *source);
 char *str_append (char *target, const char *data);
-void fanout_error(const char *msg);
+void clear_socket_buffer (int sock);
+void fanout_error (const char *msg);
 void fanout_debug (int level, const char *format, ...);
-char *getsocketpeername(int fd);
+char *getsocketpeername (int fd);
 
 int channel_exists (const char *channel_name);
 int channel_has_subscription (struct channel *c);
@@ -173,6 +174,12 @@ int main (int argc, char *argv[])
 
     struct client *client_i = NULL;
     struct client *client_tmp = NULL;
+    
+    struct linger so_linger;
+    so_linger.l_onoff = 1;
+    // immediately discard any remaining data
+    so_linger.l_linger = 0;
+
 
     socklen_t clilen;
     struct sockaddr_storage cli_addr;
@@ -355,7 +362,7 @@ xit\n");
             fanout_error ("failed setting REUSEADDR");
             exit (EXIT_FAILURE);
         }
-
+        
         if (bind (fds[nfds].data.fd, runp->ai_addr, runp->ai_addrlen ) != 0) {
             fanout_error ("ERROR on binding");
             exit (EXIT_FAILURE);
@@ -502,6 +509,9 @@ xit\n");
         for (n = 0; n < nevents; n++) {
             // new connection
             efd = events[n].data.fd;
+            fanout_debug (3, "processing event %d of %d\n", (n+1),
+                           nevents);
+            fanout_debug (3, "current event fd %d\n", efd);
 
             int newconnection = 0;
             for (n=0; n < nfds; n++) {
@@ -597,16 +607,14 @@ resetting counter\n");
                         if (res <= 0) {
                             fanout_debug (2, "client socket disconnected\n");
 
-                            client_tmp = client_i;
-                            client_i = client_i->next;
-
                             //del socket from watch list
                             if (epoll_ctl (epollfd, EPOLL_CTL_DEL,
-                                 client_tmp->fd, &ev) == -1) {
+                                 client_i->fd, &ev) == -1) {
                                 fanout_error ("epoll_ctl: srvsock");
                             }
-                            shutdown_client (client_tmp);
-                            continue;
+                            fanout_debug (3, "client socket removed from epoll watch list\n");
+                            shutdown_client (client_i);
+                            break;
                         } else {
                             // Process data in buffer
                             fanout_debug (3, "%d bytes read: [%.*s]\n", res,
@@ -615,9 +623,12 @@ resetting counter\n");
                                                         client_i->input_buffer,
                                                         buffer);
                             client_process_input_buffer (client_i);
+                            break;
                         }
                     }
                     client_i = client_i->next;
+                    if (client_i != NULL)
+                        fanout_debug (3, "moving to client_i %d\n", client_i->fd);
                 }//end while (client_i != NULL)
             }//end else
         }//end for
@@ -684,6 +695,25 @@ char *str_append (char *target, const char *data)
     return strcat (target, data);
 }
 
+
+void clear_socket_buffer (int sock)
+{
+    int res;
+    char buffer[1025];
+    for(;;) {
+        res = read (sock, buffer, 1024);
+        
+        if (res < 0) {
+            fanout_debug (0, "%s\n", "failed clearing socket buffer");
+            break;
+        }
+
+        if (!res)
+            break;
+    }
+}
+
+
 void fanout_error(const char *msg)
 {
     fanout_debug (0, "%s: %s\n", msg, strerror (errno));
@@ -752,8 +782,8 @@ char *getsocketpeername (int fd)
     socklen_t len;
     len = sizeof m_addr;
 
-    getpeername(fd, (struct sockaddr*)&m_addr, &len);
-    getnameinfo((struct sockaddr*)&m_addr, len, ipstr, sizeof ipstr, NULL, 0, NI_NUMERICHOST);
+    getpeername (fd, (struct sockaddr*)&m_addr, &len);
+    getnameinfo ((struct sockaddr*)&m_addr, len, ipstr, sizeof ipstr, NULL, 0, NI_NUMERICHOST);
     return ipstr;
 }
 
@@ -859,9 +889,15 @@ void remove_client (struct client *c)
     fanout_debug (3, "removing client %d connected from service\n",
                    c->fd);
     if (c->next != NULL) {
+        if (c->previous != NULL)
+            fanout_debug (3, "setting previous on %d to %d\n",
+                           c->next->fd, c->previous->fd);
         c->next->previous = c->previous;
     }
     if (c->previous != NULL) {
+        if (c->next != NULL)
+            fanout_debug (3, "setting next on %d to %d\n",
+                           c->previous->fd, c->next->fd);
         c->previous->next = c->next;
     }
     if (c == client_head) {
@@ -883,8 +919,13 @@ void shutdown_client (struct client *c)
     }
 
     remove_client (c);
-    shutdown (c->fd, 2);
-    close (c->fd);
+    if (shutdown (c->fd, 2) == -1) {
+        fanout_error ("ERROR calling shutdown on client");
+    }
+    clear_socket_buffer (c->fd);
+    if (close (c->fd) == -1) {
+        fanout_error ("ERRRO closing the socket");
+    }
     destroy_client (c);
 }
 
@@ -904,7 +945,8 @@ void client_write (struct client *c, const char *data)
     c->output_buffer = str_append (c->output_buffer, data);
 
     while (strlen (c->output_buffer) > 0) {
-        sent = send (c->fd, c->output_buffer, strlen (c->output_buffer), 0);
+        sent = send (c->fd, c->output_buffer, strlen (c->output_buffer),
+                      MSG_NOSIGNAL);
         if (sent == -1)
             break;
         fanout_debug (3, "wrote %d bytes\n", sent);
-- 
GitLab