Patch for exim-0.42 SMTP problem (serious)

トップ ページ
このメッセージを削除
このメッセージに返信
著者: Lee McLoughlin
日付:  
To: exim-users
題目: Patch for exim-0.42 SMTP problem (serious)
Before you worry this bug is only present on Sunos 4.

Basically in the smtp code the recv() system call is restarted by unix
if the alarm() interrupt occurs *before* any data has been received from
the remote end. The code expects the recv() to be stopped by the
interrupt and because it isn't the smtp code can hang indefinetly in
recv().

On *most* unixes the alarm() interrupt will cause the recv() to return
with an error. It just so happens that Sunos 4 does it differently.

The fix below will only allow the recv() to be called if data is
available, so preventing the problem.

I've discussed this with Philip but didn't get this patch to him before
his break.

Incidentally the new code basically does:
    select()
    recv()


this saves 3 system calls over the old code of:
    sigvec()    signal() = 2 sigvec() under sunos 4.
    sigvec()
    alarm()
    recv()
    alarm()


I've not had a chance to try this patch on anything other than a Sunos 4
box.

    Lee
--
Lee McLoughlin.                         Phone: +44 171 594 8388
IC-Parc, Imperial College,              Fax:   +44 171 594 8449
South Kensington, London. SW7 2BZ. UK.  Email: L.McLoughlin@???

*** smtp.c.ORIG    Tue Mar 19 17:55:47 1996
--- smtp.c    Mon Mar 25 19:19:49 1996
***************
*** 137,142 ****
--- 137,146 ----
  char *ptr = buffer;
  char *readptr = buffer;


+ fd_set in;
+ int ret;
+ struct timeval t;
+
/* Ensure errno starts out zero */

errno = 0;
***************
*** 146,171 ****

  for (;;)
    {
-   /* Set up for timing out */
-   
    transport_sigalrm_seen = FALSE;
-   alarm(dotcmd? ob->final_timeout : ob->command_timeout);


! /* Initialize empty buffer in case nothing gets read, read the response,
! then cancel the timer. */

! *readptr = 0;
! count = recv(deliver_socket, readptr, size-1, 0);
! alarm(0);

! /* Handle a timeout */

!   if (transport_sigalrm_seen)
      {
      errno = ETIMEDOUT;
      buffer[0] = 0; 
      return FALSE;
      }


    /* Handle an EOF (i.e. close down of the connection). */


--- 150,181 ----

  for (;;)
    {
    transport_sigalrm_seen = FALSE;


! /* Arrange for select() to fail if no data is available within the timeout */

! FD_ZERO (&in);
! FD_SET (deliver_socket, &in);

! t.tv_sec = (dotcmd? ob->final_timeout : ob->command_timeout);
! t.tv_usec = 0;

!   ret = select (1 << deliver_socket, &in, 0, 0, &t);
! 
!   if (ret <= 0)
      {
      errno = ETIMEDOUT;
      buffer[0] = 0; 
      return FALSE;
      }
+   else if (FD_ISSET(deliver_socket, &in))
+     {
+     /* Initialize empty buffer in case nothing gets read, read the response. */
+   
+     *readptr = 0;
+     count = recv(deliver_socket, readptr, size-1, 0);
+     }
+   


    /* Handle an EOF (i.e. close down of the connection). */