Mailing-List: contact cygwin-help AT sourceware DOT cygnus DOT com; run by ezmlm List-Subscribe: List-Archive: List-Post: List-Help: , Sender: cygwin-owner AT sources DOT redhat DOT com Delivered-To: mailing list cygwin AT sources DOT redhat DOT com From: "Markus Hoenicka" MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Transfer-Encoding: 7bit Message-ID: <14894.33300.706000.788630@gargle.gargle.HOWL> Date: Wed, 6 Dec 2000 18:14:44 +0000 (CT0) To: cygwin AT sources DOT redhat DOT com Subject: socket read()/write() problem in 1.1.6 X-Mailer: VM 6.75 under Emacs 20.6.1 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 DOT Hoenicka AT uth DOT tmc DOT edu http://ourworld.compuserve.com/homepages/hoenicka_markus/ -- Want to unsubscribe from this list? Send a message to cygwin-unsubscribe AT sourceware DOT cygnus DOT com