proxy_utils.c

Go to the documentation of this file.
00001 
00008 /* $Id: proxy_utils.c,v 1.25 2008/12/16 19:22:25 seymour Exp $ */
00009 /* $UTK_Copyright: $ */
00010 
00011 #define BSD_COMP        /* $#@$! Sloaris needs this.  Stupid twits. */
00012 #include <errno.h>
00013 #include <memory.h>
00014 #include <stdio.h>
00015 #include <stdlib.h>
00016 #include <stddef.h>
00017 #include <string.h>
00018 #include <sys/types.h>
00019 #include <sys/stat.h>
00020 #include <fcntl.h>
00021 
00022 #ifdef HAVE_CONFIG_H
00023 #include "config.h"
00024 #endif /* HAVE_CONFIG_H */
00025 
00026 #include "portability.h"
00027 #include "proxy_utils.h"
00028 
00029 #ifndef INADDR_NONE
00030 #define INADDR_NONE ((unsigned int) 0xffffffff)
00031 #endif
00032 
00043 static const char *
00044 inet_ntoa_replacement(const struct in_addr in)
00045 {
00046   static char buf[16];
00047   const unsigned char *p;
00048 
00049   p = (const unsigned char *) &in.s_addr;
00050   sprintf(buf, "%u.%u.%u.%u",
00051       (unsigned int) (p[0] & 0xff), (unsigned int) (p[1] & 0xff),
00052       (unsigned int) (p[2] & 0xff), (unsigned int) (p[3] & 0xff));
00053   return buf;
00054 }
00055 
00069 ipaddr_t 
00070 proxy_get_my_ipaddr()
00071 {
00072   struct hostent *hp;
00073   ipaddr_t IPaddr;
00074   char buf[1024];
00075   int rv;
00076 
00077   buf[0] = '\0';
00078 
00079   /* First try to get a real IP address */
00080 
00081   rv = proxy_get_host_id(buf, sizeof(buf), SKIP_LOOPBACK, SKIP_PRIVATE);
00082 
00083   if (rv < 0) {
00084 
00085     /* Could not get a real IP, now fall back an accept a private IP */
00086     rv = proxy_get_host_id(buf, sizeof(buf), SKIP_LOOPBACK, INCLUDE_PRIVATE);
00087 
00088     if (rv < 0) {
00089       /* Could not get a real IP or a private IP.  can probably get a loopback IP
00090        * address.  */
00091 
00092       rv = proxy_get_host_id(buf, sizeof(buf), INCLUDE_LOOPBACK, INCLUDE_PRIVATE);
00093 
00094       if (rv < 0) {
00095     fprintf(stderr,"All attempts to determine the IP address failed.\n");
00096     return -1;
00097       }
00098     }
00099   }
00100 
00101   if (strlen(buf) == 0) {
00102     fprintf(stderr,"Strange.. after proxy_get_host_id, buf is empty.\n");
00103     return -1;
00104   }
00105 
00106   if ((hp = gethostbyname(buf)) == NULL) {
00107     perror("gethostbyname()");
00108     return -1;
00109   }
00110   memcpy((void *) &IPaddr, hp->h_addr_list[0], sizeof(IPaddr));
00111   return IPaddr;
00112 }
00113 
00114 
00123 int 
00124 proxy_is_socket_error(SOCKET s)
00125 {
00126   return (s == SOCKET_ERROR);
00127 }
00128 
00137 int
00138 proxy_send_keepalive(SOCKET sock)
00139 {
00140   proxy_tag_t ktag;
00141 
00142   ktag = PROXY_KEEPALIVE;
00143   
00144   if(write_socket(sock, &ktag, sizeof(ktag)) < 0)
00145     return -1;
00146 
00147   if(proxy_tread(sock, (char *)&ktag, sizeof(ktag), 1) < 0) {
00148     printf("Failed to receive ack for keepalive message.\n");
00149     return -1;
00150   }
00151 
00152   return 0;
00153 }
00154 
00164 int 
00165 proxy_is_something_on_socket(SOCKET sock)
00166 {
00167   char buf[1];
00168   int try;
00169   
00170 #ifdef WIN32
00171   u_long off = 0;
00172   u_long on = 1;
00173   ioctlsocket(sock, FIONBIO, &on);
00174   try = recv(sock, buf, 1, MSG_PEEK);
00175   ioctlsocket(sock, FIONBIO, &off);
00176 #else
00177   int off = 0;
00178   int on = 1;
00179   ioctl(sock, FIONBIO, &on);
00180   try = recv(sock, buf, 1, MSG_PEEK);
00181   ioctl(sock, FIONBIO, &off);
00182 #endif              /* UNIX */
00183   
00184   /* mm notes - found bug.  recv() above is failing with a return of
00185    * EWOULDBLOCK because the socket is non-blocking, but this recv
00186    * would block since there is nothing waiting to be read from the
00187    * socket.  This is a polling interface which will never received
00188    * data.  It only checks for endpoint exit. recv() returns 0 if no
00189    * messages are available and the peer has closed the connections.
00190    * recv() returns -1 and sets errno if error.  Upon success, recv()
00191    * returns number of bytes received. */
00192 
00193   errno = errno_socket();
00194   if (proxy_is_socket_error(try) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
00195     return -1;
00196 
00197   if (try == 0)
00198     return 0;
00199 
00200   return 1;
00201 }
00202 
00203 
00217 int 
00218 proxy_get_host_id(char *hostid, int hostidlen, int skip_loopback, 
00219   int skip_private)
00220 {
00221 
00222 #if defined (WIN32) 
00223 
00224  /* TODO AYK this only works for a client so fix it before
00225   * implementing WIN32 servers*/
00226   strncpy(hostid, "localhost", hostidlen);
00227   hostid[hostidlen-1] = 0;
00228   return (strlen(hostid));
00229 
00230 
00231 #elif defined (__INTERIX) 
00232 
00233   SOCKET s = INVALID_SOCKET;
00234   struct sockaddr_in ia;
00235   int slen;
00236   char local_hostid[255];
00237   int status = -1;          /* assume failure */
00238 
00239   /* Connect to port 80 at google */
00240   if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) goto done;
00241   memset(&ia, 0, sizeof(ia));
00242   ia.sin_family = PF_INET;
00243   ia.sin_port = htons(80);
00244   ia.sin_addr.s_addr = inet_addr("216.239.59.99"); /* TODO googles ip */
00245   if (connect(s, (struct sockaddr *)&ia, sizeof(ia)) < 0) goto done;
00246 
00247   /* Get socket name */
00248   memset(&ia, 0, sizeof(ia));
00249   slen = sizeof(ia);
00250   if (getsockname(s, (struct sockaddr *)&ia, &slen) < 0) goto done;
00251   
00252  done:
00253   
00254   if (s != INVALID_SOCKET) {
00255     strcpy(local_hostid, inet_ntoa_replacement(ia.sin_addr));
00256     strncpy(hostid, local_hostid, hostidlen);
00257     status = strlen(local_hostid);
00258     close_socket(s);
00259   }
00260 
00261   return status;
00262   
00263 #else  /* if not win32 or interix */
00264 
00265   int s;
00266   int i;
00267   struct ifconf ifc;
00268   char local_hostid[255];
00269   char inbuf[8192];
00270   int status;
00271   struct in_addr ia;
00272 
00273   status = -1;          /* assume failure */
00274 
00275   if (hostidlen < 0) return status;
00276 
00277   if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
00278     goto done;
00279 
00280   /* try to shut up purify by initializing the buffer */
00281   memset(inbuf, '\0', sizeof(inbuf));
00282 
00283   ifc.ifc_len = sizeof(inbuf);
00284   ifc.ifc_buf = inbuf;
00285   if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
00286     goto done;
00287 
00288   /* scan list of interfaces */
00289   for (i = 0; i < ifc.ifc_len;) {
00290     struct ifreq *ifr = (struct ifreq *) (ifc.ifc_buf + i);
00291     struct sockaddr sa;
00292 #ifdef SIOCGIFFLAGS
00293     struct ifreq ifrf;
00294 #endif
00295 
00296 #ifdef SOCKADDR_HAS_SA_LEN
00297 #define SA_LEN(x) ((x)->ifr_addr.sa_len)
00298 #else
00299 #define SA_LEN(x) (sizeof (struct sockaddr))
00300 #endif
00301 
00302     /* 
00303      * copying the ifr_addr to a separate struct sockaddr buffer
00304      * appears to work around a compiler (or alignment) bug on solaris.
00305      * code generated by gcc worked just fine with sa as a 
00306      * pointer (declared as struct sockaddr *sa) initialized to 
00307      * &(ifr->ifr_addr).   sigh...
00308      */
00309     memcpy((char *)&sa, (char *)ifr + offsetof(struct ifreq, ifr_addr),
00310            sizeof(struct sockaddr));
00311 
00312     /* 
00313      * figure out where the next interface definition starts
00314      */
00315 #ifdef _SIZEOF_ADDR_IFREQ
00316     i += _SIZEOF_ADDR_IFREQ(*ifr);
00317 #else
00318 #ifdef SOCKADDR_HAS_SA_LEN
00319     if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr))
00320       i += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
00321     else
00322       i += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
00323 #else               /* SOCKADDR_HAS_SA_LEN */
00324     i += sizeof(*ifr);
00325 #endif              /* SOCKADDR_HAS_SA_LEN */
00326 #endif              /* _SIZEOF_ADDR_IFREQ */
00327 
00328 #ifdef PROXY_HOSTID_TEST
00329     printf("name %s\n", ifr->ifr_name);
00330     printf(" family %d\n", sa.sa_family);
00331     printf(" len %d\n", SA_LEN(ifr));
00332 #endif              /* PROXY_HOSTID_TEST */
00333 
00334     if (sa.sa_family != AF_INET)
00335       continue;
00336 
00337     /* 
00338      * get interface flags
00339      */
00340 #ifdef SIOCGIFFLAGS
00341     memset(&ifrf, 0, sizeof(struct ifreq));
00342     strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name));
00343     ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
00344 # define IFRFREF ifrf
00345 #else
00346 # define IFRFREF (*ifr)
00347 #endif              /* SIOCGIFFLAGS */
00348 
00349     /* 
00350      * skip non configured and loopback interfaces
00351      */
00352     if ((IFRFREF.ifr_flags & IFF_UP) == 0)
00353       continue;
00354     if (((IFRFREF.ifr_flags & IFF_LOOPBACK) != 0) && (skip_loopback == SKIP_LOOPBACK))
00355       continue;
00356 
00357     /* 
00358      * extract IP address from the list
00359      */
00360     ia = (((struct sockaddr_in *) &sa)->sin_addr);
00361     if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE)
00362       continue;
00363 
00364     if (skip_private == SKIP_PRIVATE) {
00365       const unsigned char *p = (const unsigned char *) &ia.s_addr;
00366       unsigned int b1 = (unsigned int) (p[0] & 0xff);
00367       unsigned int b2 = (unsigned int) (p[1] & 0xff);
00368 
00369       if (b1 == 10)
00370     continue;
00371 
00372       if ((b1 == 172) && ((b2 >> 4) == 1))
00373     continue;
00374 
00375       if ((b1 == 192) && (b2 == 168))
00376     continue;
00377 
00378       if ((b1 == 169) && (b2 == 254))
00379     continue;
00380     }
00381 
00382     if (hostidlen > 0) {
00383       goto done;
00384     }
00385   }
00386   
00387  done:
00388   strcpy(local_hostid, inet_ntoa_replacement(ia));
00389   strncpy(hostid, local_hostid, hostidlen);
00390   status = strlen(local_hostid);
00391 
00392   close_socket(s);
00393   return status;
00394 
00395 #endif  /* if not interix or win32 */
00396 }
00397 
00398 
00410 int
00411 proxy_readable_timeout(SOCKET fd, int sec)
00412 {
00413   fd_set rset;
00414   struct timeval tv, *tvp;
00415 
00416   FD_ZERO(&rset);
00417   FD_SET(fd, &rset);
00418 
00419   tvp = NULL;
00420 
00421   if(sec >= 0) {
00422     tv.tv_sec = sec;
00423     tv.tv_usec = 0;
00424 
00425     tvp = &tv;
00426   }
00427 
00428   return select(fd+1, &rset, NULL, NULL, tvp);
00429 }
00430 
00447 int
00448 proxy_read_timeout(SOCKET d, char *b, int n, int sec)
00449 {
00450   int e;
00451 
00452   if(sec != PROXY_TIMEOUT_NONE) {
00453     do {
00454       e = proxy_readable_timeout(d, sec);
00455     } while((e == -1) && ((errno=errno_socket()) == EINTR));
00456 
00457     switch(e) {
00458       case 0:
00459         fprintf(stderr,"proxy_read_timeout(): timed out after %d seconds\n", 
00460           sec);
00461         errno = EDEADLK;
00462         return -1;
00463       case -1:
00464         fprintf(stderr,"proxy_read_timeout(): failed to wait for desc\n");
00465         return -1;
00466       /* default: */
00467         /* the descriptor is ready for reading.  drop to the actual read()
00468          * below.
00469          */
00470     }
00471   }
00472 
00473   if ((e = read_socket(d, b, n)) == SOCKET_ERROR) {
00474     perror("read");
00475     return e;
00476   }
00477 
00478   return e;
00479 }
00480 
00494 int
00495 proxy_tread(SOCKET fd, char *vptr, int n, int sec)
00496 {
00497   int nleft;
00498   int nread;
00499   char *ptr;
00500 
00501   ptr = vptr;
00502   nleft = n;
00503   while (nleft > 0) {
00504     nread = proxy_read_timeout(fd, ptr, nleft, sec);
00505 
00506     if (nread < 0) {
00507       if (errno == EINTR)
00508         nread = 0;              /* and call read() again */
00509       else
00510         return(-1);
00511     } else if (nread == 0)
00512       break;                    /* EOF */
00513 
00514     nleft -= nread;
00515     ptr   += nread;
00516   }
00517 
00518   if((n-nleft) <= 0) 
00519     return -1;
00520 
00521   return(n - nleft);
00522 }