Mail Archives: cygwin/2000/12/06/13:07:19
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
- Raw text -