Logo Search packages:      
Sourcecode: ganglia version File versions

tcp.c

/*
 * $Id: tcp.c 1237 2008-04-13 09:18:00Z carenas $
 * This code was originally written by the authors below but 
 * I rewrote it and took out all the glib dependencies. 
 *
 * GNet - Networking library
 * Copyright (C) 2000  David Helder
 * Copyright (C) 2000  Andrew Lanoix
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
 * Boston, MA  02111-1307, USA.
 */
#include <unistd.h>

#include <gm_msg.h>
#include "net.h"

g_tcp_socket*
g_tcp_socket_connect (const char* hostname, int port)
{
  g_inet_addr* ia;
  g_tcp_socket* socket;

  ia = g_inetaddr_new(hostname, port);
  if (ia == NULL)
    return NULL;

  socket = g_tcp_socket_new(ia);
  g_inetaddr_delete(ia);

  return socket;
}

g_tcp_socket*
g_tcp_socket_new (const g_inet_addr* addr)
{
  int          sockfd;
  g_tcp_socket*     s;
  struct sockaddr_in*   sa_in;
  int       rv;

  if( addr == NULL )
     return NULL;

  /* Create socket */
  sockfd = socket (AF_INET, SOCK_STREAM, 0);
  if (sockfd < 0)
    return NULL;

  s = malloc( sizeof( g_tcp_socket ) );
  memset( s, 0, sizeof( g_tcp_socket ));
  s->sockfd = sockfd;
  s->ref_count = 1;

  /* Set up address and port for connection */
  memcpy(&s->sa, &addr->sa, sizeof(s->sa));
  sa_in = (struct sockaddr_in*) &s->sa;
  sa_in->sin_family = AF_INET;

  /* Connect */
  rv = connect(sockfd, &s->sa, sizeof(s->sa));
  if (rv != 0)
    {
      close (sockfd);
      free (s);
      return NULL;
    }

  return s;
}

#if 0
static void
g_tcp_socket_ref(g_tcp_socket* s)
{
  if( s==NULL)
     return;

  ++s->ref_count;
}
#endif

static void
g_tcp_socket_unref(g_tcp_socket* s)
{
  if( s == NULL )
     return;

  --s->ref_count;

  if (s->ref_count == 0)
    {
       close(s->sockfd);
       free(s);
    }
}

void
g_tcp_socket_delete(g_tcp_socket* s)
{
  if (s != NULL)
    g_tcp_socket_unref(s);
}

g_tcp_socket*
g_tcp_socket_server_new (int port)
{
  g_inet_addr iface;
  struct sockaddr_in* sa_in;

  /* Set up address and port (any address, any port) */
  memset (&iface, 0, sizeof(iface));
  sa_in = (struct sockaddr_in*) &iface.sa;
  sa_in->sin_family = AF_INET;
  sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
  sa_in->sin_port = htons(port);

  return g_tcp_socket_server_new_interface (&iface);
}


g_tcp_socket* 
g_tcp_socket_server_new_interface (const g_inet_addr* iface)
{
  g_tcp_socket* s;
  struct sockaddr_in* sa_in;
  socklen_t socklen;
  int rval;
  const int on = 1;

  /* Create socket */
  s = malloc( sizeof(g_tcp_socket));
  memset(s, 0, sizeof(g_tcp_socket));

  s->ref_count = 1;
  s->sockfd = socket(AF_INET, SOCK_STREAM, 0);
  if (s->sockfd < 0)
    goto error;

  /* Set up address and port for connection */
  sa_in = (struct sockaddr_in*) &s->sa;
  sa_in->sin_family = AF_INET;
  if (iface)
    {
      sa_in->sin_addr.s_addr = G_SOCKADDR_IN(iface->sa).sin_addr.s_addr;
      sa_in->sin_port = G_SOCKADDR_IN(iface->sa).sin_port;
    }
  else
    {
      sa_in->sin_addr.s_addr = htonl(INADDR_ANY);
      sa_in->sin_port = 0;
    }

  /* Set REUSEADDR so we can reuse the port */
  rval = setsockopt(s->sockfd, SOL_SOCKET, SO_REUSEADDR, (void*) &on, sizeof(on));
  if ( rval <0)
     {
        err_ret("tcp_listen() setsockopt() SO_REUSEADDR error");
        goto error;
     }

  rval = setsockopt(s->sockfd, SOL_SOCKET, SO_KEEPALIVE, (void *)&on, sizeof(on));
  if ( rval <0)
     {
        err_ret("tcp_listen() setsockopt() SO_KEEPALIVE error");
        goto error;
     }
  rval = setsockopt(s->sockfd, IPPROTO_TCP, TCP_NODELAY, (void *)&on, sizeof(on));
  if ( rval <0)
     {
        err_ret("tcp_listen() setsockopt() TCP_NODELAY error");
        goto error;
     }

  /* Bind */
  if (bind(s->sockfd, &s->sa, sizeof(s->sa)) != 0)
    goto error;
  
  /* Get the socket name */
  socklen = sizeof(s->sa);
  if (getsockname(s->sockfd, &s->sa, &socklen) != 0)
    goto error;
  
  /* Listen */
  if (listen(s->sockfd, 10) != 0)
    goto error;
  
  return s;
  
 error:
  if (s) free(s);
  return NULL;
}

g_tcp_socket *
g_tcp_socket_server_accept (g_tcp_socket* socket)
{
  int sockfd;
  struct sockaddr sa;
  socklen_t n;
  fd_set fdset;
  g_tcp_socket* s;

  if( socket == NULL )
     return NULL;

 try_again:

  FD_ZERO(&fdset);
  FD_SET(socket->sockfd, &fdset);

  if (select(socket->sockfd + 1, &fdset, NULL, NULL, NULL) == -1)
    {
      if (errno == EINTR)
   goto try_again;

      return NULL;
    }

  n = sizeof(s->sa);

  if ((sockfd = accept(socket->sockfd, &sa, &n)) == -1)
    {
      if (errno == EWOULDBLOCK ||
     errno == ECONNABORTED ||
#ifdef EPROTO     /* OpenBSD does not have EPROTO */
     errno == EPROTO ||
#endif
     errno == EINTR)
   goto try_again;

      return NULL;
    }

  s = malloc( sizeof(g_tcp_socket) );
  memset( s, 0, sizeof(g_tcp_socket));
  s->ref_count = 1;
  s->sockfd = sockfd;
  memcpy(&s->sa, &sa, sizeof(s->sa));

  return s;
}



Generated by  Doxygen 1.6.0   Back to index