Defines | Functions

proxy_utils.c File Reference

#include <errno.h>
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include "portability.h"
#include "proxy_utils.h"
Include dependency graph for proxy_utils.c:

Go to the source code of this file.

Defines

#define BSD_COMP
#define INADDR_NONE   ((unsigned int) 0xffffffff)
#define SA_LEN(x)   (sizeof (struct sockaddr))
#define IFRFREF   (*ifr)

Functions

static const char * inet_ntoa_replacement (const struct in_addr in)
ipaddr_t proxy_get_my_ipaddr ()
int proxy_is_socket_error (SOCKET s)
int proxy_send_keepalive (SOCKET sock)
int proxy_is_something_on_socket (SOCKET sock)
int proxy_get_host_id (char *hostid, int hostidlen, int skip_loopback, int skip_private)
int proxy_readable_timeout (SOCKET fd, int sec)
int proxy_read_timeout (SOCKET d, char *b, int n, int sec)
int proxy_tread (SOCKET fd, char *vptr, int n, int sec)

Detailed Description

A set of routines needed for the proxy that were extracted from the rest of the GridSolve distribution in order to make the proxy code more stand-alone

Definition in file proxy_utils.c.


Define Documentation

#define BSD_COMP

Definition at line 11 of file proxy_utils.c.

#define IFRFREF   (*ifr)
#define INADDR_NONE   ((unsigned int) 0xffffffff)

Definition at line 30 of file proxy_utils.c.

#define SA_LEN (  )     (sizeof (struct sockaddr))

Function Documentation

static const char* inet_ntoa_replacement ( const struct in_addr  in  )  [static]

Replacement for the inet_ntoa() function, which returns a pointer to a string representation of the specified address.

Parameters:
in -- the address to convert into a string
Returns:
the string form of the address

Definition at line 44 of file proxy_utils.c.

{
  static char buf[16];
  const unsigned char *p;

  p = (const unsigned char *) &in.s_addr;
  sprintf(buf, "%u.%u.%u.%u",
      (unsigned int) (p[0] & 0xff), (unsigned int) (p[1] & 0xff),
      (unsigned int) (p[2] & 0xff), (unsigned int) (p[3] & 0xff));
  return buf;
}

Here is the caller graph for this function:

int proxy_get_host_id ( char *  hostid,
int  hostidlen,
int  skip_loopback,
int  skip_private 
)

Get a unique host id for authentication purposes from the system. For this, we use the address of the first configured, non-loopback, IP interface.

Parameters:
hostid -- on return contains string representation of the host id
hostidlen -- max length of the hostid
skip_loopback -- if TRUE, do not return a loopback address
skip_private -- if TRUE, do not return a private IP address
Returns:
one of this machine's IP addresses, or -1 on failure

Definition at line 218 of file proxy_utils.c.

{

#if defined (WIN32) 

 /* TODO AYK this only works for a client so fix it before
  * implementing WIN32 servers*/
  strncpy(hostid, "localhost", hostidlen);
  hostid[hostidlen-1] = 0;
  return (strlen(hostid));


#elif defined (__INTERIX) 

  SOCKET s = INVALID_SOCKET;
  struct sockaddr_in ia;
  int slen;
  char local_hostid[255];
  int status = -1;          /* assume failure */

  /* Connect to port 80 at google */
  if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) goto done;
  memset(&ia, 0, sizeof(ia));
  ia.sin_family = PF_INET;
  ia.sin_port = htons(80);
  ia.sin_addr.s_addr = inet_addr("216.239.59.99"); /* TODO googles ip */
  if (connect(s, (struct sockaddr *)&ia, sizeof(ia)) < 0) goto done;

  /* Get socket name */
  memset(&ia, 0, sizeof(ia));
  slen = sizeof(ia);
  if (getsockname(s, (struct sockaddr *)&ia, &slen) < 0) goto done;
  
 done:
  
  if (s != INVALID_SOCKET) {
    strcpy(local_hostid, inet_ntoa_replacement(ia.sin_addr));
    strncpy(hostid, local_hostid, hostidlen);
    status = strlen(local_hostid);
    close_socket(s);
  }

  return status;
  
#else  /* if not win32 or interix */

  int s;
  int i;
  struct ifconf ifc;
  char local_hostid[255];
  char inbuf[8192];
  int status;
  struct in_addr ia;

  status = -1;          /* assume failure */

  if (hostidlen < 0) return status;

  if ((s = socket(AF_INET, SOCK_DGRAM, 0)) < 0)
    goto done;

  /* try to shut up purify by initializing the buffer */
  memset(inbuf, '\0', sizeof(inbuf));

  ifc.ifc_len = sizeof(inbuf);
  ifc.ifc_buf = inbuf;
  if (ioctl(s, SIOCGIFCONF, (char *) &ifc) < 0)
    goto done;

  /* scan list of interfaces */
  for (i = 0; i < ifc.ifc_len;) {
    struct ifreq *ifr = (struct ifreq *) (ifc.ifc_buf + i);
    struct sockaddr sa;
#ifdef SIOCGIFFLAGS
    struct ifreq ifrf;
#endif

#ifdef SOCKADDR_HAS_SA_LEN
#define SA_LEN(x) ((x)->ifr_addr.sa_len)
#else
#define SA_LEN(x) (sizeof (struct sockaddr))
#endif

    /* 
     * copying the ifr_addr to a separate struct sockaddr buffer
     * appears to work around a compiler (or alignment) bug on solaris.
     * code generated by gcc worked just fine with sa as a 
     * pointer (declared as struct sockaddr *sa) initialized to 
     * &(ifr->ifr_addr).   sigh...
     */
    memcpy((char *)&sa, (char *)ifr + offsetof(struct ifreq, ifr_addr),
           sizeof(struct sockaddr));

    /* 
     * figure out where the next interface definition starts
     */
#ifdef _SIZEOF_ADDR_IFREQ
    i += _SIZEOF_ADDR_IFREQ(*ifr);
#else
#ifdef SOCKADDR_HAS_SA_LEN
    if (ifr->ifr_addr.sa_len > sizeof(struct sockaddr))
      i += sizeof(ifr->ifr_name) + ifr->ifr_addr.sa_len;
    else
      i += sizeof(ifr->ifr_name) + sizeof(struct sockaddr);
#else               /* SOCKADDR_HAS_SA_LEN */
    i += sizeof(*ifr);
#endif              /* SOCKADDR_HAS_SA_LEN */
#endif              /* _SIZEOF_ADDR_IFREQ */

#ifdef PROXY_HOSTID_TEST
    printf("name %s\n", ifr->ifr_name);
    printf(" family %d\n", sa.sa_family);
    printf(" len %d\n", SA_LEN(ifr));
#endif              /* PROXY_HOSTID_TEST */

    if (sa.sa_family != AF_INET)
      continue;

    /* 
     * get interface flags
     */
#ifdef SIOCGIFFLAGS
    memset(&ifrf, 0, sizeof(struct ifreq));
    strncpy(ifrf.ifr_name, ifr->ifr_name, sizeof(ifrf.ifr_name));
    ioctl(s, SIOCGIFFLAGS, (char *) &ifrf);
# define IFRFREF ifrf
#else
# define IFRFREF (*ifr)
#endif              /* SIOCGIFFLAGS */

    /* 
     * skip non configured and loopback interfaces
     */
    if ((IFRFREF.ifr_flags & IFF_UP) == 0)
      continue;
    if (((IFRFREF.ifr_flags & IFF_LOOPBACK) != 0) && (skip_loopback == SKIP_LOOPBACK))
      continue;

    /* 
     * extract IP address from the list
     */
    ia = (((struct sockaddr_in *) &sa)->sin_addr);
    if (ia.s_addr == INADDR_ANY || ia.s_addr == INADDR_NONE)
      continue;

    if (skip_private == SKIP_PRIVATE) {
      const unsigned char *p = (const unsigned char *) &ia.s_addr;
      unsigned int b1 = (unsigned int) (p[0] & 0xff);
      unsigned int b2 = (unsigned int) (p[1] & 0xff);

      if (b1 == 10)
    continue;

      if ((b1 == 172) && ((b2 >> 4) == 1))
    continue;

      if ((b1 == 192) && (b2 == 168))
    continue;

      if ((b1 == 169) && (b2 == 254))
    continue;
    }

    if (hostidlen > 0) {
      goto done;
    }
  }
  
 done:
  strcpy(local_hostid, inet_ntoa_replacement(ia));
  strncpy(hostid, local_hostid, hostidlen);
  status = strlen(local_hostid);

  close_socket(s);
  return status;

#endif  /* if not interix or win32 */
}

Here is the call graph for this function:

Here is the caller graph for this function:

ipaddr_t proxy_get_my_ipaddr (  ) 

Tries hard to get a valid IP address by looking at the available network interfaces on the machine. Since machines may have multiple network interfaces (and hence multiple addresses) this routine prioritizes the available addresses as follows (from higest to lowest): -an IP address from a non-private subnet -a private IP address -loopback address

Returns:
one of this machine's IP addresses, or -1 on failure

Definition at line 70 of file proxy_utils.c.

{
  struct hostent *hp;
  ipaddr_t IPaddr;
  char buf[1024];
  int rv;

  buf[0] = '\0';

  /* First try to get a real IP address */

  rv = proxy_get_host_id(buf, sizeof(buf), SKIP_LOOPBACK, SKIP_PRIVATE);

  if (rv < 0) {

    /* Could not get a real IP, now fall back an accept a private IP */
    rv = proxy_get_host_id(buf, sizeof(buf), SKIP_LOOPBACK, INCLUDE_PRIVATE);

    if (rv < 0) {
      /* Could not get a real IP or a private IP.  can probably get a loopback IP
       * address.  */

      rv = proxy_get_host_id(buf, sizeof(buf), INCLUDE_LOOPBACK, INCLUDE_PRIVATE);

      if (rv < 0) {
    fprintf(stderr,"All attempts to determine the IP address failed.\n");
    return -1;
      }
    }
  }

  if (strlen(buf) == 0) {
    fprintf(stderr,"Strange.. after proxy_get_host_id, buf is empty.\n");
    return -1;
  }

  if ((hp = gethostbyname(buf)) == NULL) {
    perror("gethostbyname()");
    return -1;
  }
  memcpy((void *) &IPaddr, hp->h_addr_list[0], sizeof(IPaddr));
  return IPaddr;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int proxy_is_socket_error ( SOCKET  s  ) 

Checks for error on a socket.

Parameters:
s -- the socket to be checked
Returns:
TRUE if there was an error, FALSE otherwise

Definition at line 124 of file proxy_utils.c.

{
  return (s == SOCKET_ERROR);
}

Here is the caller graph for this function:

int proxy_is_something_on_socket ( SOCKET  sock  ) 

Checks whether there is something available to read on a socket.

Parameters:
sock -- the socket to check
Returns:
1 if there is something on the socket, 0 if not, and -1 on error

Definition at line 165 of file proxy_utils.c.

{
  char buf[1];
  int try;
  
#ifdef WIN32
  u_long off = 0;
  u_long on = 1;
  ioctlsocket(sock, FIONBIO, &on);
  try = recv(sock, buf, 1, MSG_PEEK);
  ioctlsocket(sock, FIONBIO, &off);
#else
  int off = 0;
  int on = 1;
  ioctl(sock, FIONBIO, &on);
  try = recv(sock, buf, 1, MSG_PEEK);
  ioctl(sock, FIONBIO, &off);
#endif              /* UNIX */
  
  /* mm notes - found bug.  recv() above is failing with a return of
   * EWOULDBLOCK because the socket is non-blocking, but this recv
   * would block since there is nothing waiting to be read from the
   * socket.  This is a polling interface which will never received
   * data.  It only checks for endpoint exit. recv() returns 0 if no
   * messages are available and the peer has closed the connections.
   * recv() returns -1 and sets errno if error.  Upon success, recv()
   * returns number of bytes received. */

  errno = errno_socket();
  if (proxy_is_socket_error(try) && (errno != EWOULDBLOCK) && (errno != EAGAIN))
    return -1;

  if (try == 0)
    return 0;

  return 1;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int proxy_read_timeout ( SOCKET  d,
char *  b,
int  n,
int  sec 
)

Read bytes from a descriptor (socket) with optional timeout. This differs from proxy_tread() in that this routine does not wait until all requested bytes are available. This is basically a timeout wrapper around read() where proxy_tread() loops calling this routine until the requested bytes are available.

Parameters:
d -- the descriptor (socket) to read from
b -- the buffer containing the data to be read
n -- the number of bytes to read
sec -- maximum number of seconds to wait. if 0, does not block. if negative, blocks until readable.
Returns:
the number of bytes actually read. Returns -1 on error.

Definition at line 448 of file proxy_utils.c.

{
  int e;

  if(sec != PROXY_TIMEOUT_NONE) {
    do {
      e = proxy_readable_timeout(d, sec);
    } while((e == -1) && ((errno=errno_socket()) == EINTR));

    switch(e) {
      case 0:
        fprintf(stderr,"proxy_read_timeout(): timed out after %d seconds\n", 
          sec);
        errno = EDEADLK;
        return -1;
      case -1:
        fprintf(stderr,"proxy_read_timeout(): failed to wait for desc\n");
        return -1;
      /* default: */
        /* the descriptor is ready for reading.  drop to the actual read()
         * below.
         */
    }
  }

  if ((e = read_socket(d, b, n)) == SOCKET_ERROR) {
    perror("read");
    return e;
  }

  return e;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int proxy_readable_timeout ( SOCKET  fd,
int  sec 
)

Check whether the descriptor is ready for reading with an optional timeout.

Parameters:
fd -- descriptor to check for readability
sec -- maximum number of seconds to wait. if 0, does not block. if negative, blocks until readable.
Returns:
-1 on error, 0 on timeout, or the number of ready descriptors

Definition at line 411 of file proxy_utils.c.

{
  fd_set rset;
  struct timeval tv, *tvp;

  FD_ZERO(&rset);
  FD_SET(fd, &rset);

  tvp = NULL;

  if(sec >= 0) {
    tv.tv_sec = sec;
    tv.tv_usec = 0;

    tvp = &tv;
  }

  return select(fd+1, &rset, NULL, NULL, tvp);
}

Here is the caller graph for this function:

int proxy_send_keepalive ( SOCKET  sock  ) 

Sends a keepalive to the other end of the socket.

Parameters:
sock -- the socket on which to send keepalive
Returns:
0 on success, -1 on error

Definition at line 138 of file proxy_utils.c.

{
  proxy_tag_t ktag;

  ktag = PROXY_KEEPALIVE;
  
  if(write_socket(sock, &ktag, sizeof(ktag)) < 0)
    return -1;

  if(proxy_tread(sock, (char *)&ktag, sizeof(ktag), 1) < 0) {
    printf("Failed to receive ack for keepalive message.\n");
    return -1;
  }

  return 0;
}

Here is the call graph for this function:

Here is the caller graph for this function:

int proxy_tread ( SOCKET  fd,
char *  vptr,
int  n,
int  sec 
)

Read bytes from a descriptor (socket) with optional timeout. Adapted from W. Richard Stevens nread().

Parameters:
d -- the descriptor (socket) to read from
b -- the buffer containing the data to be read
n -- the number of bytes to read
sec -- maximum number of seconds to wait. if PROXY_TIMEOUT_NONE, blocks as a normal read would.
Returns:
the number of bytes actually read. Returns -1 on error.

Definition at line 495 of file proxy_utils.c.

{
  int nleft;
  int nread;
  char *ptr;

  ptr = vptr;
  nleft = n;
  while (nleft > 0) {
    nread = proxy_read_timeout(fd, ptr, nleft, sec);

    if (nread < 0) {
      if (errno == EINTR)
        nread = 0;              /* and call read() again */
      else
        return(-1);
    } else if (nread == 0)
      break;                    /* EOF */

    nleft -= nread;
    ptr   += nread;
  }

  if((n-nleft) <= 0) 
    return -1;

  return(n - nleft);
}

Here is the call graph for this function:

Here is the caller graph for this function: