4.2 UDP/IP, rawIP, and broadcasting working example

henry strickland strick at gatech.CSNET
Sat Jun 29 08:11:58 AEST 1985


It took me far longer than I thought it should to learn how
to use DGRAM(UDP/IP) and RAW(IP) datagram packets under
AF_INET sockets in 4.2BSD.  Recent postings to unix-wizards
indicate that others are having problems, too.

Here are the results of my experimenting, in the form of a
test program that works in several modes illustrating the
various kinds of datagram operation.  You run the program
on two machines, and one sends a sequence of packets to the
other.  It is great for figuring out addressing problems.
It's also a good example to go by (the only example I found online 
was the rwho daemon, which is a terrible thing to try to figure out).
I've tried to point out the pitfalls in the comments and the
help file.  A lot of this information is not to be found
online.

Good luck ...
		strick @ gatech

=========================================================
: to unbundle, "sh" this file -- DO NOT use csh
:  SHAR archive format.  Archive created Fri Jun 28 16:07:36 EDT 1985
echo x - net.help
sed 's/^X//' > net.help <<'+FUNKY+STUFF+'
Xusage:  net cmd port localhost foreignhost [w]
X
Xcmd =   n	UDP
X	N	broadcast UDP
X	r	raw
X	R	broadcast raw
X
Xcmd is followed by a decimal number (e.g. 'n5' ) to specify
Xa number-of-packets-per-burst other than the default 1.
X
XInclude fifth parameter w if this is the writer.  Otherwise
Xthe program will run as the reader.
X
Xgeorgia tech host ids:  look in /etc/hosts to find your own.
X		
Xgat	1013d81		port must be 0 for raw socket.
Xstr	2013d81
Xcir	3013d81		ports are given as ordinary hex numbers.
Xnim	4013d81			(the program DOES swap them for your)
Xgit	5013d81		hostids may be given as 3 letter code (left)
Xnet	   3d81			or as a hex number, but you must give
Xany	      0			it with all 4 bytes reversed (the
X				numbers to the left are what you should
X				type) -- I DON'T swap these for you (lazy).
X
XAt least at georgia tech, address 0 ('any') doesn't work for broadcasts.
XThe IPC primer suggests that it does.  It took me a week to get past
Xthis one.  You must use 3d81 ('net') to broadcast on the ethernet.
XNotice we use type B addresses, with a two byte net and a two byte host.
X
XLocal host must be the name of your current machine, or 'net'.
XForeigh host specifies where the packet will go.
X
XYou must be root to use RAW or BROADCAST sockets, or to use ports
X0 through 1023.  I'm not sure if port 0 means anything.
X
XPorts 8000 to 9000 (hex) are probably good numbers to play with.
X
XThese work at georgia tech:
X
Xcommand to send on stratus:         command to receive on gatech:
X-------------------------------     ---------------------------------
X
X1)  ordinary UDP datagrams (root not required if port>1023)
X
X	net n 3333 str gat w		net n 3333 gat str	(*)
X
X(or, using full (swapped) hex numbers instead of the aliases:
X
X	net n 3333 2013d81 1013d81	net n 3333 1013d81 2013d81
X)
X
X2)  broadcast UDP datagram 
X
X	net N 4444 str net w		net n 5555 net net	(**)
X
X3)  RAW datagrams
X
X	net r 0 str gat w		net r 0 gat str		(*)
X
X4)  RAW broadcasts
X
X	net R 0 str net w		net r 0 net net		(**)
X
XSublte notes:
X	(*)  The last parameter ( foreign host 'str' ) is only used
Xif the 'connected' option is set in net.c
X
X	(**) The last parameter ( i just put 'net') is not used. This
Xparameter must be 'str' if the 'connected' option is set.  But this
Xis kind of stupid, because you could only receive broadcasts from stratus.
XSo don't use connected sockets if you are receiving broadcasts.
X
XMore notes:
X
X	Although I never found it explained in the manuals, appearently
Xwhen you receive a 'raw' packet, you get the 20 bytes of IP header with
Xit.  You don't specify this header when you call 'send' on a raw
Xpacket;  you receive something that is 20 bytes longer than what you
Xsend.  With DGRAM (i.e. UDP) sockets, you get what you send, and no
Xmore.
X
X
+FUNKY+STUFF+
echo '-rw-r--r--  1 strick       2725 Jun 28 16:02 net.help    (as sent)'
chmod u=rw,g=r,o=r net.help
ls -l net.help
echo x - net.c
sed 's/^X//' > net.c <<'+FUNKY+STUFF+'
X/*   net.c -- network datagram tester -- spring 1985
X *
X *  	henry strickland 
X *	uucp: strick at gatech
X *	the clouds project
X * 	school of information and computer science
X *	georgia tech     atlanta ga  30332
X *
X *	compile with:
X *		cc -o net net.c
X *
X *	recommended:   
X *		chown root net;  chmod 4555 net  ( 4 is the set-uid bit )
X *	so you can use broadcast and raw w/o being root all the time
X *		
X *
X *   assume running on vax, not pyramid (byte order matters)
X * 
X *   written with ethernet in mind ... 
X *   
X *   kludgy datagram test program.  Will test sockets of type RAW or
X *   DGRAM (no STREAM).  Will use specific destination or broadcast.
X *
X *   The program may be run as either a reader or a writer.
X *   For a real test, run one as reader and one as writer.
X *   (extra 'w' parameter makes it a writer).  The writer
X *   sends bursts of packets; see comments below.  The
X *   reader recieves the packets and prints them to standard
X *   output. 
X *
X *   See the net.help file for full instructions.
X *
X *   You should be able to change the while(1) loop easily to do what
X *     you want with it.
X *
X *   Does not use any of the network database ... addresses
X *     are hardwired into the end of the program ... change these
X *     to your own addresses (see /etc/hosts)
X *
X *   Runs in the 'connectionless' mode by default -- change the
X *	initialization of 'conn' below to make it connected.
X *	To properly do broadcast reception, it should be
X *	connectionless.
X */
X
X#include <sys/types.h>
X#include <sys/socket.h>
X#include <netinet/in.h>
X
X#include <stdio.h>
X
X/* if these are not static, you MUST zero all 16 bytes! */
Xstruct sockaddr_in sin = { AF_INET };  /* source address */
Xstruct sockaddr_in dst = { AF_INET };  /* dest address */
X
Xextern errno;
X
X
Xint on = 1;
Xint freq, f;
Xint s;
X
Xint cc;
Xint n;
X
X/* options flags */
Xint writer;
Xint raw;
Xint broadcast;
X
Xint conn = 0;   /* initialize to 1 for connected socket, 0 for unconnect */
X
Xchar buffer [50];    /* buffer for messages in & out */
X
X
X
X
Xmain(argc,argv)
Xchar *argv[];
X{
X	setlinebuf(stdout);
X
X	if ( argc<5 || !argv[1][0] ) {
X		system(" cat net.help " );
X	}
X
X
X	if (argc>5) writer = 1;
X	if (argv[1][0]=='N') broadcast = 1;
X	if (argv[1][0]=='r') raw = 1;
X	if (argv[1][0]=='R') raw = broadcast = 1;
X
X	printf("%s %s %s\n", 
X		( writer? "write" : "read" ),
X		( broadcast ? "broadcast" : "" ),
X		( raw ? "raw" : "" )
X	);
X
X/* swap the two bytes in a short */
X#define swap(x) ( (((x)<<8)&0xff00)|(((x)>>8)&0xff))
X
X	printf("port %x   host %x    foreign %x\n",
X		AtoX(argv[2]), AtoX(argv[3]), AtoX(argv[4])
X	);
X
X	if ((s=socket(AF_INET,raw?SOCK_RAW:SOCK_DGRAM,0))<0)
X			bomb("socket");
X
X	if (broadcast)
X		if (setsockopt(s, SOL_SOCKET, SO_BROADCAST, &on, sizeof(on))<0)
X			bomb("sockopt");
X			
X
X	sin.sin_family = AF_INET;
X	sin.sin_addr.s_addr = AtoX( argv[3] );
X	sin.sin_port = swap( AtoX( argv[2] ));
X	if (bind(s, (char*) &sin, sizeof(sin))<0) bomb("bind");
X
X	dst.sin_family = AF_INET;
X	dst.sin_addr.s_addr = AtoX( argv[4] );
X	dst.sin_port = swap( AtoX( argv[2] ));
X	if (conn)
X		if (connect(s, (char*) &dst, sizeof(dst))<0) bomb("connect");
X
X	
X
X	if (argv[1][1]) {  /* if $1 is not single character */
X		freq = atoi ( &argv[1][1] );
X	} else
X		freq = 1;
X
X
X
X
X	/* main loop begins here */
X
X	while (1) {
X	   if (writer) {
X
X
X/*  WRITER
X *
X *  send bursts of freq packets, with incrementing sequence numbers,
X *     sleeping one second (plus a little more if loaded system) between
X *     bursts.  Freq defaults to one, or argv[1] may be of the form
X *     cn, where c is the character specifying raw, broadcast, etc.,
X *     and n is freq as a decimal integer.
X */
X
X
X	     for ( f=0; f<freq; f++ ) {
X		static count;
X		sprintf( &buffer[0], "== %d ==", count++);
X
X		if (conn)
X			cc = send( s, buffer, 12,0  );
X		else
X			cc = sendto( s, buffer, 12, 0, &dst, sizeof(dst) );
X
X		if (cc<0) printf("sendto error %d", errno);
X	     }
X	     sleep(1);
X
X
X	   } else {
X
X
X
X/*  READER
X *
X *  the reader sends all message recieved to standard output.
X */
X		int junk;
X		int i;
X
X		if (conn)
X			cc = recv( s, buffer, 50, 0  );
X		else
X			cc = recvfrom( s, buffer, 50, 0, &dst, &junk );
X
X		for ( i=0; i<cc; i++) 
X			if (buffer[i]<32 || buffer[i]>127)
X				buffer[i]='.';
X
X		buffer[49]=0;
X		printf("%s\n", buffer );
X
X
X
X	   } /* end if */
X
X	} /* end while(1) */
X
X} /* end main */
X
X
X
Xbomb(s)
X	char *s;
X{	perror(s);	exit(-1); }
X
X
X
X#define equal !strcmp
X
X/* convert ascii to hex, plus understand some aliases */
XAtoX(s)
Xchar *s;
X{
X	int a = 0;
X
X	int i;
X
X	if ( equal(s,"gat")) 
X		return 0x1013d81;   /* network order! */
X	if (equal(s,"str"))
X		return 0x2013d81;
X	if (equal(s,"cir"))
X		return 0x3013d81;
X	if (equal(s,"nim"))
X		return 0x4013d81;
X	if (equal(s,"git"))
X		return 0x5013d81;
X	if (equal (s,"net"))
X		return 0x0003d81;
X	if (equal (s,"any"))
X		return 0;
X
X
X	for ( i=0; s[i]; i++ ) {
X		if ( '0' <= s[i] && s[i] <= '9' )
X			a = ( a << 4 ) + s[i] - '0';
X		else if ( 'a' <= s[i] && s[i] <= 'f' )
X			a = ( a << 4 ) + s[i] - 'a' + 10;
X		else if ( 'A' <= s[i] && s[i] <= 'F' )
X			a = ( a << 4 ) + s[i] - 'A' + 10;
X		else
X			{  printf("bad char: %c: bomb!\n", s[i]);
X				exit(-1);
X			}
X	}
X
X	return a;
X}
+FUNKY+STUFF+
echo '-rw-r--r--  1 strick       5074 Jun 28 15:32 net.c    (as sent)'
chmod u=rw,g=r,o=r net.c
ls -l net.c
exit 0
===========================================

-- 
 --  henry strickland  
  --  the clouds project            { akgua allegra hplabs inhp4 }
   --   school of ics / ga tech                         !gatech!strick
    --    atlanta ga 30332



More information about the Comp.unix.wizards mailing list