[net.lan] bsd networking primitives

kc@rna.UUCP (Kaare Christian) (07/23/86)

Following the cookbook in ``4.2BSD IPC Primer'' I have managed to make a
machine-macine connection between two programs.  All things considered it
was easier than I expected, just a mornings work.

Anyway I wondered if anyone could tell me  more about the bind call.
For ipc in the Unix domain it seems that both parties need a bind
following socket creation, but when ipc is in the internet domain only
the server needs a bind.  Why??

Ques 2. When you use the internet domain, but client and server are on
the same machine, does your data go though the loop back connection? Is this
the reason for the loop back connection.

Just thought I'd ask.

Kaare Christian
cmcl2!rna!kc

chris@umcp-cs.UUCP (Chris Torek) (08/06/86)

In article <523@rna.UUCP> kc@rna.UUCP (Kaare Christian) writes:
>For ipc in the Unix domain it seems that both parties need a bind
>following socket creation, but when ipc is in the internet domain only
>the server needs a bind.  Why??

Sounds like a bug to me.  It is not true in 4.3BSD beta-plus-upgrades.
(See example programs below.)

>Ques 2. When you use the internet domain, but client and server are on
>the same machine, does your data go though the loop back connection?
>Is this the reason for the loop back connection.

Actually, that depends on the driver.  Some Ethernet boards cannot send
to themselves; so drivers for those will call the loopback driver in
such cases.  Other boards do not have this limitation, but usually the
driver will call the loopback code anyway.

I threw the following code together to see whether the client needed
to bind before connecting.  (It did not.)  Extract the files (the
script makes a fresh directory for them), compile, and run with an
argument as to what socket to create.  Careful: `se' (the server)
removes any file with the same name as that socket.

: Run this shell script with "sh" not "csh"
PATH=/bin:/usr/bin:/usr/ucb:/etc:$PATH
export PATH
all=FALSE
if [ x$1 = x-a ]; then
	all=TRUE
fi
echo Making directory test_AF_UNIX
mkdir test_AF_UNIX
echo Extracting test_AF_UNIX/Makefile
sed 's/^X//' <<'//go.sysin dd *' >test_AF_UNIX/Makefile
DESTDIR=
CFLAGS=	-O

STD=	cl se

all: ${STD}

${STD}: error.o
	${CC} ${CFLAGS} -o $@ $@.c error.o

install:
	@echo "test programs are never installed, silly!"

clean:
	rm -f *.o *.s a.out core *.bak
	rm -f ${STD}

depend:
	for i in ${STD} error; do \
	    ${CC} -M $$i.c | sed -e 's/\.o//' | \
	    awk '{ if ($$1 != prev) { if (rec != "") print rec; \
		rec = $$0; prev = $$1; } \
		else { if (length(rec $$2) > 78) { print rec; rec = $$0; } \
		else rec = rec " " $$2 } } \
		END { print rec }'; done >makedep
	echo '/^# DO NOT DELETE THIS LINE/+2,$$d' >eddep
	echo '$$r makedep' >>eddep
	echo 'w' >>eddep
	cp Makefile Makefile.bak
	ed - Makefile <eddep
	rm eddep makedep
	echo '# DEPENDENCIES MUST END AT END OF FILE' >>Makefile
	echo '# IF YOU PUT STUFF HERE IT WILL GO AWAY' >>Makefile
	echo '# see make depend above' >>Makefile

# DO NOT DELETE THIS LINE -- make depend uses it

cl: cl.c /usr/include/stdio.h /usr/include/sys/types.h
cl: /usr/include/sys/socket.h /usr/include/sys/un.h
se: se.c /usr/include/stdio.h /usr/include/sys/types.h
se: /usr/include/sys/socket.h /usr/include/sys/un.h
error: error.c /usr/include/stdio.h
# DEPENDENCIES MUST END AT END OF FILE
# IF YOU PUT STUFF HERE IT WILL GO AWAY
# see make depend above
//go.sysin dd *
if [ `wc -c < test_AF_UNIX/Makefile` != 1238 ]; then
	made=FALSE
	echo error transmitting test_AF_UNIX/Makefile --
	echo length should be 1238, not `wc -c < test_AF_UNIX/Makefile`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 test_AF_UNIX/Makefile
	echo -n '	'; ls -ld test_AF_UNIX/Makefile
fi
echo Extracting test_AF_UNIX/cl.c
sed 's/^X//' <<'//go.sysin dd *' >test_AF_UNIX/cl.c
X/*
 * client
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define suntosa(x) ((struct sockaddr *) (x))
#define namesize(x) (strlen((x)->sun_path) + sizeof ((x)->sun_family))

struct	sockaddr_un servname;
int	servsock;

extern int errno;

char	*strcpy();

main(argc, argv)
	int argc;
	char **argv;
{
	char buf[20];

	if (argc < 2)
		error(1, 0, "usage: cl <server>");
	if ((servsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
		error(1, errno, "socket");
	servname.sun_family = AF_UNIX;
	(void) strcpy(servname.sun_path, argv[1]);
	if (connect(servsock, suntosa(&servname), namesize(&servname)))
		error(1, errno, "connect");
	if (write(servsock, "hi", 2) != 2)
		error(1, errno, "write");
	if (read(servsock, buf, 5) != 5)
		error(1, errno, "read");
	buf[5] = 0;
	printf("\"hi\" => \"%s\"\n", buf);
	exit(0);
}
//go.sysin dd *
if [ `wc -c < test_AF_UNIX/cl.c` != 855 ]; then
	made=FALSE
	echo error transmitting test_AF_UNIX/cl.c --
	echo length should be 855, not `wc -c < test_AF_UNIX/cl.c`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 test_AF_UNIX/cl.c
	echo -n '	'; ls -ld test_AF_UNIX/cl.c
fi
echo Extracting test_AF_UNIX/error.c
sed 's/^X//' <<'//go.sysin dd *' >test_AF_UNIX/error.c
X/*
 * For other systems... mine comes from my C library.
 */

#ifdef lint

X/*VARARGS3 ARGSUSED*/
error(quit, e, fmt) int quit, e; char *fmt; {;}

#else

#include <stdio.h>

char	*_argv0;	/* set by C start up code before calling main */

error(quit, e, fmt, args)
	int quit;
	register int e;
	char *fmt;
{
	extern char *sys_errlist[];
	extern int sys_nerr;

	if (_argv0)
		(void) fprintf(stderr, "%s: ", _argv0);
	_doprnt(fmt, &args, stderr);
	if (e) {
		if (e < sys_nerr)
			(void) fprintf(stderr, ": %s", sys_errlist[e]);
		else
			(void) fprintf(stderr, ": unknown error code %d", e);
	}
	(void) putc('\n', stderr);
	(void) fflush(stderr);
	if (quit)
		exit(quit);
}

#endif
//go.sysin dd *
if [ `wc -c < test_AF_UNIX/error.c` != 677 ]; then
	made=FALSE
	echo error transmitting test_AF_UNIX/error.c --
	echo length should be 677, not `wc -c < test_AF_UNIX/error.c`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 test_AF_UNIX/error.c
	echo -n '	'; ls -ld test_AF_UNIX/error.c
fi
echo Extracting test_AF_UNIX/se.c
sed 's/^X//' <<'//go.sysin dd *' >test_AF_UNIX/se.c
X/*
 * server
 */

#include <stdio.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/un.h>

#define suntosa(x) ((struct sockaddr *) (x))
#define namesize(x) (strlen((x)->sun_path) + sizeof ((x)->sun_family))

struct	sockaddr_un servname, cliname;
int	servsock, clisock;

extern int errno;

char	*strcpy();

main(argc, argv)
	int argc;
	char **argv;
{
	char buf[20];
	int fromlen;

	if (argc < 2)
		error(1, 0, "usage: se <server>");
	if ((servsock = socket(AF_UNIX, SOCK_STREAM, 0)) < 0)
		error(1, errno, "socket");
	(void) unlink(argv[1]);		/* clear the way */
	servname.sun_family = AF_UNIX;
	(void) strcpy(servname.sun_path, argv[1]);
	if (bind(servsock, suntosa(&servname), namesize(&servname)))
		error(1, errno, "connect");
	if (listen(servsock, 1))
		error(1, errno, "listen");
	fromlen = sizeof (cliname);
	if ((clisock = accept(servsock, suntosa(&cliname), &fromlen)) < 0)
		error(1, errno, "accept");
	if (read(clisock, buf, 2) != 2)
		error(1, errno, "read");
	if (write(clisock, "there", 5) != 5)
		error(1, errno, "write");
	exit(0);
}
//go.sysin dd *
if [ `wc -c < test_AF_UNIX/se.c` != 1063 ]; then
	made=FALSE
	echo error transmitting test_AF_UNIX/se.c --
	echo length should be 1063, not `wc -c < test_AF_UNIX/se.c`
else
	made=TRUE
fi
if [ $made = TRUE ]; then
	chmod 644 test_AF_UNIX/se.c
	echo -n '	'; ls -ld test_AF_UNIX/se.c
fi
made=TRUE
if [ $made = TRUE ]; then
	chmod 755 test_AF_UNIX
	echo -n '	'; ls -ld test_AF_UNIX
fi
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 1516)
UUCP:	seismo!umcp-cs!chris
CSNet:	chris@umcp-cs		ARPA:	chris@mimsy.umd.edu