Preliminary fix for blocked socket closing.

From: George (greerga@circlemud.org)
Date: 01/15/99


Currently I have this to fix it.  The question is: Is the infrequent
occurrance of a blocked socket write while snooping frequent enough to
complicate the code to fix?  See the diff for more details on the effect I
am speaking of.

diff -u -p -r1.63 comm.c
--- comm.c      1999/01/08 08:17:01     1.63
+++ comm.c      1999/01/16 05:20:56
@@ -724,10 +724,17 @@ void game_loop(int mother_desc)
       next_d = d->next;
       if (*(d->output) && FD_ISSET(d->descriptor, &output_set)) {
        /* Output for this player is ready */
-       if (process_output(d) < 0)
+       switch (process_output(d)) {
+       case -1:                /* fatal/unknown error */
          close_socket(d);
-       else
+         break;
+       case 0:                 /* write blocked */
+         d->has_prompt = 0;
+         break;
+       default:                /* normal */
          d->has_prompt = 1;
+         break;
+       }
       }
     }

@@ -1292,7 +1299,7 @@ int new_descriptor(int s)
 int process_output(struct descriptor_data *t)
 {
   char i[MAX_SOCK_BUF];
-  int result;
+  int written, offset = 2;

   /* we may need this \r\n for later -- see below */
   strcpy(i, "\r\n");
@@ -1316,9 +1323,9 @@ int process_output(struct descriptor_dat
    * CRLF, otherwise send the straight output sans CRLF.
    */
   if (t->has_prompt)           /* && !t->connected) */
-    result = write_to_descriptor(t->descriptor, i);
-  else
-    result = write_to_descriptor(t->descriptor, i + 2);
+    offset = 0;
+
+  written = write_to_descriptor(t->descriptor, i + offset);

   /* handle snooping: prepend "% " and send to snooper */
   if (t->snoop_by) {
@@ -1341,7 +1348,20 @@ int process_output(struct descriptor_dat
   t->bufptr = 0;
   *(t->output) = '\0';

-  return (result);
+  /*
+   * We blocked, restore the unwritten output. Known
+   * bug in that the snooping immortal will see it twice
+   * but details...
+   */
+  if (written < 0) {
+    write_to_output(i + -written + offset, t);
+    return (0);
+  }
+
+  if (written == 0)    /* Error, kill'em. */
+    return (-1);
+
+  return (1);
 }


@@ -1450,38 +1470,39 @@ ssize_t perform_socket_write(socket_t de
  * encountered.
  *
  * Returns:
- *  0  If all is well and good,
- * -1  If an error was encountered, so that the player should be cut off
+ * >0  How many bytes written, all is well and good.
+ *  0  If an error was encountered, so that the player should be cut off.
+ * <0  The socket write would block, but wrote this many bytes previously.
  */
 int write_to_descriptor(socket_t desc, const char *txt)
 {
-  size_t total;
-  ssize_t bytes_written;
-
-  total = strlen(txt);
+  ssize_t bytes_written, bytes_total = 0;
+  size_t total = strlen(txt);

   while (total > 0) {
     bytes_written = perform_socket_write(desc, txt, total);

     if (bytes_written < 0) {
       /* Fatal error.  Disconnect the player. */
-      perror("SYSERR: Write to socket");
-      return (-1);
+      perror("SYSERR: write_to_descriptor");
+      return (0);
     } else if (bytes_written == 0) {
       /*
        * Temporary failure -- socket buffer full.  For now we'll just
        * cut off the player, but eventually we'll stuff the unsent
        * text into a buffer and retry the write later.  JE 30 June 98.
+       * Implemented the anti-cut-off code he wanted. GG 13 Jan 99.
        */
-      log("WARNING: write_to_descriptor: socket write would block, about to close");
-      return (-1);
+      log("WARNING: write_to_descriptor: socket write would block.");
+      return (-bytes_total);
     } else {
       txt += bytes_written;
       total -= bytes_written;
+      bytes_total += bytes_written;
     }
   }

-  return (0);
+  return (bytes_total);
 }

Thoughts?

--
George Greer
greerga@circlemud.org
http://www.van.ml.org/CircleMUD/


     +------------------------------------------------------------+
     | Ensure that you have read the CircleMUD Mailing List FAQ:  |
     |  http://qsilver.queensu.ca/~fletchra/Circle/list-faq.html  |
     +------------------------------------------------------------+



This archive was generated by hypermail 2b30 : 12/15/00 PST