home *** CD-ROM | disk | FTP | other *** search
- /*
- * File: sock_rtns.c
- * By: Dave Hiebeler
- * April 1988
- * modified August 1989, to fix non-blocking reads
- *
- * Various socket routines.
- *
- */
-
- /*
- *
- * Cellsim copyright 1989, 1990 by Chris Langton and Dave Hiebeler
- * (cgl@lanl.gov, hiebeler@heretic.lanl.gov)
- *
- * This package may be freely distributed, as long as you don't:
- * - remove this notice
- * - try to make money by doing so
- * - prevent others from copying it freely
- * - distribute modified versions without clearly documenting your changes
- * and notifying us
- *
- * Please contact either of the authors listed above if you have questions
- * or feel an exception to any of the above restrictions is in order.
- *
- * If you make changes to the code, or have suggestions for changes,
- * let us know! If we use your suggestion, you will receive full credit
- * of course.
- */
-
- /*****
- * Cellsim history:
- *
- * Cellsim was originally written on Apollo workstations by Chris Langton.
- *
- * Sun versions:
- *
- * - version 1.0
- * by C. Ferenbaugh and C. Langton
- * released 09/02/88
- *
- * - version 1.5
- * by Dave Hiebeler and C. Langton May - June 1989
- * released 07/03/89
- *
- * - version 2.0
- * by Dave Hiebeler and C. Langton July - August 1989
- * never officially released (unofficially released 09/08/89)
- *
- * - version 2.5
- * by Dave Hiebeler and C. Langton September '89 - February 1990
- * released 02/26/90
- *****/
-
-
-
- /*
- *
- *
- * Parameters used in all routines:
- * debug:
- * If debug has a non-zero value, then the routines will be quite verbose
- * about any errors they may be having, or any work they are doing. For
- * example, if you try to read 5000 bytes from a socket, and it gets
- * the data in 3 pieces, then if the debug-parm is non-zero, you will
- * see a message each time a piece comes in. If debug is zero, you won't
- * get such information.
- * All of this information printed with debug set goes to stderr.
- *
- * mode:
- * Whether to do blocking or non-blocking I/O
- * If you pass ON as this parameter, then non-blocking I/O will be used,
- * and you won't be guaranteed that all of your data arrived.
- * If you give OFF as this parm, blocking I/O will be used, and if you
- * tell it to read N bytes, it will keep trying to read until all N bytes
- * have come in.
- *
- *
- * In all of the procedures, if anything goes wrong, a value of -1 is
- * returned.
- */
-
- #include <stdio.h> /* for fprintf, NULL, etc, etc */
- #include <errno.h> /* for errno, and error names */
- #include <strings.h> /* for strcpy, strcmp */
- #include <signal.h> /* for signal */
- #include <sys/file.h> /* for open, close */
- #include <sys/ioctl.h> /* for ioctl */
- #include <sys/time.h> /* for the timeout structure */
- #include <sys/types.h> /* for accept, socket, listen */
- #include <sys/socket.h> /* for accept, socket, listen */
- #include <netinet/in.h> /* for sockaddr_in structure */
- #include <netdb.h> /* for hostent structure */
-
-
- #define ON 1
- #define OFF 0
-
-
-
- static int on=1, off=0;
-
- /* Write data to an established socket */
- int
- write_to_sock(s,buf,bytes,mode,debug)
- int s; /* file-descriptor of socket */
- char *buf; /* pointer to buffer to write */
- int bytes; /* how many bytes to write */
- int mode; /* blocking/non-blocking */
- int debug; /* whether to be verbose or not */
- {
- int bytes_to_write=bytes; /* countdown of how many bytes left to send */
- int ret_val; /* how many were sent for the last write() */
- int count=0; /* return to caller how many bytes were sent */
-
-
- if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
- fprintf(stderr,"write_to_sock: Error -- could not set mode %d on socket %d\n",
- mode,s);
- perror("sock_rtns");
- return(-1);
- }
- while (bytes_to_write) {
- while ((ret_val = write(s,buf,bytes_to_write))==-1)
- if (mode == ON)
- return (-1);
- if (debug) fprintf(stderr,"...%d bytes written...\n",ret_val);
- bytes_to_write -= ret_val;
- buf += ret_val;
- count += ret_val;
- if (mode == ON)
- return count;
- }
- return(count);
- }
-
- /*----------------------------------------*/
-
- /* read data from an established socket */
- int
- read_from_sock(s,buf,bytes,mode,debug)
- int s; /* file-descriptor of socket */
- char *buf; /* buffer to read into */
- int bytes; /* how many bytes to read */
- int mode; /* blocking/non-blocking */
- int debug; /* whether to be verbose or not */
- {
- int bytes_to_read=bytes; /* countdown of bytes left to read */
- int ret_val; /* how many bytes from each read */
- int count=0; /* total bytes read, return to caller */
-
- if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
- fprintf(stderr,"read_from_sock: Error -- could not set mode %d on socket %d\n",mode,s);
- perror("sock_rtns");
- return(-1);
- }
- while (bytes_to_read) {
- if ((ret_val=read(s,buf,bytes_to_read))==-1) {
- /* perror("sock_rtns"); */
- return (-1);
- }
- if (ret_val == 0)
- return 0;
- if (debug) fprintf(stderr,"...%d bytes read...\n",ret_val);
- bytes_to_read -= ret_val;
- buf += ret_val;
- count += ret_val;
- if (mode == ON)
- return (count);
- }
- return(count);
- }
-
- /*----------------------------------------*/
-
-
- /* This returns the file-descriptor of the socket it opens.
- There are 2 ways of using it -- if the value of "port" is 0, then
- the routine will keep trying random ports until it finds one that
- is free. If port is non-zero, then the routine will try to open
- that port, and if it fails, will immediately return.
- If a socket is opened, in either method, the port that was actually
- opened will be in the "port" parameter upon returning to the caller,
- and the address will be returned in "addrs" as well.
- */
- int
- open_host_socket(addrs,port,debug)
- int *addrs;
- u_short *port;
- int debug;
- {
- int s; /* socket file-descriptor */
- struct sockaddr_in my_addrs_rec;
- struct sockaddr_in other_addrs_rec;
- register struct hostent *host = 0;
- char myhostname[64];
-
- s = socket(AF_INET, SOCK_STREAM, 0);
- bzero((char *)&my_addrs_rec, sizeof(struct sockaddr_in));
- if (!*port) /* try random ports */
- while(1) {
- my_addrs_rec.sin_port = 1025+(random()%4096);
- if (bind(s,&my_addrs_rec,sizeof(struct sockaddr_in))!=-1) break;
- }
- else { /* try a specified port */
- my_addrs_rec.sin_port = *port;
- if (bind(s,&my_addrs_rec,sizeof(struct sockaddr_in))==-1) return(-1);
- }
- bzero((char *)&other_addrs_rec,sizeof(struct sockaddr_in));
- other_addrs_rec.sin_family = AF_INET;
- other_addrs_rec.sin_addr.s_addr = inet_addr("0.0.0.0");
- other_addrs_rec.sin_port = htons(0);
- if (listen(s,5)==-1) {
- if (debug) fprintf(stderr,"Error with listen()\n");
- return(-1);
- }
- gethostname(myhostname,sizeof(myhostname));
- host = gethostbyname(myhostname);
- if (host) {
- int hostaddr;
- bcopy(host->h_addr,&hostaddr,sizeof(hostaddr));
- *addrs = hostaddr;
- *port = my_addrs_rec.sin_port;
- }
- else {
- if (debug) fprintf(stderr,"Error -- host is 0\n");
- return(-1);
- }
- return(s);
- }
-
- /*----------------------------------------*/
-
- /* Get my host number, and return it */
- int
- get_my_host_number()
- {
- int host_addr;
- char myhostname[64];
- register struct hostent *host;
-
- gethostname(myhostname,sizeof(myhostname));
- host = gethostbyname(myhostname);
- bcopy(host->h_addr,&host_addr,sizeof(int));
- return(host_addr);
- }
-
- /*----------------------------------------*/
- /* Sit and wait until someone calls up the socket s, if mode is blocking.
- * Otherwise, see if someone is waiting, and if so accept them, and if
- * not, return -1
- */
- int
- wait_to_accept_socket(s,addr,addrlen,mode,debug)
- int s; /* socket fildes */
- struct sockaddr *addr;
- int *addrlen;
- int mode;
- int debug;
- {
- int ns;
-
- if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
- fprintf(stderr,"wait_to_accept_socket: Error -- could not set mode %d on socket %d\n",mode,s);
- perror("sock_rtns");
- return(-1);
- }
- if ((ns=accept(s,addr,addrlen))==-1)
- if (debug)
- fprintf(stderr,"Errno in accept() is %d\n",errno);
- if (debug) printf("The file-descriptor for new socket is %d\n",ns);
- return(ns);
- }
- /*----------------------------------------*/
-
- /* Call up a waiting socket. The address and port of the socket
- to call are in the parameters addrs and port.
- */
-
- int
- connect_to_waiting_socket(addrs,port,debug)
- int addrs;
- u_short port;
- int debug;
- {
- struct sockaddr_in sock;
- int fd;
-
- if ((!addrs)||(!port)) return(-1);
- fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
- if (fd == -1) {
- if (debug) fprintf(stderr,"socket returned -1\n");
- return(-1);
- }
- sock.sin_family = AF_INET;
- bcopy(&addrs, (caddr_t)&sock.sin_addr,sizeof(addrs));
- sock.sin_port = port;
- if (connect(fd,(struct sockaddr *)&sock, sizeof(sock))==-1) {
- if (debug) fprintf(stderr,"Error with connect()\n");
- return(-1);
- }
- return(fd);
- }
-
- /*----------------------------------------*/
-
- /* Write the addrs and port to the file whose name is in fname.
- This is in case you want to have another program call this one
- by looking up its address in the file. Battlefield, by Sandro
- Wallach and Ron Frederick, for example, uses this method of
- letting the clients know what address/port the host is running on.
- This method requires that other programs using this must have access
- to the same filesystem.
- */
- int
- write_to_file(fname,addrs,port,debug)
- char *fname;
- unsigned long addrs;
- u_short port;
- int debug;
- {
- FILE *outfile;
-
- if ((outfile=fopen(fname,"w"))==NULL) {
- if (debug) fprintf(stderr,"Couldn't open file %s\n",fname);
- return(-1);
- }
- fprintf(outfile,"%08x%06hd",htonl(addrs),htons(port));
- if (debug) printf("addrs = %08x, port = %06hd\n",
- htonl(addrs),htons(port));
- fclose(outfile);
- return(0);
- }
-
- /*----------------------------------------*/
- /* Pull out the address & port of an attached client.
- (this data is hidden away inside the "struct sockaddr"
- that you pass to accept() ).
- */
- int
- see_who_client_is(other_addrs,o_addrs,o_port,debug)
- struct sockaddr *other_addrs;
- int *o_addrs;
- u_short *o_port;
- int debug;
- {
- int *ptr;
-
- ptr = (int *) other_addrs;
- *o_addrs = *(ptr+1);
- *o_port = (*ptr)&0xffff;
- return(0);
- }
- /*----------------------------------------*/
-
- /* Read in the address and port which are stored in the file "fname".
- */
-
- int
- read_from_file(fname,addrs,port,debug)
- char *fname;
- unsigned long *addrs;
- u_short *port;
- int debug;
- {
- FILE *infile;
-
- if ((infile=fopen(fname,"r"))==NULL) {
- if (debug) fprintf(stderr,"Couldn't open file %s\n",fname);
- return(-1);
- }
- fscanf(infile,"%08x%06hd",addrs,port);
- *addrs = ntohl(*addrs);
- *port = ntohs(*port);
- if (debug) printf("addrs = %08x, port = %06hd\n",*addrs,*port);
- return(0);
- }
-
- /*----------------------------------------*/
- /* use this routine to turn on & off non-blocking I/O on a particular
- * file-descriptor.
- */
- int
- set_mode(fd,mode)
- int fd, /* file-descriptor to affect */
- mode; /* 1 to turn on non-blocking, 0 to turn off non-blocking */
- {
-
- if (ioctl(fd,FIONBIO,(mode)?&on:&off)==-1) {
- fprintf(stderr,"error in FIONBIO\n");
- return(-1);
- }
- }
-