home *** CD-ROM | disk | FTP | other *** search
/ Education Sampler 1992 [NeXTSTEP] / Education_1992_Sampler.iso / Programming / Source / WAIS / ir / sockets.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-02-02  |  7.6 KB  |  310 lines

  1. /* WIDE AREA INFORMATION SERVER SOFTWARE    
  2.    No guarantees or restrictions.  See the readme file for the full standard 
  3.    disclaimer.  
  4.    5.29.90    Harry Morris, morris@think.com
  5.  
  6.    Added code in fd_accept_client_connection to print source Inet address to
  7.    stderr. 
  8.    - Jonny G Fri Apr 12 1991
  9.  
  10. */
  11.  
  12. #define sockets_c
  13.  
  14. #include "sockets.h"
  15.  
  16. #ifdef NOTCPIP /* we don't have TCPIP */
  17.  
  18. void open_server (port,socket,size) long port; long* socket; long size; {}
  19. void accept_client_connection (socket,file) long socket; FILE** file; {}
  20. void close_client_connection (file) FILE* file; {}
  21. void close_server (socket) long socket; {}
  22. FILE *connect_to_server (host_name,port) char* host_name; long port; 
  23.                                   {return(NULL);}
  24. void close_connection_to_server (file) FILE* file; {}
  25.  
  26. #else /* there is TCPIP */
  27.  
  28. #include <sys/types.h>
  29. #include <netinet/in.h>
  30. #include <errno.h>
  31. #include <string.h>
  32. #include "panic.h"
  33.  
  34. #ifdef ultrix
  35. extern int errno;
  36. #endif
  37.  
  38. #ifdef BSD
  39. extern int errno;
  40. #endif
  41.  
  42. extern char *sys_errlist[];
  43.  
  44.  
  45. /* XXX
  46. still need:
  47.  non-blocking modes
  48.  special send/recieve functions? (there are now some in ui.c)
  49.  asynchronous calls?
  50. */
  51.  
  52. /* define the number of queued connections allowable on each port */
  53. #define QUEUE_SIZE 3
  54.  
  55. /*---------------------------------------------------------------------------*/
  56. /* Server functions                                                          */
  57. /*---------------------------------------------------------------------------*/
  58.  
  59. boolean clr_socket _AP((struct sockaddr_in *address, long portnumber,
  60.             long* sock));
  61.  
  62. static boolean clr_socket(address, portnumber, sock)
  63.      struct sockaddr_in *address;
  64.      long portnumber;
  65.      long *sock;
  66. {
  67.   if (errno == EADDRINUSE) {
  68.     /* Try connecting to it */
  69.     if (connect(*sock, address, sizeof (struct sockaddr_in)) == 0) {
  70.       close(*sock);
  71.       waislog(WLOG_HIGH, WLOG_ERROR,
  72.           "Cannot bind port %d: (Address already in use).\n\
  73. waisserver is already running on this system", portnumber);
  74.       panic("Exiting");
  75.     } else {
  76.       /* Connection failed; probably socket in FIN_WAIT */
  77.       int one = 1;
  78.  
  79.       (void) close(*sock);
  80.       if ((*sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
  81.     panic("Open socket failed in trying to clear the port.");
  82.       /*printf("Error binding port %d: (address already in use).\n\
  83. Attempting to clear stale socket...", portnumber);*/
  84.       if ( setsockopt(*sock, SOL_SOCKET, SO_REUSEADDR, 
  85.               &one, sizeof (one)) < 0) {
  86.     /*printf("Warning: Setsockopt SO_REUSEADDR failed.");*/
  87.       }
  88.       address->sin_family = AF_INET;
  89.       address->sin_addr.s_addr = INADDR_ANY;
  90.       address->sin_port = htons(portnumber);
  91.       if (bind(*sock, address, sizeof(*address)) == 0) {
  92.     /*printf("Successfully cleared stale EADDRINUSE error");*/
  93.       }
  94.     }
  95.   }
  96.   return(true);
  97. }
  98.  
  99.  
  100. void
  101. open_server(port,fd,size)
  102. long port;
  103. long* fd;
  104. long size;
  105. { struct sockaddr_in address;
  106.  
  107.   /* open the fd */
  108.   if ((*fd = socket(AF_INET,SOCK_STREAM,0)) < 0){
  109.     panic("can't get file descriptor for socket: %s", sys_errlist[errno]);
  110.   }
  111.  
  112.   address.sin_family = AF_INET;
  113.   address.sin_addr.s_addr = htonl(INADDR_ANY);
  114.   address.sin_port = htons(port);
  115.   if (bind(*fd,(struct sockaddr*)&address,sizeof(struct sockaddr)) < 0)
  116.     clr_socket(&address, port, fd);
  117.  
  118.   /*  if (setsockopt(*fd,SOL_SOCKET,SO_REUSEADDR,&trueValue,sizeof(char)) != 0)
  119.       { perror("reuse"); waislog("errno = %d\n",errno);panic("can't reuse the socket");}
  120.       */
  121.   if (setsockopt(*fd,SOL_SOCKET,SO_SNDBUF,&size,sizeof(long)) != 0)
  122.     panic("can't set socket size");
  123.   if (setsockopt(*fd,SOL_SOCKET,SO_RCVBUF,&size,sizeof(long)) != 0)
  124.     panic("can't set socket size");
  125.  
  126.   if (listen(*fd,QUEUE_SIZE) < 0)
  127.     panic("can't open server: %s", sys_errlist[errno]);
  128. }
  129.  
  130.  
  131.  
  132. /* This is a lower level function provided for use by the lisp version of
  133.  * this library 
  134.  * XXX should support non-blocking mode
  135.  */
  136.  
  137. #include <arpa/inet.h>
  138.  
  139. void
  140. fd_accept_client_connection(socket,fd)
  141. long socket;
  142. long* fd;
  143. { /* accept an input connection, and open a file on it */
  144.   struct sockaddr_in source;
  145.   int sourcelen;
  146. #ifdef BSD
  147.   struct in_addr {
  148.     union {
  149.       struct { u_char s_b1,s_b2,s_b3,s_b4; } S_un_b;
  150.       u_long S_addr;
  151.     } S_un;
  152.   } addr_p;
  153. #endif /* BSD */
  154.  
  155.   sourcelen = sizeof(struct sockaddr_in);
  156.  
  157.   do {
  158.     errno = 0;
  159.     *fd = accept(socket, &source, &sourcelen);
  160.   } while (*fd < 0 && errno == EINTR);
  161.  
  162. #ifdef BSD
  163.   addr_p.S_un.S_addr = source.sin_addr.s_addr;
  164. #endif /* BSD */
  165.   
  166.   if(source.sin_family == AF_INET) {
  167. #ifdef NOINETNTOA
  168.     waislog(WLOG_MEDIUM, WLOG_CONNECT,
  169.         "Accepted connection from: %d.%d.%d.%d",
  170. #ifdef BSD
  171.          addr_p.S_un.S_un_b.s_b1,
  172.          addr_p.S_un.S_un_b.s_b2,
  173.          addr_p.S_un.S_un_b.s_b3,
  174.          addr_p.S_un.S_un_b.s_b4
  175. #else
  176.         source.sin_addr.S_un.S_un_b.s_b1,
  177.         source.sin_addr.S_un.S_un_b.s_b2,
  178.         source.sin_addr.S_un.S_un_b.s_b3,
  179.         source.sin_addr.S_un.S_un_b.s_b4
  180. #endif /* BSD */
  181.         );
  182. #else
  183.     waislog(WLOG_MEDIUM, WLOG_CONNECT,
  184.         "Accepted connection from: %s",
  185.         inet_ntoa(source.sin_addr));
  186. #endif /* NOINETNTOA */
  187.   }
  188.   if (*fd < 0)
  189.     panic("can't accept connection");
  190. }
  191.  
  192.  
  193. /* This is the prefered C function for accepting client requests */
  194. void
  195. accept_client_connection(socket,file)
  196. long socket;
  197. FILE** file;
  198. { long fd; /* file descriptor actually used */
  199.   fd_accept_client_connection(socket,&fd);
  200.   if ((*file = fdopen(fd,"r+")) == NULL)
  201.     panic("can't accept connection");
  202. }
  203.  
  204. /* When a server wants to end the session with a client */
  205. void
  206. close_client_connection(file)
  207. FILE* file;
  208.   fclose(file);
  209. }
  210.  
  211. /* when exiting the top level server process (not the forked
  212.    server processes that come one per client).
  213.    Maybe we need to do this once per client as well.
  214. */
  215. void
  216. close_server(socket)
  217. long socket;
  218. {
  219.   close(socket);
  220. }
  221.  
  222. /*---------------------------------------------------------------------------*/
  223. /* Client functions                                                          */
  224. /*---------------------------------------------------------------------------*/
  225.  
  226. /* This is a lower level function provided for use by the lisp version of
  227.  * this library 
  228.  * XXX should support non-blocking mode
  229.  */
  230.  
  231. #define HOSTNAME_BUFFER_SIZE 120
  232.  
  233. boolean
  234. fd_connect_to_server(host_name,port,fd)
  235. char* host_name;
  236. long port;
  237. long* fd;
  238. {
  239.   char hostnamebuf[80];
  240.   long rc;
  241.   struct hostent *host;
  242.   /* struct servent *service = NULL; not used */
  243.   struct sockaddr_in name;
  244.  
  245.   memset((char *)&name, 0,sizeof (name));
  246.   name.sin_addr.s_addr = inet_addr(host_name);
  247.   if (name.sin_addr.s_addr != -1) {
  248.     name.sin_family = AF_INET;
  249.     (void) strcpy(hostnamebuf, host_name);
  250.   }
  251.   else {
  252.     host = gethostbyname(host_name);
  253.  
  254.     if(NULL == host){
  255.       return FALSE;
  256.     }
  257.  
  258.     name.sin_family = host->h_addrtype;
  259. #ifdef h_addr
  260.     bcopy(host->h_addr_list[0],
  261.       (caddr_t)&name.sin_addr, host->h_length);
  262. #endif
  263.     (void) strcpy(hostnamebuf, host->h_name);
  264.   }
  265.   host_name = hostnamebuf;
  266.  
  267.   name.sin_port = htons(port);
  268.  
  269.   *fd = socket (AF_INET, SOCK_STREAM, 0);
  270.   rc = connect (*fd, &name, sizeof (name));
  271.   if(-1 == rc){
  272.     perror("Connect to socket did not work");
  273.     return FALSE;
  274.   }
  275.   return TRUE;
  276. }
  277.  
  278. /* This is the prefered C function for initiating client requests */
  279. FILE *
  280. connect_to_server(host_name,port)
  281. char* host_name;
  282. long port;
  283. {
  284.   FILE* file;
  285.   long fd;
  286.   if(fd_connect_to_server(host_name,port,&fd) == FALSE) {
  287.     perror("Connect to socket did not work");
  288.     return NULL;
  289.   }
  290.  
  291.   if ((file = fdopen(fd,"r+")) == NULL) {
  292.     perror("Connect to socket did not work");
  293.     return NULL;
  294.   }
  295.  
  296.   return file;
  297. }
  298.  
  299. void
  300. close_connection_to_server(file)
  301. FILE* file;
  302. {
  303.   fclose(file);
  304. }
  305.  
  306. /*---------------------------------------------------------------------------*/
  307.  
  308. #endif /* there is TCPIP */
  309.