bug in 1.3.3 2000/NT (probably socket())

Keith Seitz keiths@cygnus.com
Fri Oct 19 14:46:00 GMT 2001


(Moved back onto the list)

On Fri, 19 Oct 2001, Eric Mandel wrote:

> The test case is just an echo server, you just telnet into port 1234
> and type away. The way I see it working (when it works) is that the
> server echos each nl-terminated string. It was just a throw-away test,
> since in the 1.3.3 failure case, it won't even get to recv() -- it
> will die on the select() call. Thus, the code to recv() the socket is
> just there in case something works.

I've been using 1.3.2 for a little while, so I bit the bullet and
installed 1.3.3. As you know, 1.3.2 works.

I've had to tweak the testcase so that it would work as a single-threaded,
non-spawning echo server, and the testcase is below.

Here's my setup:

$ uname -a
CYGWIN-NT-5.0 LINDT 1.3.3(0.46/3/2) 2001-09-12 23:54 i686 unknown
$ gcc -v
Reading specs from /usr/lib/gcc-lib/i686-pc-cygwin/2.95.3-5/specs
gcc version 2.95.3-5 (cygwin special)

I run this, and I can attach any number of telnet sessions to it, and type
away at it without incident.

If this doesn't work on your system, there is another problem. Check your
networking code. If the original example is anything like the real code
your trying to run, well, there ARE bigger problems.

One thing I might suspect, though. The getdtablesize function on my
machine returns 256. I have no idea how many connections cygwin select,
but maybe it cannot handle this many. I dunno.

As for your debugging session. I stepped through this and had no problems:

   GNU gdb 5.0-gnupro-00r1
   Copyright 2000 Free Software Foundation, Inc.
   GDB is free software, covered by the GNU General Public License, and you are
   welcome to change it and/or distribute copies of it under certain conditions.
   Type "show copying" to see the conditions.  This version of GDB is supported
   for customers of Cygnus Solutions.  Type "show warranty" for details.
   This GDB was configured as "i686-pc-cygwin"...
   (gdb) b main
   Breakpoint 1 at 0x40108c: file srvr.c, line 36.
   (gdb) r
   Starting program: /home/keiths/srvr.exe

   Breakpoint 1, main (argc=1, argv=0xa0112b0) at srvr.c:36
   36	{
   (gdb) n
   44	  int get=SZ_BUF-1;
   (gdb)
   45	  int reuse_addr=1;
   (gdb)
   46	  int keep_alive=1;
   (gdb)
   52	  if( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
   (gdb)
   56	  setsockopt(lsock, SOL_SOCKET, SO_KEEPALIVE,
   (gdb)
   58	  memset((char *)&sock_in, 0, sizeof(sock_in));
   (gdb)
   59	  setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR,
   (gdb)
   61	  sock_in.sin_family = AF_INET;
   (gdb)
   62	  sock_in.sin_addr.s_addr = htonl(INADDR_ANY);
   (gdb)
   63	  sock_in.sin_port = htons(PORT);
   (gdb)
   66	  if( bind(lsock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){
   (gdb)
   72	  if( listen(lsock, MAXLISTEN) < 0 ){
   (gdb)
   78	  index = 0;
   (gdb)
   79	  fds[index++] = lsock;
   (gdb)
   80	  width = lsock+1;
   (gdb)
   83	  while( 1 ){
   (gdb)
   85	    FD_ZERO(&readfds);
   (gdb)
   86	    for (i = 0; i < index; i++)
   (gdb)
   88		if (fds[i] != -1)
   (gdb)
   89		  FD_SET(fds[i], &readfds);
   (gdb)
   86	    for (i = 0; i < index; i++)
   (gdb)
   93	    if( select(width, &readfds, NULL, NULL, NULL) > 0 ){
   (gdb)

   Program received signal SIGINT, Interrupt.
   [Switching to thread 972.0x46c]
   0x77ec813b in _libkernel32_a_iname ()
   (gdb)


Here's my version of the testcase:

/* ************************** foo.c ************************************** */

/*
   To compile:
     gcc -g -o foo foo.c (for Sun Solaris add: -lsocket)

   To Run:

     # start server
     window1: ./foo
     (waits for connect and then reads from socket and writes to stdout)

     # connect using telnet client in another window
     window2: telnet localhost 1234
     (type characters and they should echo on the foo server machine)
or
     # can also use hostname ...
     window2: telnet <hostname> 1234
     (type characters and they should echo on the foo server machine)
*/

#include <stdio.h>
#include <fcntl.h>
#include <signal.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <errno.h>

#define SZ_BUF 		1024
#define PORT   		1234
#define MAXLISTEN	100

int main(int argc, char **argv)
{
  char buf[SZ_BUF];
  int fds[1024];
  int got, i, index;
  int lsock;
  int sock;
  int width;
  int slen;
  int get=SZ_BUF-1;
  int reuse_addr=1;
  int keep_alive=1;
  fd_set readfds;
  struct sockaddr_in sock_in;
  struct sockaddr_in sock_in2;

  /* create listening socket */
  if( (lsock = socket(AF_INET, SOCK_STREAM, 0)) < 0 ){
    perror("lsocket");
    exit(1);
  }
  setsockopt(lsock, SOL_SOCKET, SO_KEEPALIVE,
	     (char *)&keep_alive, sizeof(keep_alive));
  memset((char *)&sock_in, 0, sizeof(sock_in));
  setsockopt(lsock, SOL_SOCKET, SO_REUSEADDR,
	     (char *)&reuse_addr, sizeof(reuse_addr));
  sock_in.sin_family = AF_INET;
  sock_in.sin_addr.s_addr = htonl(INADDR_ANY);
  sock_in.sin_port = htons(PORT);

  /* bind to a port */
  if( bind(lsock, (struct sockaddr *)&sock_in, sizeof(sock_in)) < 0 ){
    perror("bind()");
    exit(1);
  }

  /* set for listening */
  if( listen(lsock, MAXLISTEN) < 0 ){
    perror("listen()");
    exit(1);
  }

  /* add listening socket to array to select on */
  index = 0;
  fds[index++] = lsock;
  width = lsock+1;

  /* enter processing loop */
  while( 1 ){
    /* re-initialize select flags */
    FD_ZERO(&readfds);
    for (i = 0; i < index; i++)
      {
	if (fds[i] != -1)
	  FD_SET(fds[i], &readfds);
      }

    /* wait for next request */
    if( select(width, &readfds, NULL, NULL, NULL) > 0 ){

      /* process request */
      if( FD_ISSET(lsock, &readfds) ){
	slen = sizeof(struct sockaddr_in);
	/* accept new connection */
	if( (sock=accept(lsock, (struct sockaddr *)&sock_in2, &slen)) >=0 ){
	  int flags;

	  /* make sure we close on exec (does nothing in this case) */
	  fcntl(sock, F_SETFD, FD_CLOEXEC);

	  /* add to array */
	  fds[index++] = sock;
	  width = (width - 1 > sock ? width : sock + 1);

	  /* set non-blocking */
	  if ((flags = fcntl (sock, F_GETFL, 0)) < 0)
	    {
	      perror ("F_GETFL");
	      exit (1);
	    }
	  if (fcntl (sock, F_SETFL, flags|O_NONBLOCK) < 0)
	    {
	      perror ("F_SETFL");
	      exit (1);
	    }
	}
	else
	  {
	    perror ("accept");
	    exit (1);
	  }
      }
      else
	{
	  /* echo to stdout */
	  for (i = 0; i < index; i++)
	    {
	      if (fds[i] != -1 && FD_ISSET (fds[i], &readfds))
		{
		  do {
		    got = recv (sock, buf, get, 0);
		    if (got > 0)
		      {
			/* echo */
			write(1, buf, got);
		      }
		    else if (got < 0 && errno != EAGAIN)
		      {
			for (i = 0; i < index; i++)
			  {
			    if (fds[i] == sock)
			      {
				close (sock);
				fds[i] = -1;
			      }
			  }
		      }
		  }
		  while(got > 0);
		}
	    }
	}
    }
    /* UNDER CYGWIN 1.3.3, THIS ERROR HAPPENS IMMEDIATELY */
    else{
      perror("select()");
      exit(1);
    }
  }
}

I don't know what else to say, other than "check your cygwin
installation and your code".

Keith




--
Unsubscribe info:      http://cygwin.com/ml/#unsubscribe-simple
Bug reporting:         http://cygwin.com/bugs.html
Documentation:         http://cygwin.com/docs.html
FAQ:                   http://cygwin.com/faq/



More information about the Cygwin mailing list