Functions

comm_basics.c File Reference

#include <signal.h>
#include <errno.h>
#include <string.h>
#include <sys/types.h>
#include "portability.h"
#include "proxylib.h"
#include "comm_basics.h"
#include "utility.h"
Include dependency graph for comm_basics.c:

Go to the source code of this file.

Functions

ssize_t gs_twrite (SOCKET fildes, const void *buf, size_t nbyte)
ssize_t gs_writen (SOCKET fd, const void *vptr, size_t n)
int gs_tread (SOCKET d, char *b, int n)
ssize_t gs_readline (int fd, void *vptr, size_t maxlen)
SOCKET gs_establish_socket (in_port_t *port, int reuse)
SOCKET gs_bind_to_first_available_port (in_port_t initport, in_port_t *found_port)
int gs_listen_on_socket (SOCKET sock)
int gs_accept_connection (SOCKET listening_socket)
int gs_close_socket (SOCKET sock)
SOCKET gs_connect_to_host (char *ID, ipaddr_t ipaddr, int port, ipaddr_t proxyIP, int proxyPort)
SOCKET gs_connect_direct (char *host, int port)

Detailed Description

The functions in this file implement GridSolve basic communication infrastructure. Users wanting to use their own communication and authentication mechanism will have to rewrite these functions using their mechanisms. Users behind NATs are advised to use this communication library.

Definition in file comm_basics.c.


Function Documentation

int gs_accept_connection ( SOCKET  listening_socket  ) 

Wait for a connection on this socket.

Parameters:
lisetening_socket -- the socket to wait for connections on
Returns:
the descriptor for the accepted socket. on failure, returns -1.

Definition at line 292 of file comm_basics.c.

{
  struct sockaddr_in addr;  /* INET socket address */
  socklen_t addrlen;        /* address length */
  int sock;

  addrlen = sizeof(addr);
  sock = proxy_accept(listening_socket, (struct sockaddr *) &addr, &addrlen);
  while (sock == INVALID_SOCKET && errno_socket() == EINTR) {
    sock = proxy_accept(listening_socket, (struct sockaddr *) &addr, &addrlen);
  }
  return sock;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SOCKET gs_bind_to_first_available_port ( in_port_t  initport,
in_port_t *  found_port 
)

Bind to the first available port greater than or equal to the parameter 'initport'. After GS_NUM_PORTS_TO_TRY attempts it fails.

Parameters:
initport -- the requested port number
found_port -- on return, set to the actual port number bound
Returns:
descriptor for the bound socket. Returns -1 on error.

Definition at line 228 of file comm_basics.c.

{
  in_port_t port;
  in_port_t tryport;
  SOCKET sock;

  port = initport;
  tryport = port;

  /* 
   * It's important that we don't reuse the addresses here, as we will 
   * just attempt the next port if the current one fails - no problem...  
   * This call is typically used where the exact port doesn't matter much, 
   * but where we have multiple processes on the local host concurrently 
   * trying this call with the same starting port number. The proxy does 
   * this, and setting reuse=1 in the gs_establish_socket() call will spawn 
   * an unholy number of proxy processes. 
   */

  while ((sock = gs_establish_socket(&tryport, 0)) == -2) {
    port++;
    tryport = port;
    if (port > initport + GS_NUM_PORTS_TO_TRY) {
      ERRPRINTF("Impossible to bind to a port\n");
      return INVALID_SOCKET;
    }
  }

  if (proxy_is_socket_error(sock))
    return INVALID_SOCKET;

  *found_port = tryport;

  if (*found_port == 0) {
    *found_port = initport;
  }

  return sock;
}

Here is the call graph for this function:

int gs_close_socket ( SOCKET  sock  ) 

Close this socket.

Parameters:
sock -- the socket to be closed
Returns:
0 on success, -1 on failure

Definition at line 315 of file comm_basics.c.

{
  return proxy_close(sock);
}

Here is the call graph for this function:

Here is the caller graph for this function:

SOCKET gs_connect_direct ( char *  host,
int  port 
)

Connect directly (no proxy) to the specified host/port.

Parameters:
host -- hostname to connect to
port -- port to connect to
Returns:
the connected socket descriptor on success, -1 on failure.

Definition at line 381 of file comm_basics.c.

{
  char agent_cid[CID_LEN];
  struct hostent *hp;
  ipaddr_t ipaddr;
  
  DBGPRINTF("Connecting to host %s port %d\n", host, port);

  if ((hp = gethostbyname(host)) == NULL) {
    errno = errno_socket();
    ERRPRINTF("Could not gethostbyname for %s (errno %d) \n", host, errno);
    perror("gethostbyname()");
    return INVALID_SOCKET;
  }

  memcpy((void *) &ipaddr, hp->h_addr_list[0], sizeof(ipaddr));
  
  /* all ones will match any component ID */
  memset(agent_cid, 0xFF, CID_LEN);

  return gs_connect_to_host(agent_cid, ipaddr, port, 0, 0);
}

Here is the call graph for this function:

Here is the caller graph for this function:

SOCKET gs_connect_to_host ( char *  ID,
ipaddr_t  ipaddr,
int  port,
ipaddr_t  proxyIP,
int  proxyPort 
)

Establish a connection to the specified host.

Parameters:
ID -- the component ID of the host to connect to.
ipaddr -- the IP address of the host to connect to. If connecting through proxy, set this to 0.
port -- the port to connect to.
proxyIP -- the IP address of the host's proxy server. If not proxied, set this to 0.
proxyPort -- the port number of the proxy server.
Returns:
the connected socket descriptor on success, -1 on failure.

Definition at line 335 of file comm_basics.c.

{
  PROXY_COMPONENTADDR servaddr;
  char dottedip[20];
  char dottedproxy[20];
  SOCKET sockfd, option_value = 1;

  memcpy(servaddr.ID, ID, CID_LEN);

  servaddr.IP = ipaddr;
  servaddr.port = htons(port);
  servaddr.proxyIP = proxyIP;
  servaddr.proxyPort = htons(proxyPort);

  sockfd = proxy_socket(AF_INET, SOCK_STREAM, 0);

  if(setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, (char *) &option_value, 
       sizeof(int)) < 0)
    DBGPRINTF("Warning: failed to set TCP_NODELAY for fd %d\n", sockfd);

  proxy_ip_to_str(servaddr.IP, dottedip);
  proxy_ip_to_str(servaddr.proxyIP, dottedproxy);
  DBGPRINTF("Connecting to %s:%d (proxy %s:%d)\n", dottedip, 
    ntohs(servaddr.port), dottedproxy, ntohs(servaddr.proxyPort));

  if (proxy_connect(sockfd, &servaddr) < 0) {
    ERRPRINTF("Could not connect to %s:%d (proxy %s:%d)\n", dottedip, 
      ntohs(servaddr.port), dottedproxy, ntohs(servaddr.proxyPort));
    proxy_close(sockfd);
    return INVALID_SOCKET;
  }

  return sockfd;
}

Here is the call graph for this function:

Here is the caller graph for this function:

SOCKET gs_establish_socket ( in_port_t *  port,
int  reuse 
)

Get a socket and bind to it. Use the proxy library (gs_socket, gs_bind) to get a new socket descriptor and bind to it.

Parameters:
port -- Port number to be bound (on return this parameter is set to the actual value bound)
reuse -- If TRUE, the DO_REUSEADDR option is set to allow reuse of the requested port.
Returns:
The socket descriptor on success, -2 if the requested port is already in use, or -1 on failure.

Definition at line 170 of file comm_basics.c.

{
  SOCKET desc;
  struct sockaddr_in addr;
  socklen_t addr_length;
  int option_value = 1;

  if ((desc = proxy_socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) {
    return INVALID_SOCKET;
  }

  /* TODO */
  if (reuse) {
    if (setsockopt(desc, SOL_SOCKET, SO_REUSEADDR,
           (char *) (&option_value), sizeof(int)) == -1) {
      return INVALID_SOCKET;
    }
  }

  if(setsockopt(desc, IPPROTO_TCP, TCP_NODELAY, (char *) &option_value, 
       sizeof(int)) < 0)
    DBGPRINTF("Warning: failed to set TCP_NODELAY for fd %d\n", desc);

  memset((char *) &addr, 0x0, sizeof(addr));
  addr.sin_family = AF_INET;
  addr.sin_addr.s_addr = htonl(INADDR_ANY);
  addr.sin_port = htons(*port);

  if (proxy_bind(desc, (struct sockaddr *) &addr, sizeof(addr))) {
    if (errno_socket() == EADDRINUSE) {
      proxy_close(desc);
      return -2;
    }
    proxy_close(desc);
    return INVALID_SOCKET;
  }

  addr_length = sizeof(addr);
  if((proxy_getsockname(desc, (struct sockaddr *) &addr, &addr_length)) == -1) {
    proxy_close(desc);
    return INVALID_SOCKET;
  }
  *port = ntohs(addr.sin_port);

  return (desc);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int gs_listen_on_socket ( SOCKET  sock  ) 

Set socket as listening.

Parameters:
sock -- the socket descriptor
Returns:
0 on success, -1 on failure.

Definition at line 277 of file comm_basics.c.

{
  return proxy_listen(sock, PROXY_MAX_CONNECTIONS);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ssize_t gs_readline ( int  fd,
void *  vptr,
size_t  maxlen 
)

Reads from descriptor until newline.

Parameters:
fd -- descriptor to read from
vptr -- pointer to buffer to store string
maxlen -- length of vptr
Returns:
number of bytes read, 0 on EOF, or -1 on error.

Definition at line 132 of file comm_basics.c.

{
  int n, rc;
  char c, *ptr;

  ptr = vptr;
  for (n = 1; n < (int)maxlen; n++) {
    if ((rc = proxy_tread(fd, &c, 1, PROXY_TIMEOUT_DEFAULT)) == 1) {
      *ptr++ = c;
      if (c == '\n')
        break;                  /* newline is stored, like fgets() */
    } else if (rc == 0) {
      if (n == 1)
        return (0);             /* EOF, no data read */
      else
        break;                  /* EOF, some data was read */
    } else
      return (-1);              /* error, errno set by read() */
  }

  *ptr = 0;                     /* null terminate like fgets() */
  return (n);
}

Here is the call graph for this function:

Here is the caller graph for this function:

int gs_tread ( SOCKET  d,
char *  b,
int  n 
)

Read bytes from a descriptor (socket).

Parameters:
d -- the descriptor (socket) to read from
b -- the buffer containing the data to be read
n -- the number of bytes to read
Returns:
the number of bytes actually read. Returns -1 on error.

Definition at line 106 of file comm_basics.c.

{
  static int sig = 1;
  int retval = -1;

  if (sig) {
    (void) gs_signal(GS_SIGPIPE, SIG_IGN);
    sig = 0;
  }
  
  retval = proxy_tread(d, b, n, PROXY_TIMEOUT_DEFAULT);

  return retval;
}

Here is the call graph for this function:

Here is the caller graph for this function:

ssize_t gs_twrite ( SOCKET  fildes,
const void *  buf,
size_t  nbyte 
)

Write bytes to a descriptor (socket).

Parameters:
fildes -- the descriptor (socket) to write to
buf -- the buffer containing the data to be written
nbyte -- the number of bytes to write
Returns:
the number of bytes actually written. returns -1 on error.

Definition at line 46 of file comm_basics.c.

{
  static int sig = 1;
  if (sig) {
    (void) gs_signal(GS_SIGPIPE, SIG_IGN);
    sig = 0;
  }
  return gs_writen(fildes, buf, nbyte);
}

Here is the call graph for this function:

Here is the caller graph for this function:

ssize_t gs_writen ( SOCKET  fd,
const void *  vptr,
size_t  n 
)

Write until all bytes have been written (borrowed from Stevens "Unix Network Programming").

Parameters:
fd -- the descriptor (socket) to write to
vptr -- the buffer containing the data to be written
n -- the number of bytes to write
Returns:
the number of bytes written (which should equal the parameter 'n' since this routine keeps writing until 'n' bytes have been written). Returns -1 on error.

Definition at line 71 of file comm_basics.c.

{
  size_t          nleft;
  ssize_t         nwritten;
  const char      *ptr;

  ptr = vptr;
  DBGPRINTF("ns_writen: write %d bytes to socket %d num %d char %c\n", 
     n, fd, *((int *)ptr), (char)*ptr);
  nleft = n;
  while (nleft > 0) {
    if ( (nwritten = write_socket(fd, ptr, nleft)) == SOCKET_ERROR) {
      if (errno_socket() == EINTR)
        nwritten = 0;           /* and call write() agai n */
      else
        return(-1);             /* error */
    }

    nleft -= nwritten;
    ptr   += nwritten;
  }
  return(n);
}

Here is the caller graph for this function: