home *** CD-ROM | disk | FTP | other *** search
/ Photo CD Demo 1 / Demo.bin / cellsim / v2_5 / cm2 / sck_rtns.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-02-26  |  10.6 KB  |  394 lines

  1. /*
  2.  * File: sock_rtns.c
  3.  *   By: Dave Hiebeler
  4.  *       April 1988
  5.  *       modified August 1989, to fix non-blocking reads
  6.  *
  7.  * Various socket routines.
  8.  *
  9.  */
  10.  
  11. /*
  12.  *
  13.  * Cellsim copyright 1989, 1990 by Chris Langton and Dave Hiebeler
  14.  * (cgl@lanl.gov, hiebeler@heretic.lanl.gov)
  15.  *
  16.  * This package may be freely distributed, as long as you don't:
  17.  * - remove this notice
  18.  * - try to make money by doing so
  19.  * - prevent others from copying it freely
  20.  * - distribute modified versions without clearly documenting your changes
  21.  *   and notifying us
  22.  *
  23.  * Please contact either of the authors listed above if you have questions
  24.  * or feel an exception to any of the above restrictions is in order.
  25.  *
  26.  * If you make changes to the code, or have suggestions for changes,
  27.  * let us know!  If we use your suggestion, you will receive full credit
  28.  * of course.
  29.  */
  30.  
  31. /*****
  32.  * Cellsim history:
  33.  *
  34.  * Cellsim was originally written on Apollo workstations by Chris Langton.
  35.  *
  36.  * Sun versions:
  37.  *
  38.  * - version 1.0
  39.  *   by C. Ferenbaugh and C. Langton
  40.  *   released 09/02/88
  41.  *
  42.  * - version 1.5
  43.  *   by Dave Hiebeler and C. Langton  May - June 1989
  44.  *   released 07/03/89
  45.  *
  46.  * - version 2.0
  47.  *   by Dave Hiebeler and C. Langton  July - August 1989
  48.  *   never officially released (unofficially released 09/08/89)
  49.  *
  50.  * - version 2.5
  51.  *   by Dave Hiebeler and C. Langton  September '89 - February 1990
  52.  *   released 02/26/90
  53.  *****/
  54.  
  55.  
  56.  
  57. /*
  58.  *
  59.  *
  60.  * Parameters used in all routines:
  61.  * debug: 
  62.  *  If debug has a non-zero value, then the routines will be quite verbose
  63.  * about any errors they may be having, or any work they are doing.  For
  64.  * example, if you try to read 5000 bytes from a socket, and it gets
  65.  * the data in 3 pieces, then if the debug-parm is non-zero, you will
  66.  * see a message each time a piece comes in.  If debug is zero, you won't
  67.  * get such information.
  68.  *  All of this information printed with debug set goes to stderr.
  69.  *
  70.  * mode:
  71.  *  Whether to do blocking or non-blocking I/O
  72.  * If you pass ON as this parameter, then non-blocking I/O will be used,
  73.  * and you won't be guaranteed that all of your data arrived.
  74.  * If you give OFF as this parm, blocking I/O will be used, and if you
  75.  * tell it to read N bytes, it will keep trying to read until all N bytes
  76.  * have come in.
  77.  *
  78.  *
  79.  * In all of the procedures, if anything goes wrong, a value of -1 is
  80.  * returned.
  81.  */
  82.  
  83. #include <stdio.h>      /* for fprintf, NULL, etc, etc */
  84. #include <errno.h>      /* for errno, and error names */
  85. #include <strings.h>    /* for strcpy, strcmp */
  86. #include <signal.h>     /* for signal */
  87. #include <sys/file.h>   /* for open, close */
  88. #include <sys/ioctl.h>  /* for ioctl */
  89. #include <sys/time.h>   /* for the timeout structure */
  90. #include <sys/types.h>  /* for accept, socket, listen */
  91. #include <sys/socket.h> /* for accept, socket, listen */
  92. #include <netinet/in.h> /* for sockaddr_in structure */
  93. #include <netdb.h>      /* for hostent structure */
  94.  
  95.  
  96. #define ON      1
  97. #define OFF     0
  98.  
  99.  
  100.  
  101. static int on=1, off=0;
  102.  
  103. /* Write data to an established socket */
  104. int
  105. write_to_sock(s,buf,bytes,mode,debug)
  106. int s;      /* file-descriptor of socket */
  107. char *buf;    /* pointer to buffer to write */
  108. int bytes;    /* how many bytes to write */
  109. int mode;    /* blocking/non-blocking */
  110. int debug;    /* whether to be verbose or not */
  111. {
  112. int bytes_to_write=bytes;  /* countdown of how many bytes left to send */
  113. int ret_val;             /* how many were sent for the last write() */
  114. int count=0;           /* return to caller how many bytes were sent */
  115.  
  116.  
  117.     if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
  118.         fprintf(stderr,"write_to_sock: Error -- could not set mode %d on socket %d\n",
  119.             mode,s);
  120.         perror("sock_rtns");
  121.         return(-1);
  122.     }
  123.     while (bytes_to_write) {
  124.         while ((ret_val = write(s,buf,bytes_to_write))==-1)
  125.             if (mode == ON)
  126.             return (-1);
  127.         if (debug) fprintf(stderr,"...%d bytes written...\n",ret_val);
  128.         bytes_to_write -= ret_val;
  129.         buf += ret_val;
  130.         count += ret_val;
  131.         if (mode == ON)
  132.             return count;
  133.     }
  134.     return(count);
  135. }
  136.  
  137. /*----------------------------------------*/
  138.  
  139. /* read data from an established socket */
  140. int
  141. read_from_sock(s,buf,bytes,mode,debug)
  142. int s;      /* file-descriptor of socket */
  143. char *buf;    /* buffer to read into */
  144. int bytes;    /* how many bytes to read */
  145. int mode;    /* blocking/non-blocking */
  146. int debug;    /* whether to be verbose or not */
  147. {
  148.     int bytes_to_read=bytes;  /* countdown of bytes left to read */
  149.     int ret_val;  /* how many bytes from each read */
  150.     int count=0;  /* total bytes read, return to caller */
  151.  
  152.     if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
  153.     fprintf(stderr,"read_from_sock: Error -- could not set mode %d on socket %d\n",mode,s);
  154.     perror("sock_rtns");
  155.     return(-1);
  156.     }
  157.     while (bytes_to_read) {
  158.     if ((ret_val=read(s,buf,bytes_to_read))==-1) {
  159.         /* perror("sock_rtns"); */
  160.         return (-1);
  161.     }
  162.     if (ret_val == 0)
  163.         return 0;
  164.     if (debug) fprintf(stderr,"...%d bytes read...\n",ret_val);
  165.     bytes_to_read -= ret_val;
  166.     buf += ret_val;
  167.     count += ret_val;
  168.     if (mode == ON)
  169.         return (count);
  170.     }
  171.     return(count);
  172. }
  173.  
  174. /*----------------------------------------*/
  175.  
  176.  
  177. /* This returns the file-descriptor of the socket it opens.
  178.    There are 2 ways of using it -- if the value of "port" is 0, then
  179.    the routine will keep trying random ports until it finds one that
  180.    is free.  If port is non-zero, then the routine will try to open
  181.    that port, and if it fails, will immediately return.
  182.     If a socket is opened, in either method, the port that was actually
  183.    opened will be in the "port" parameter upon returning to the caller,
  184.    and the address will be returned in "addrs" as well.
  185. */
  186. int
  187. open_host_socket(addrs,port,debug)
  188. int *addrs;
  189. u_short *port;
  190. int debug;
  191. {
  192. int s;  /* socket file-descriptor */
  193. struct sockaddr_in my_addrs_rec;
  194. struct sockaddr_in other_addrs_rec;
  195. register struct hostent *host = 0;
  196. char myhostname[64];
  197.  
  198.     s = socket(AF_INET, SOCK_STREAM, 0);
  199.     bzero((char *)&my_addrs_rec, sizeof(struct sockaddr_in));
  200.     if (!*port)    /* try random ports */
  201.       while(1) {
  202.         my_addrs_rec.sin_port = 1025+(random()%4096);
  203.         if (bind(s,&my_addrs_rec,sizeof(struct sockaddr_in))!=-1) break;
  204.       }
  205.     else {     /* try a specified port */
  206.       my_addrs_rec.sin_port = *port;
  207.       if (bind(s,&my_addrs_rec,sizeof(struct sockaddr_in))==-1) return(-1);
  208.     }
  209.     bzero((char *)&other_addrs_rec,sizeof(struct sockaddr_in));
  210.     other_addrs_rec.sin_family = AF_INET;
  211.     other_addrs_rec.sin_addr.s_addr = inet_addr("0.0.0.0");
  212.     other_addrs_rec.sin_port = htons(0);
  213.     if (listen(s,5)==-1) {
  214.         if (debug) fprintf(stderr,"Error with listen()\n");
  215.         return(-1);
  216.     }
  217.     gethostname(myhostname,sizeof(myhostname));
  218.     host = gethostbyname(myhostname);
  219.     if (host) {
  220.         int hostaddr;
  221.         bcopy(host->h_addr,&hostaddr,sizeof(hostaddr));
  222.         *addrs = hostaddr;
  223.         *port = my_addrs_rec.sin_port;
  224.     }
  225.     else {
  226.         if (debug) fprintf(stderr,"Error -- host is 0\n");
  227.         return(-1);
  228.     }
  229.     return(s);
  230. }
  231.  
  232. /*----------------------------------------*/
  233.  
  234. /* Get my host number, and return it */
  235. int
  236. get_my_host_number()
  237. {
  238. int host_addr;
  239. char myhostname[64];
  240. register struct hostent *host;
  241.  
  242.     gethostname(myhostname,sizeof(myhostname));
  243.     host = gethostbyname(myhostname);
  244.     bcopy(host->h_addr,&host_addr,sizeof(int));
  245.     return(host_addr);
  246. }
  247.  
  248. /*----------------------------------------*/
  249. /* Sit and wait until someone calls up the socket s, if mode is blocking.
  250.  * Otherwise, see if someone is waiting, and if so accept them, and if
  251.  * not, return -1
  252.  */
  253. int
  254. wait_to_accept_socket(s,addr,addrlen,mode,debug)
  255. int s;  /* socket fildes */
  256. struct sockaddr *addr;
  257. int *addrlen;
  258. int mode;
  259. int debug;
  260. {
  261. int ns;
  262.  
  263.     if (ioctl(s, FIONBIO, (mode)?&on:&off)==-1) {
  264.         fprintf(stderr,"wait_to_accept_socket: Error -- could not set mode %d on socket %d\n",mode,s);
  265.         perror("sock_rtns");
  266.         return(-1);
  267.     }
  268.     if ((ns=accept(s,addr,addrlen))==-1)  
  269.         if (debug)
  270.             fprintf(stderr,"Errno in accept() is %d\n",errno);
  271.     if (debug) printf("The file-descriptor for new socket is %d\n",ns);
  272.     return(ns);
  273. }
  274. /*----------------------------------------*/
  275.  
  276. /* Call up a waiting socket.  The address and port of the socket
  277.    to call are in the parameters addrs and port.
  278. */
  279.  
  280. int
  281. connect_to_waiting_socket(addrs,port,debug)
  282. int addrs;
  283. u_short port;
  284. int debug;
  285. {
  286. struct sockaddr_in sock;
  287. int fd;
  288.  
  289.     if ((!addrs)||(!port)) return(-1);
  290.     fd = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
  291.     if (fd == -1) {
  292.         if (debug) fprintf(stderr,"socket returned -1\n");
  293.         return(-1);
  294.     }
  295.     sock.sin_family = AF_INET;
  296.     bcopy(&addrs, (caddr_t)&sock.sin_addr,sizeof(addrs));
  297.     sock.sin_port = port;
  298.     if (connect(fd,(struct sockaddr *)&sock, sizeof(sock))==-1) {
  299.         if (debug) fprintf(stderr,"Error with connect()\n");
  300.         return(-1);
  301.     }
  302.     return(fd);
  303. }
  304.  
  305. /*----------------------------------------*/
  306.  
  307. /* Write the addrs and port to the file whose name is in fname.
  308.    This is in case you want to have another program call this one
  309.    by looking up its address in the file.  Battlefield, by Sandro
  310.    Wallach and Ron Frederick, for example, uses this method of
  311.    letting the clients know what address/port the host is running on.
  312.    This method requires that other programs using this must have access
  313.    to the same filesystem.
  314. */
  315. int
  316. write_to_file(fname,addrs,port,debug)
  317. char *fname;
  318. unsigned long addrs;
  319. u_short port;
  320. int debug;
  321. {
  322. FILE *outfile;
  323.  
  324.     if ((outfile=fopen(fname,"w"))==NULL) {
  325.         if (debug) fprintf(stderr,"Couldn't open file %s\n",fname);
  326.         return(-1);
  327.     }
  328.     fprintf(outfile,"%08x%06hd",htonl(addrs),htons(port));
  329.     if (debug) printf("addrs = %08x, port = %06hd\n",
  330.               htonl(addrs),htons(port));
  331.     fclose(outfile);
  332.     return(0);
  333. }
  334.  
  335. /*----------------------------------------*/
  336. /* Pull out the address & port of an attached client.
  337.    (this data is hidden away inside the "struct sockaddr"
  338.    that you pass to accept() ).
  339. */
  340. int
  341. see_who_client_is(other_addrs,o_addrs,o_port,debug)
  342. struct sockaddr *other_addrs;
  343. int *o_addrs;
  344. u_short *o_port;
  345. int debug;
  346. {
  347. int *ptr;
  348.  
  349.     ptr = (int *) other_addrs;
  350.     *o_addrs = *(ptr+1);
  351.     *o_port = (*ptr)&0xffff;
  352.     return(0);
  353. }
  354. /*----------------------------------------*/
  355.  
  356. /* Read in the address and port which are stored in the file "fname".
  357. */
  358.  
  359. int
  360. read_from_file(fname,addrs,port,debug)
  361. char *fname;
  362. unsigned long *addrs;
  363. u_short *port;
  364. int debug;
  365. {
  366. FILE *infile;
  367.  
  368.     if ((infile=fopen(fname,"r"))==NULL) {
  369.         if (debug) fprintf(stderr,"Couldn't open file %s\n",fname);
  370.         return(-1);
  371.     }
  372.     fscanf(infile,"%08x%06hd",addrs,port);
  373.     *addrs = ntohl(*addrs);
  374.     *port = ntohs(*port);
  375.     if (debug) printf("addrs = %08x, port = %06hd\n",*addrs,*port);
  376.     return(0);
  377. }
  378.  
  379. /*----------------------------------------*/
  380. /* use this routine to turn on & off non-blocking I/O on a particular
  381.  * file-descriptor.
  382.  */
  383. int
  384. set_mode(fd,mode)
  385. int fd,  /* file-descriptor to affect */
  386.     mode;  /* 1 to turn on non-blocking, 0 to turn off non-blocking */
  387. {
  388.  
  389.     if (ioctl(fd,FIONBIO,(mode)?&on:&off)==-1) {
  390.         fprintf(stderr,"error in FIONBIO\n");
  391.         return(-1);
  392.     }
  393. }
  394.