WriteData() and EAGAIN (Resource temporarily unavailable)

"Dmitry N. Fomin" <dif-Ojq+iQ4dngjh4wg/[email protected]> Wed, 15 Oct 2003 15:01:36 +0400
Newsgroups gmane.comp.security.zebedee.general
Organization MEDLUX network, Moscow, Russia
Message-ID <[email protected]>
I. Topic.

send() returns errno = EAGAIN (Resource temporarily unavailable).

Product - Zebedee 2.4.1.
Platform - FreeBSD 4.8-STABLE.

II. Problem Description.

    Let the server of application is located on the same host,
as Zebedee server. The server of application can create a stream of
the big messages, which are badly compressed.
For example, loading big .jpeg files through http.
Zebedee server has not time to transfer this stream in the tunnel
and returns errno = EAGAIN (Resource temporarily unavailable).
The increase maxbufsize up to 16383 does not solve a problem. 

Configuration file:

verbosity       5
detached        true 
ipmode          tcp  
udpmode         false
multiuse        true
#
redirect       80         # HTTP
redirect       443        # HTTPS
#
target localhost:80
target localhost:443
#
compression zlib:9
#maxbufsize 16383
readtimeout 20 
tcptimeout 3600
udptimeout 100

Part logfile:
......
      read 8192 bytes from local socket 1                              
     writeMessage: message compressed from 8192 to 4711 bytes          
     writeMessage: message size = 4711, encrypted, compressed          
      writeData: sending 4713 of 4713                                  
      writeData: sent 4713 byte(s)                                     
      read 8192 bytes from local socket 1                              
     writeMessage: message compressed from 8192 to 4391 bytes          
     writeMessage: message size = 4391, encrypted, compressed          
      writeData: sending 4393 of 4393                                  
      writeData: EOF or error: (Resource temporarily unavailable)      
    connection closed or timed out                                     
   read 317 bytes (317 expanded) in 10 messages                        
   wrote 60307 bytes (122754 expanded) in 25 messages                  
 ERROR: failed communicating with remote client: (Resource temporarily unavailable)
....... 

III. The possible solution.

======== cut zebedee.c.patch ==========================
--- zebedee.c	Tue May 28 06:31:15 2002
+++ zebedee.c	Wed Oct 15 09:19:30 2003
@@ -1163,25 +1163,89 @@
 int
 writeData(int fd, unsigned char *buffer, unsigned short size)
 {
+    fd_set testSet;
+    int ready=0;
+    struct timeval delay;
     int num = 0;
     char *bufP = NULL;
     unsigned short total = 0;
 
     bufP = (char *)buffer;
+
+    /* Set up the delay for select */
+
+    delay.tv_usec=0;
+
+    if (ReadTimeout > 0)
+    {
+       delay.tv_sec=ReadTimeout;
+    }
+    else
+    {
+       delay.tv_sec=0;
+    } 
+    message(5, 0, "writeData: writetimeout %d", delay.tv_sec);
+ 
+    /*  Set up file descriptors in mask to test */
+
+    FD_ZERO(&testSet);
+    FD_SET(fd,&testSet);
+ 
+    /*Do a blocking select waiting for any i/o */
+
+    ready=select(fd+1,0,&testSet,0,&delay);
+ 
+    if(ready<=0 && errno!=EINTR)
+    {
+      message(5, errno, "writeData: error in select");
+      FD_CLR(fd, &testSet);
+      return -1;
+    }   
     do
     {
 	message(5, 0, "writeData: sending %d of %d", (size - total), size);
-	if ((num = send(fd, (bufP + total), (size - total), 0)) <= 0)
+/*	if ((num = send(fd, (bufP + total), (size - total), 0)) <= 0)
 	{
+*/
+        do {
+             if ((num = send(fd, (bufP + total), (size - total), 0)) > 0)
+             {
+                break;
+             }
+
+             if (num<0 && errno==EAGAIN) 
+             {
+                ready=select(fd+1,0,&testSet,0,&delay);
+
+                if(ready==0)
+                {
+                  message(0, errno, "timed out writing data");
+                  FD_CLR(fd, &testSet);
+                  return -1;
+                }
+
+                if(ready<=0 && errno!=EINTR)
+                {
+                  message(5, errno, "writeData: error in select");
+                  FD_CLR(fd, &testSet);
+                  return -1;
+                }
+
+	        message(5, 0, "writeData: again sending to local socket %d", ready);
+                continue;   
+             }
 	    /* Premature EOF or error */
 	    message(5, errno, "writeData: EOF or error");
+            FD_CLR(fd, &testSet);
 	    return num;
 	}
+        while(1);
 	total += (unsigned short)num;
 	message(5, 0, "writeData: sent %d byte(s)", num);
     }
     while (total < size);
 
+    FD_CLR(fd, &testSet);
     return total;
 }

======== end cut zebedee.c.patch ======================

Timeout sendings are defined with a "readtimeout" option.
Look "ReadTimeout" variable.
Probably, it is necessary to add a "writetimeout" option.


P.S.
It is necessary to process also and other erroneous conditions for system calls
send() and recv(). For example, EPIPE (Broken pipe).


-------------------------------------------------------
This SF.net email is sponsored by: SF.net Giveback Program.
SourceForge.net hosts over 70,000 Open Source Projects.
See the people who have HELPED US provide better services:
Click here: http://sourceforge.net/supporters.php