Patch to work around flaky pop3 server behaviour



This patch makes pop3 mail retrieval more robust.

It uses a non-blocking read function when retrieving characters from the
server, so that the mail retrieval thread doesn't hang when the server
fails to send an expected response.

I believe this resolves bug #55091.

Just this morning I discovered another issue that should be addressed: when
the pop3 server goes down, the mail retrieval thread hangs. I'll turn the
BALSA_TEST_POP3 code on, so that if the server goes down again, I'll know
what happened.

BTW, Neil Padgett <npadgett@redhat.com> helped with the attached patch.

To apply:

$(BALSA_SOURCE)/patch -p 1 < balsa-safe-read.patch

Keep up the great work on Balsa,
Tom
diff -c -r balsa-1.1.4/libbalsa/pop3.c balsa-1.1.4-modified/libbalsa/pop3.c
*** balsa-1.1.4/libbalsa/pop3.c	Thu Nov 16 14:43:13 2000
--- balsa-1.1.4-modified/libbalsa/pop3.c	Wed Jun  6 18:46:32 2001
***************
*** 32,37 ****
--- 32,39 ----
  #include <netdb.h>
  #include <string.h>
  
+ #include <errno.h>
+ #include <fcntl.h>
  #include <unistd.h>
  #include <stdio.h>
  #include <gnome.h>
***************
*** 61,72 ****
      return _(errmsgs[status]);
  }
  
  static int getLine (int fd, char *s, int len)
  {
      char ch;
      int bytes = 0;
      
!     while (read (fd, &ch, 1) > 0) {
  	*s++ = ch;
  	bytes++;
  	if (ch == '\n') {
--- 63,113 ----
      return _(errmsgs[status]);
  }
  
+ #define NUMBER_OF_RETRIES 20
+ 
+ /* safe_read_char:
+         Reads a character, without blocking indefinitely until a character
+         is available to be read. Retry NUMBER_OF_RETRIES times before
+         returning with an error.
+ */
+ static int
+ safe_read_char(int fd, char *ch)
+ {
+     int i = 0;
+     int retval = 0;
+ 
+     /* make read non-blocking */
+     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+     retval = read (fd, ch, 1);
+     /* make read blocking again */
+     fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) ^ O_NONBLOCK);
+     
+     if (retval == -1) {
+         
+         if (errno == EAGAIN) {
+             /* pause one second before trying again */
+             sleep(1);
+         } else return -1;
+         
+         if(i < NUMBER_OF_RETRIES) {
+             fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
+             retval = read (fd, ch, 1);
+             fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) ^ O_NONBLOCK);
+         } else return -1;
+         
+         i++;
+     } else return retval;
+     
+     /* make gcc happy */
+     return retval;
+ }
+ 
  static int getLine (int fd, char *s, int len)
  {
      char ch;
      int bytes = 0;
      
!     while (safe_read_char (fd, &ch) > 0) {
  	*s++ = ch;
  	bytes++;
  	if (ch == '\n') {


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