This is the mail archive of the cygwin@sources.redhat.com mailing list for the Cygwin project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

socket read()/write() problem in 1.1.6


Hi,

I stumbled over a problem with socket reading/writing after I upgraded
from cygwin1.dll version 1.1.4 to 1.1.6

I'm developing a client/server application that communicates via Unix
sockets in a fairly standard way. This app works on Linux and used to
work from CygWin B20 until 1.1.4. Now its broke.

I use wrappers for read() [tread()] and write() [iwrite()] that use
select() to retry in case of transmission problems (these wrappers
were stolen and modified from GNU wget; the code with some debug
printf()s is appended below). The problem occurs if I use more than
one iwrite() call to write to the socket. While this should be
possible, tread() just reads the first transmission and quits with a
"connection reset by peer" error. See the following transcripts with
two versions of cygwin1.dll. The server sends 2 short strings of 4 and
6 byte, respectively, a newline after each, and a '\0' to terminate
the message. To demonstrate the problem, everything is written
separately, i.e. something like (pseudo code)

iwrite(string0,...);
iwrite("\n",...);
iwrite(string1,...);
iwrite("\n",...);
iwrite("",...);

The server output with both cygwin versions looks like this:

iwrite0:4
iwrite1:4
iwrite0:1
iwrite1:1
iwrite0:6
iwrite1:6
iwrite0:1
iwrite1:1
iwrite0:1
iwrite1:1

i.e. all the bits and pieces get written to the socket.

If I look at the client side, I get with version 1.1.3 (or on Linux):

tread0:13
tread0: error 0

i.e. all subsequently written strings were read by tread().

With version 1.1.6 I see instead:

tread1:4
tread1: Connection reset by peer

i.e. the server apparently resets the connection after the first chunk
is written and the client cannot read again from the same socket.

What am I doing wrong? Any help is appreciated.

regards,
Markus

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  tread(): Read at most LEN bytes from FD, storing them to BUF.  This
  is virtually the same as iread(), but it checks after each success-
  ful read() whether a string is complete (i.e. whether a '\0' was
  received). In this case, the function returns immediately, instead
  of timing out, even if less byte than requested were received.

  int tread the number of bytes read from fd, or -1 if timeout

  char *buf a pointer to a character buffer which receives the data

  int len the number of bytes that iread will attempt to read from fd

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int tread (int fd, char *buf, int len) {
  int res;
  int n_byte_read = 0;

  while (len > 0) { /* read until we have all, a complete string, or timeout */
    do {
      if (n_refdb_timeout) {
	do {
	  res = select_fd (fd, n_refdb_timeout, 0);
	} while (res == -1 && errno == EINTR);
	if (res <= 0) {
	  /* Set errno to ETIMEDOUT on timeout.  */
	  if (res == 0)
	    /* #### Potentially evil!  */
	    errno = ETIMEDOUT;
	  return -1;
	}
      }
      res = read(fd, buf, len); /* read some data */
      if (res > 0) { /* see whether we've got a complete string */
	if (buf[res-1] == '\0') { /* complete string received */
	  n_byte_read += res;
	  printf("tread0:%d\n", n_byte_read);
	  perror("tread0");
	  return n_byte_read; /* get back w/o timeout */
	}
      }
    } while (res == -1 && errno == EINTR);
    if (res <= 0)
      break;
    n_byte_read += res;
    buf += res;
    len -= res;
  }
  printf("tread1:%d\n", n_byte_read);
  perror("tread1");
  return n_byte_read;
}

/*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
  iwrite(): Write LEN bytes from BUF to FD.  This is similar to
  iread().  It makes sure that all of BUF is actually
  written to FD, so callers needn't bother with checking that the
  return value equals to LEN.  Instead, you should simply check
  for -1.

  int iwrite the number of bytes actually written to fd, or -1 if
             timeout

  char *buf a pointer to a character buffer which holds the data

  int len the number of bytes that iwrite will attempt to write to fd

  ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++*/
int iwrite (int fd, const char *buf, int len) {
  int res = 0;
  int n_byte_written = 0;

  /* `write' may write less than LEN bytes, thus the outward loop
     keeps trying it until all was written, or an error occurred.  The
     inner loop is reserved for the usual EINTR f*kage, and the
     innermost loop deals with the same during select().  */
  while (len > 0) {
    do {
      if (n_refdb_timeout) {
	do {
	  res = select_fd (fd, n_refdb_timeout, 1);
	} while (res == -1 && errno == EINTR);
	if (res <= 0) {
	  /* Set errno to ETIMEDOUT on timeout.  */
	  if (res == 0)
	    /* #### Potentially evil!  */
	    errno = ETIMEDOUT;
	  return -1;
	}
      }
      res = write (fd, buf, len); /* write some data */
      printf("iwrite0:%d\n", res);
      n_byte_written += res;
    } while (res == -1 && errno == EINTR);
    if (res <= 0)
      break;
    buf += res;
    len -= res;
  }
  printf("iwrite1:%d\n", n_byte_written);
  return n_byte_written;
}


-- 
Markus Hoenicka, PhD
UT Houston Medical School
Dept. of Integrative Biology and Pharmacology
6431 Fannin MSB4.114
Houston, TX 77030
(713) 500-6313, -7477
(713) 500-7444 (fax)
Markus.Hoenicka@uth.tmc.edu
http://ourworld.compuserve.com/homepages/hoenicka_markus/


--
Want to unsubscribe from this list?
Send a message to cygwin-unsubscribe@sourceware.cygnus.com


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]