comm_basics.c

Go to the documentation of this file.
00001 
00011 /* $Id: comm_basics.c,v 1.48 2008/12/10 19:00:41 seymour Exp $ */
00012 /* $UTK_Copyright: $ */
00013 #ifdef HAVE_CONFIG_H
00014 #include "config.h"
00015 #include "gridsolve-config.h"
00016 #endif
00017 
00018 #include <signal.h>
00019 #include <errno.h>
00020 #include <string.h>
00021 #ifdef HAVE_STROPTS_H
00022 #include <stropts.h>
00023 #endif
00024 #include <sys/types.h>
00025 
00026 #if defined (solaris)
00027 #include <sys/filio.h>
00028 #endif
00029 
00030 #include "portability.h"
00031 #include "proxylib.h"
00032 #include "comm_basics.h"
00033 #include "utility.h"
00034 
00045 ssize_t
00046 gs_twrite(SOCKET fildes, const void *buf, size_t nbyte)
00047 {
00048   static int sig = 1;
00049   if (sig) {
00050     (void) gs_signal(GS_SIGPIPE, SIG_IGN);
00051     sig = 0;
00052   }
00053   return gs_writen(fildes, buf, nbyte);
00054 }
00055 
00056 
00070 ssize_t
00071 gs_writen(SOCKET fd, const void *vptr, size_t n)
00072 {
00073   size_t          nleft;
00074   ssize_t         nwritten;
00075   const char      *ptr;
00076 
00077   ptr = vptr;
00078   DBGPRINTF("ns_writen: write %d bytes to socket %d num %d char %c\n", 
00079      n, fd, *((int *)ptr), (char)*ptr);
00080   nleft = n;
00081   while (nleft > 0) {
00082     if ( (nwritten = write_socket(fd, ptr, nleft)) == SOCKET_ERROR) {
00083       if (errno_socket() == EINTR)
00084         nwritten = 0;           /* and call write() agai n */
00085       else
00086         return(-1);             /* error */
00087     }
00088 
00089     nleft -= nwritten;
00090     ptr   += nwritten;
00091   }
00092   return(n);
00093 }
00094 
00105 int 
00106 gs_tread(SOCKET d, char *b, int n)
00107 {
00108   static int sig = 1;
00109   int retval = -1;
00110 
00111   if (sig) {
00112     (void) gs_signal(GS_SIGPIPE, SIG_IGN);
00113     sig = 0;
00114   }
00115   
00116   retval = proxy_tread(d, b, n, PROXY_TIMEOUT_DEFAULT);
00117 
00118   return retval;
00119 }
00120 
00131 ssize_t
00132 gs_readline(int fd, void *vptr, size_t maxlen)
00133 {
00134   int n, rc;
00135   char c, *ptr;
00136 
00137   ptr = vptr;
00138   for (n = 1; n < (int)maxlen; n++) {
00139     if ((rc = proxy_tread(fd, &c, 1, PROXY_TIMEOUT_DEFAULT)) == 1) {
00140       *ptr++ = c;
00141       if (c == '\n')
00142         break;                  /* newline is stored, like fgets() */
00143     } else if (rc == 0) {
00144       if (n == 1)
00145         return (0);             /* EOF, no data read */
00146       else
00147         break;                  /* EOF, some data was read */
00148     } else
00149       return (-1);              /* error, errno set by read() */
00150   }
00151 
00152   *ptr = 0;                     /* null terminate like fgets() */
00153   return (n);
00154 }
00155 
00169 SOCKET 
00170 gs_establish_socket(in_port_t * port, int reuse)
00171 {
00172   SOCKET desc;
00173   struct sockaddr_in addr;
00174   socklen_t addr_length;
00175   int option_value = 1;
00176 
00177   if ((desc = proxy_socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
00178     return INVALID_SOCKET;
00179   }
00180 
00181   /* TODO */
00182   if (reuse) {
00183     if (setsockopt(desc, SOL_SOCKET, SO_REUSEADDR,
00184            (char *) (&option_value), sizeof(int)) == -1) {
00185       return INVALID_SOCKET;
00186     }
00187   }
00188 
00189   if(setsockopt(desc, IPPROTO_TCP, TCP_NODELAY, (char *) &option_value, 
00190        sizeof(int)) < 0)
00191     DBGPRINTF("Warning: failed to set TCP_NODELAY for fd %d\n", desc);
00192 
00193   memset((char *) &addr, 0x0, sizeof(addr));
00194   addr.sin_family = AF_INET;
00195   addr.sin_addr.s_addr = htonl(INADDR_ANY);
00196   addr.sin_port = htons(*port);
00197 
00198   if (proxy_bind(desc, (struct sockaddr *) &addr, sizeof(addr))) {
00199     if (errno_socket() == EADDRINUSE) {
00200       proxy_close(desc);
00201       return -2;
00202     }
00203     proxy_close(desc);
00204     return INVALID_SOCKET;
00205   }
00206 
00207   addr_length = sizeof(addr);
00208   if((proxy_getsockname(desc, (struct sockaddr *) &addr, &addr_length)) == -1) {
00209     proxy_close(desc);
00210     return INVALID_SOCKET;
00211   }
00212   *port = ntohs(addr.sin_port);
00213 
00214   return (desc);
00215 }
00216 
00227 SOCKET 
00228 gs_bind_to_first_available_port(in_port_t initport, in_port_t * found_port)
00229 {
00230   in_port_t port;
00231   in_port_t tryport;
00232   SOCKET sock;
00233 
00234   port = initport;
00235   tryport = port;
00236 
00237   /* 
00238    * It's important that we don't reuse the addresses here, as we will 
00239    * just attempt the next port if the current one fails - no problem...  
00240    * This call is typically used where the exact port doesn't matter much, 
00241    * but where we have multiple processes on the local host concurrently 
00242    * trying this call with the same starting port number. The proxy does 
00243    * this, and setting reuse=1 in the gs_establish_socket() call will spawn 
00244    * an unholy number of proxy processes. 
00245    */
00246 
00247   while ((sock = gs_establish_socket(&tryport, 0)) == -2) {
00248     port++;
00249     tryport = port;
00250     if (port > initport + GS_NUM_PORTS_TO_TRY) {
00251       ERRPRINTF("Impossible to bind to a port\n");
00252       return INVALID_SOCKET;
00253     }
00254   }
00255 
00256   if (proxy_is_socket_error(sock))
00257     return INVALID_SOCKET;
00258 
00259   *found_port = tryport;
00260 
00261   if (*found_port == 0) {
00262     *found_port = initport;
00263   }
00264 
00265   return sock;
00266 }
00267 
00276 int 
00277 gs_listen_on_socket(SOCKET sock)
00278 {
00279   return proxy_listen(sock, PROXY_MAX_CONNECTIONS);
00280 }
00281 
00291 int 
00292 gs_accept_connection(SOCKET listening_socket)
00293 {
00294   struct sockaddr_in addr;  /* INET socket address */
00295   socklen_t addrlen;        /* address length */
00296   int sock;
00297 
00298   addrlen = sizeof(addr);
00299   sock = proxy_accept(listening_socket, (struct sockaddr *) &addr, &addrlen);
00300   while (sock == INVALID_SOCKET && errno_socket() == EINTR) {
00301     sock = proxy_accept(listening_socket, (struct sockaddr *) &addr, &addrlen);
00302   }
00303   return sock;
00304 }
00305 
00314 int 
00315 gs_close_socket(SOCKET sock)
00316 {
00317   return proxy_close(sock);
00318 }
00319 
00334 SOCKET 
00335 gs_connect_to_host(char *ID, ipaddr_t ipaddr, int port, 
00336       ipaddr_t proxyIP, int proxyPort)
00337 {
00338   PROXY_COMPONENTADDR servaddr;
00339   char dottedip[20];
00340   char dottedproxy[20];
00341   SOCKET sockfd, option_value = 1;
00342 
00343   memcpy(servaddr.ID, ID, CID_LEN);
00344 
00345   servaddr.IP = ipaddr;
00346   servaddr.port = htons(port);
00347   servaddr.proxyIP = proxyIP;
00348   servaddr.proxyPort = htons(proxyPort);
00349 
00350   sockfd = proxy_socket(AF_INET, SOCK_STREAM, 0);
00351 
00352   if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &option_value, 
00353        sizeof(int)) < 0)
00354     DBGPRINTF("Warning: failed to set TCP_NODELAY for fd %d\n", sockfd);
00355 
00356   proxy_ip_to_str(servaddr.IP, dottedip);
00357   proxy_ip_to_str(servaddr.proxyIP, dottedproxy);
00358   DBGPRINTF("Connecting to %s:%d (proxy %s:%d)\n", dottedip, 
00359     ntohs(servaddr.port), dottedproxy, ntohs(servaddr.proxyPort));
00360 
00361   if (proxy_connect(sockfd, &servaddr) < 0) {
00362     ERRPRINTF("Could not connect to %s:%d (proxy %s:%d)\n", dottedip, 
00363       ntohs(servaddr.port), dottedproxy, ntohs(servaddr.proxyPort));
00364     proxy_close(sockfd);
00365     return INVALID_SOCKET;
00366   }
00367 
00368   return sockfd;
00369 }
00370 
00380 SOCKET 
00381 gs_connect_direct(char *host, int port)
00382 {
00383   char agent_cid[CID_LEN];
00384   struct hostent *hp;
00385   ipaddr_t ipaddr;
00386   
00387   DBGPRINTF("Connecting to host %s port %d\n", host, port);
00388 
00389   if ((hp = gethostbyname(host)) == NULL) {
00390     errno = errno_socket();
00391     ERRPRINTF("Could not gethostbyname for %s (errno %d) \n", host, errno);
00392     perror("gethostbyname()");
00393     return INVALID_SOCKET;
00394   }
00395 
00396   memcpy((void *) &ipaddr, hp->h_addr_list[0], sizeof(ipaddr));
00397   
00398   /* all ones will match any component ID */
00399   memset(agent_cid, 0xFF, CID_LEN);
00400 
00401   return gs_connect_to_host(agent_cid, ipaddr, port, 0, 0);
00402 }