[unix-pc.general] Nice work on the socket code!!

steveb@shade.UUCP (Steve Barber) (10/11/89)

Congratulations are in order to Bradley Smith and Alex Crain for
their work on the socket code!  Nice work, guys!

However,
(I'll bet you knew there had to be a catch, right?  :-)

In the process of porting a multiplayer game that uses sockets to
run on the 3B1, I discovered what appears to be a lack in the
current (1.2) socket code - specifically the select call.

NOTE: I'm new to sockets and learning as I go, so bear with me
here.  If I'm out of line, I'm sure you'll let me know...  :-)

The symptoms are as follows:  the driver program gets started up in
the background.  It creates a socket, binds it to a filename in /tmp,
then does a listen(s, 5) on it.  The client program (one per player)
then creates a socket, binds it to the filename, and does a connect(2)
call to connect to it.  It hangs about here someplace until an alarm
goes off.

I need to do some more testing, but this is what appears to be the
problem:

The select(2) call that the driver runs is not detecting the connection
requested by the client program, therefore it never calls accept(2).
According to a man page I checked on a BSD system (accept(2), specifically),
select is supposed to set a flag in the read bitmask if there is a
connection pending.  Currently it doesn't look like this functionality
is provided in the 1.2 version of select.

If anyone in the know would like to comment on the validity of my
diagnosis, as well as any possible workarounds, I would appreciate it.
As I said, this is a port from a game that works on a BSD system and
I'm more than 99% sure that this is not a logic error in the game itself.
I know Bradley and Alex are busy, so I'm asking the net to see if anyone
knows the code well enough to help me out.

BTW: I don't mind coding a fix to the socket code, but I'm a little queasy
about messing with the driver code without some idea of what the right
thing to do is!
-- 
--**-Steve Barber----steveb@shade.Ann-Arbor.MI.US----(cmode)-------------------

alex@umbc5.umbc.edu (Alex S. Crain) (10/11/89)

> The select(2) call that the driver runs is not detecting the connection
> requested by the client program, therefore it never calls accept(2).
> According to a man page I checked on a BSD system (accept(2), specifically),
> select is supposed to set a flag in the read bitmask if there is a
> connection pending.  Currently it doesn't look like this functionality
> is provided in the 1.2 version of select.

	This sounds like my mistake. I remember Brad telling me 
that he had fixed this, which means that I'm one version behind
in the distribution. My apologies to those folks who believed me
when I said that I had it together :-).

	Brad: could you please send your latest version of the 
code, or the diffs to what ever I have (my code includes select 
without the read bitmask stuff)

	To those folks waiting for me to mail the code:  I'll
mail it as soon as I get the latest version.

	To those folks with anonymous ftp access: I'll post
when my archive is up to date.

#################################		:alex.
#Disclamer: Anyone who agrees   #    University of Maryland Baltimore County
#with me deserves what they get.#	alex@umbc3.umbc.edu
#################################	

bes@holin.ATT.COM (Bradley Smith) (10/12/89)

In article <1498@shade.UUCP>, steveb@shade.UUCP (Steve Barber) writes:
> The symptoms are as follows:  the driver program gets started up in
> the background.  It creates a socket, binds it to a filename in /tmp,
> then does a listen(s, 5) on it.  The client program (one per player)
> then creates a socket, binds it to the filename, and does a connect(2)
> call to connect to it.  It hangs about here someplace until an alarm
> goes off.
> 
> The select(2) call that the driver runs is not detecting the connection
> requested by the client program, therefore it never calls accept(2).
> According to a man page I checked on a BSD system (accept(2), specifically),
> select is supposed to set a flag in the read bitmask if there is a
> connection pending.  Currently it doesn't look like this functionality
> is provided in the 1.2 version of select.
Here is tcpsend.c and tcpread.c.  Make sure that you have some windows
around via windy -b ksh, then.  Start tcpread in 1 window then go to the
next window, and starting up tcpsend, and in another window start
tcpsend again.  tcpread should see the new connects, if not you
don't have the most recent release of software in which I can mail it.
-- 
Bradley Smith
Telecommunications Solutions Development
AT&T Bell Labs, Holmdel, NJ 
201-949-0090 att!holin!bes or bes@holin.ATT.COM
==============cut here============
: This is a shar archive.  Extract with sh, not csh.
: This archive ends with exit, so do not worry about trailing junk.
echo 'Extracting tcpread.c'
sed 's/^X//' > tcpread.c << '+ END-OF-FILE tcpread.c'
X#include	<stdio.h>
X#include	<sys/types.h>
X#include	<uipc/socket.h>
X#include	<uipc/un.h>
X
Xchar	*PORT;
X#define TESTSIZE 512
X
Xchar sourcebuf[TESTSIZE];
Xchar sinkbuf[TESTSIZE];
X
Xextern int errno;
Xstruct sockaddr_un sinsource;
Xstruct sockaddr_un sinsink;
Xint s, s1, ns[100], nscnt = 0;
X
Xlong t;
Xextern char *ctime();
X
Xlong timeout=0;
X
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	if(argc != 2) {
X		fprintf(stderr,"usage: %s port_name\n", argv[0]);
X		exit(-1);
X	}
X	PORT = argv[1];
X	/* tcploopinit(); */
X	tcpsource();
X	tcpsink();
X}
Xtcpsource()
X{
X	int i, cc;
X	struct hostent *hp;
X	sinsource.sun_family = AF_UNIX;
X	sinsink.sun_family = AF_UNIX;
X
X	for(i = 0; i< TESTSIZE;i++) {
X		sinkbuf[i] = 0;
X		sourcebuf[i] = i;
X	}
X	s1 = socket(AF_UNIX, SOCK_STREAM, 0);
X	if( s1 == -1) {
X		perror("Second socket() failed!");
X		exit(1);
X	}
X	strcpy(sinsource.sun_path,PORT);
X	strcpy(sinsink.sun_path,PORT);
X
X
X	if(bind(s1, &sinsink, sizeof(struct sockaddr_un)) == -1) {
X		perror("Frist bind failed!");
X		exit(1);
X	}
X
X	if(listen(s1, 5) == -1) {
X		perror("Listen failed!\n");
X		exit(1);
X	}
X
X}
Xtcpsink()
X{
X	int i, j;
X	int hismsglen;
X	static int addrlen = 0;
X	int sret, srd, swr, sex;
X	long t;
X	int a2, ret;
X	char xxx[16];
X
X
Xhere:
X
X	do {
X		a2 = 1 << s1;	 /* get first one */
X		for(i=0;i<nscnt;i++) 
X			if(ns[i])
X				a2 |= 1 << ns[i];
X		time(&t);
X		printf("select bitmask = 0x%x @ %s",a2, ctime(&t));
X		t = 3;
X		ret = select(32,&a2,0,0,&timeout);
X		time(&t);
X		printf("select ret=%d, bitmask = 0x%x, - %s", ret, a2,ctime(&t));
X	} while(ret == 0);
X	if( (1 << s1) & a2) {
X		for(j = 0; j<nscnt;j++) {
X			if(!ns[j])
X				break;
X		}
X		if(j == nscnt) {
X			ns[nscnt] = accept(s1, (char *) &sinsink, &addrlen);
X			printf("new connection nscnt = %d\n",nscnt);
X			nscnt++;
X		}else {
X			ns[j] = accept(s1, (char *) &sinsink, &addrlen);
X			printf("new connection j = %d\n",j);
X		}
X	}
X	for(i=0;i<nscnt;i++) {
X	    if( (1 << ns[i]) & a2) {
X		printf("ns[%d]:", i); fflush(stdout);
X		hismsglen = read(ns[i], sinkbuf, TESTSIZE);
X		if(hismsglen > 0) {
X			printf("tcpsink: %d characters where received\n"
X				,hismsglen);
X		}else {
X			sret = errno;
X			perror("Recv failed!");
X			printf("errno = %d\n", sret);
X			close(ns[i]);
X			ns[i] = 0;
X		}
X	   }
X	}
X	printf("hit return\n");
X	gets(xxx);
X	goto here;
Xthere:
X	if(close(s1) == -1)
X		perror("Close on s1 failed!");
X	if(close(ns) == -1)
X		perror("Close on ns failed!");
X	exit(0);
X}
X
+ END-OF-FILE tcpread.c
chmod 'u=rw,g=r,o=r' 'tcpread.c'
echo '	-rw-r--r--   1 bes      HSJ         2378 Oct 11 20:45 tcpread.c        (as sent)'
echo '	\c'
/bin/ls -l tcpread.c
echo 'Extracting tcpsend.c'
sed 's/^X//' > tcpsend.c << '+ END-OF-FILE tcpsend.c'
X#include	<stdio.h>
X#include	<signal.h>
X#include	<sys/types.h>
X#include	<uipc/socket.h>
X#include	<uipc/un.h>
X
Xchar *PORT;
X#define TESTSIZE 512
X
Xchar sourcebuf[TESTSIZE];
Xchar sinkbuf[TESTSIZE];
X
Xextern int errno;
Xstruct sockaddr_un sinsource;
Xstruct sockaddr_un sinsink;
Xint s, s1, ns;
Xint endit();
Xint timeout=2;
X
Xmain(argc,argv)
Xint argc;
Xchar *argv[];
X{
X	if(argc != 2) {
X		fprintf(stderr,"usage: %s port_name\n", argv[0]);
X		exit(-1);
X	}
X	PORT=argv[1];
X	signal(SIGINT, endit);
X	tcpsource();
X}
Xtcpsource()
X{
X	int i, cc;
X	int ret, bitmask;
X	struct hostent *hp;
X	char bb[16];
X
X	sinsource.sun_family = AF_UNIX;
X	sinsink.sun_family = AF_UNIX;
X
X	for(i = 0; i< TESTSIZE;i++) {
X		sinkbuf[i] = 0;
X		sourcebuf[i] = i;
X	}
X	s = socket(AF_UNIX, SOCK_STREAM, 0);
X	if (s == -1) {
X		perror("Frist socket() failed!");
X		exit(1);
X	}
X	strcpy(sinsource.sun_path,PORT);
X	strcpy(sinsink.sun_path,PORT);
X
X
X	if(connect(s, &sinsource, sizeof(struct sockaddr_un)) == -1) {
X		perror("Connect failed on sinsource!");
X		exit(1);
X	}
X
X
X	i=128;
X	printf("hit return\n");
X	gets(bb);
Xhere:
X	bitmask = 1 << s;
X	ret = select(32, 0, &bitmask, 0, &timeout);
X	printf("select = %d, bitmask=%d\n",ret,bitmask);
X	if(ret) {
X		cc = write(s,sourcebuf, i); /* */
X		if(cc > 0) {
X			printf("%d characters sent\n", cc);
X		}else {
X			perror("Send failed!");
X			exit(1);
X		}
X	}
X	goto here;
X	close(s);
X	exit(0);
X}
Xendit()
X{
X	close(s);
X	exit(0);
X}
+ END-OF-FILE tcpsend.c
chmod 'u=rw,g=r,o=r' 'tcpsend.c'
echo '	-rw-r--r--   1 bes      HSJ         1396 Oct 11 20:45 tcpsend.c        (as sent)'
echo '	\c'
/bin/ls -l tcpsend.c
exit 0
-- 
Bradley Smith
Telecommunications Solutions Development
AT&T Bell Labs, Holmdel, NJ 
201-949-0090 att!holin!bes or bes@holin.ATT.COM

bes@holin.ATT.COM (Bradley Smith) (10/14/89)

It looking at ftpable unixpc socket code, I have come to realize
that the version 1.2 is not the same version that I use.  Version
1.2 appears to be lacking some functionality in the select, and
if you comapre the 2 select functions, you see that the code is
different.  One way to tell if you have the right version is
that the file "Version" has a 3 in it not 2.0.

Alex: are you out there?  let me know if I can remail my stuff
to you.

Hope this helps
-- 
Bradley Smith
Telecommunications Solutions Development
AT&T Bell Labs, Holmdel, NJ 
201-949-0090 att!holin!bes or bes@holin.ATT.COM