Re: [EXTERNAL] Re: Spurious / persistent "exception" condition in half-closed sockets

2022-07-11 Thread Corinna Vinschen
On Jul 11 09:52, Corinna Vinschen wrote:
> On Jul  9 23:02, Lavrentiev, Anton (NIH/NLM/NCBI) [C] via Cygwin wrote:
> > > This was fixed in Cygwin 3.3.0, as the announcement of the latter stated:
> > 
> > Thanks!  So maybe it is time to upgrade... after all LOL
> > 
> > > But you can still run a parallel Cygwin installation
> > 
> > I tried that before...  And it did not work out well.  Unless it's a VM,
> > there's a small but real chance that at some point they are to get 
> > intertwined,
> 
> This must have been very long ago.  For a long time, Cygwin's path
> handling and shared memory interaction between Cygwin processes is
> based on the installation path of the Cygwin DLL a process is running
> under.  A Cygwin process running under a Cygwin DLL from path A uses
> different default Windows PATH and different shared memory names than a

make that "different names for all shared objects"

> process running under Cygwin DLL from path B.  Keeping Cygwin
> installations separate just requires never to run processes from
> installation A under Cygwin DLL B.
> 
> 
> > and then ... it's quite a mess (learned that the hard way, unfortunately).
> 
> It really isn't.  Only if you start to mix paths from two parallel
> Cygwin installations inside the same shell session, which should be
> easy to avoid.
> 
> 
> Corinna

-- 
Problem reports:  https://cygwin.com/problems.html
FAQ:  https://cygwin.com/faq/
Documentation:https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple


Re: [EXTERNAL] Re: Spurious / persistent "exception" condition in half-closed sockets

2022-07-11 Thread Corinna Vinschen
On Jul  9 23:02, Lavrentiev, Anton (NIH/NLM/NCBI) [C] via Cygwin wrote:
> > This was fixed in Cygwin 3.3.0, as the announcement of the latter stated:
> 
> Thanks!  So maybe it is time to upgrade... after all LOL
> 
> > But you can still run a parallel Cygwin installation
> 
> I tried that before...  And it did not work out well.  Unless it's a VM,
> there's a small but real chance that at some point they are to get 
> intertwined,

This must have been very long ago.  For a long time, Cygwin's path
handling and shared memory interaction between Cygwin processes is
based on the installation path of the Cygwin DLL a process is running
under.  A Cygwin process running under a Cygwin DLL from path A uses
different default Windows PATH and different shared memory names than a
process running under Cygwin DLL from path B.  Keeping Cygwin
installations separate just requires never to run processes from
installation A under Cygwin DLL B.


> and then ... it's quite a mess (learned that the hard way, unfortunately).

It really isn't.  Only if you start to mix paths from two parallel
Cygwin installations inside the same shell session, which should be
easy to avoid.


Corinna

-- 
Problem reports:  https://cygwin.com/problems.html
FAQ:  https://cygwin.com/faq/
Documentation:https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple


RE: [EXTERNAL] Re: Spurious / persistent "exception" condition in half-closed sockets

2022-07-09 Thread Lavrentiev, Anton (NIH/NLM/NCBI) [C] via Cygwin
> This was fixed in Cygwin 3.3.0, as the announcement of the latter stated:

Thanks!  So maybe it is time to upgrade... after all LOL

> But you can still run a parallel Cygwin installation

I tried that before...  And it did not work out well.  Unless it's a VM,
there's a small but real chance that at some point they are to get intertwined,
and then ... it's quite a mess (learned that the hard way, unfortunately).

Anton Lavrentiev
Contractor NIH/NLM/NCBI


-- 
Problem reports:  https://cygwin.com/problems.html
FAQ:  https://cygwin.com/faq/
Documentation:https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple


Re: Spurious / persistent "exception" condition in half-closed sockets

2022-07-09 Thread Ken Brown

On 7/9/2022 11:37 AM, Lavrentiev, Anton (NIH/NLM/NCBI) [C] via Cygwin wrote:

Hi all,

It took me awhile to figure this one out, but I think I have a good test case to
demonstrate a (rather serious, actually) issue with Cygwin sockets and 
select/poll.

In short, when a reading end of a socket half closes for write (basically, 
signaling the
other end of no more data to expect, resulting in TCP FIN and, subsequently, 
EOF in the other
end's read()), if that end keeps reading the still incoming remaining data, it 
will face with
a lot of "exception" conditions, which are just spurious.


This was fixed in Cygwin 3.3.0, as the announcement of the latter stated:

  https://cygwin.com/pipermail/cygwin-announce/2021-October/010268.html

You stated in a different thread that you have chosen to use an old version of 
Cygwin for your everyday work.  But you can still run a parallel Cygwin 
installation that you keep up to date, so that you can check whether a bug has 
been fixed before reporting it.


Ken

--
Problem reports:  https://cygwin.com/problems.html
FAQ:  https://cygwin.com/faq/
Documentation:https://cygwin.com/docs.html
Unsubscribe info: https://cygwin.com/ml/#unsubscribe-simple


Spurious / persistent "exception" condition in half-closed sockets

2022-07-09 Thread Lavrentiev, Anton (NIH/NLM/NCBI) [C] via Cygwin
Hi all,

It took me awhile to figure this one out, but I think I have a good test case to
demonstrate a (rather serious, actually) issue with Cygwin sockets and 
select/poll.

In short, when a reading end of a socket half closes for write (basically, 
signaling the
other end of no more data to expect, resulting in TCP FIN and, subsequently, 
EOF in the other
end's read()), if that end keeps reading the still incoming remaining data, it 
will face with
a lot of "exception" conditions, which are just spurious.  That will also burn 
CPU instead of
doing a proper wait (so a read() failed with EAGAIN, and then waited for with 
select()
(or poll() -- the same issue) will be attempted again immediately (as the 
socket would be reported
as "ready" with an "exception"), and result in another EAGAIN, etc etc...
Eventually, there will be successful reads squeezed in between, though...

Here's the "client" code ("server" code follows):

$ cat client.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


static void error(const char* what)
{
fflush(stdout);
perror(what);
exit(1);
}


int main(int argc, const char* argv[])
{
struct sockaddr_in sin;
size_t total = 0;
int c = socket(AF_INET, SOCK_STREAM, 0);

if (c == -1)
error("socket");

memset(, 0, sizeof(sin));
sin.sin_family  = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port= htons(atoi(argv[1]));

if (connect(c, (struct sockaddr*) , (socklen_t) sizeof(sin)) != 0)
error("connect");
if (fcntl(c, F_SETFL, fcntl(c, F_GETFL, 0) | O_NONBLOCK) == -1)
error("fcntl");
#ifdef BUG
if (shutdown(c, SHUT_WR) != 0)
error("shutdown");
#endif

for(;;) {
char buf[1000];
ssize_t n = read(c, buf, sizeof(buf));

if (n > 0) {
printf("%zu byte%s received from server\n", n, &"s"[n==1]);
total += n;
continue;
}
if (n == 0) {
printf("Connection closed, %zu byte%s received\n",
   total, &"s"[total==1]);
break;
}
if (errno != EAGAIN  &&  errno != EWOULDBLOCK)
error("read");
fflush(stdout);
perror("read");
for (;;) {
fd_set rfds, efds;
struct timeval tv;
int m;

FD_ZERO();
FD_ZERO();
FD_SET(c, );
FD_SET(c, );
memset(, 0, sizeof(tv));
tv.tv_sec = 2;

printf("Waiting...\n");
m = select(c + 1, , 0/*wfds*/, , );
if (!m)
continue;
if (m < 0)
error("select");
if (FD_ISSET(c, )) {
printf("Exception??\n");
break;
}
if (FD_ISSET(c, )) {
printf("Read-ready!\n");
break;
}
error("select bug");
abort();
}
}
close(c);
printf("Bye-bye\n");
return 0;
}

$ cat server.c
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 
#include 


static void error(const char* what)
{
fflush(stdout);
perror(what);
exit(1);
}


int main(int argc, const char* argv[])
{
struct sockaddr_in sin;
int s = socket(AF_INET, SOCK_STREAM, 0);

if (s == -1)
error("socket");

memset(, 0, sizeof(sin));
sin.sin_family  = AF_INET;
sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
sin.sin_port= htons(atoi(argv[1]));

if (bind(s, (struct sockaddr*) , (socklen_t) sizeof(sin)) != 0)
error("bind");
if (listen(s, 1) != 0)
error("listen");

for(;;) {
size_t total = 0;
socklen_t sinlen = sizeof(sin);
int c = accept(s, (struct sockaddr*) , );
if (c < 0)
error("accept");
printf("Client accepted\n");

for (;;) {
char buf[1000];
size_t len = rand() & 255;
ssize_t n = write(c, buf, len ? len : 1);
if (n <= 0)
error("write");
total += n;
printf("%zu byte%s sent to client\n", n, &"s"[n==1]);
if (rand() & 1)
usleep(100);
if (!(rand() % 11)) {
printf("Closing connection, %zu byte%s sent\n",
   total, &"s"[total==1]);
break;
}
}
close(c);
}
}

$ cc -Wall -o server server.c
$ cc -Wall -o client client.c

Start the server (which just sends random garbage to the client, once it's 
accepted)
in a separate Cygwin terminal:

$ ./server 

Now run the client from another Cygwin terminal:

$ ./client 

You should see the client connecting and receiving (maybe sometimes waiting)
but never having a blank read (EAGAIN) after a successful select() (that was
read-ready).  Try running the client a few times to see