[gnet-dev] [PATCH] examples/echoserver-async.c should check condition G_IO_OUT first



Greetings list!

I just noticed that the examples/echoserver-async.c program has a
small corner condition bug.

If it receives some data... and then it receives a read 0 bytes... it
will not echo the received data it previously read... because it
thinks the other side wants to disconnect... when, although this is
true, it should really send the data back first (or try to), then
disconnect.

I've attached a trivial patch which swaps the check for G_IO_IN and
G_IO_OUT flags / events... which _should_ handle this condition.

Comments?

E.g. try this to reproduce the but (timing is also a factor):


./echoserver-async 46600

echo "12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh12345678abcdefgh" | nc -vv -q 10 localhost 46600


If you use any of the other echo*servers*, they return the data, then
handle the disconnect.


-- 
Benjamin Lee                           mailto:benjamin lee realthought net
Melbourne, Australia                            http://www.realthought.net
Linux / BSD / GNU                                     tel:+61 4 16 BEN LEE

Open Source  "... invest in your company, not their company..."       
                "... invest in your world, not one country..."
__________________________________________________________________________
Nothing is faster than the speed of light ...

To prove this to yourself, try opening the refrigerator door before the
light comes on.
? echoserver-async.c.original.cvs
Index: echoserver-async.c
===================================================================
RCS file: /cvs/gnome/gnet/examples/echoserver-async.c,v
retrieving revision 1.6
diff -u -r1.6 echoserver-async.c
--- echoserver-async.c	19 Sep 2005 15:25:55 -0000	1.6
+++ echoserver-async.c	20 Nov 2005 10:07:07 -0000
@@ -184,6 +184,54 @@
       goto error;
     }
 
+  if (condition & G_IO_OUT)
+    {
+      GIOError error;
+      gsize bytes_written;
+
+      /* Write the data out */
+      error = g_io_channel_write(iochannel, client_state->buffer, 
+				 client_state->n, &bytes_written);
+
+      if (error != G_IO_ERROR_NONE) 
+	{
+	  fprintf (stderr, "Client write error (%s:%d): %d\n", 
+		   client_state->name, client_state->port, error);
+	  goto error;
+	}
+
+      else if (bytes_written > 0)
+	{
+	  guint old_watch_flags;
+
+	  /* Move the memory down some (you wouldn't want to do this
+	     in a performance server because it's slow!) */
+	  client_state->n -= bytes_written;
+	  g_memmove(client_state->buffer, 
+		    &client_state->buffer[bytes_written],
+		    client_state->n);
+
+	  old_watch_flags = client_state->watch_flags;
+
+	  /* Remove OUT watch if done */
+	  if (client_state->n == 0)
+	    client_state->watch_flags &= ~G_IO_OUT;
+
+	  /* Add IN watch */
+	  client_state->watch_flags |= G_IO_IN;
+
+	  /* Update watch flags if they changed */
+	  if (old_watch_flags != client_state->watch_flags)
+	    {
+	      g_source_remove (client_state->watch);
+	      client_state->watch = 
+		g_io_add_watch(iochannel, client_state->watch_flags,
+			       async_client_iofunc, client_state);
+	      rv = FALSE;
+	    }
+	}
+    }
+
   /* Check for data to be read (or if the socket was closed) */
   if (condition & G_IO_IN)
     {
@@ -243,54 +291,6 @@
 	    }
 	}
 
-    }
-
-  if (condition & G_IO_OUT)
-    {
-      GIOError error;
-      gsize bytes_written;
-
-      /* Write the data out */
-      error = g_io_channel_write(iochannel, client_state->buffer, 
-				 client_state->n, &bytes_written);
-
-      if (error != G_IO_ERROR_NONE) 
-	{
-	  fprintf (stderr, "Client write error (%s:%d): %d\n", 
-		   client_state->name, client_state->port, error);
-	  goto error;
-	}
-
-      else if (bytes_written > 0)
-	{
-	  guint old_watch_flags;
-
-	  /* Move the memory down some (you wouldn't want to do this
-	     in a performance server because it's slow!) */
-	  client_state->n -= bytes_written;
-	  g_memmove(client_state->buffer, 
-		    &client_state->buffer[bytes_written],
-		    client_state->n);
-
-	  old_watch_flags = client_state->watch_flags;
-
-	  /* Remove OUT watch if done */
-	  if (client_state->n == 0)
-	    client_state->watch_flags &= ~G_IO_OUT;
-
-	  /* Add IN watch */
-	  client_state->watch_flags |= G_IO_IN;
-
-	  /* Update watch flags if they changed */
-	  if (old_watch_flags != client_state->watch_flags)
-	    {
-	      g_source_remove (client_state->watch);
-	      client_state->watch = 
-		g_io_add_watch(iochannel, client_state->watch_flags,
-			       async_client_iofunc, client_state);
-	      rv = FALSE;
-	    }
-	}
     }
 
   return rv;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]