Logo Search packages:      
Sourcecode: lfc version File versions  Download package

connect.c

/*
 * $Id: connect.c,v 1.11 2009/01/07 09:49:55 dhsmith Exp $
 */

/*
 * Copyright (C) 1990-2008 by CERN/IT/PDP/DM
 * All rights reserved
 */

#ifndef lint
static char sccsid[] = "@(#)$RCSfile: connect.c,v $ $Revision: 1.11 $ $Date: 2009/01/07 09:49:55 $ CERN/IT/PDP/DM Frederic Hemmer";
#endif /* not lint */

/* connect.c    Remote File I/O - connect to remote server              */

#define RFIO_KERNEL     1       /* system part of Remote File I/O       */

#if defined(_WIN32)
#include "log.h"             /* system logger                        */
#else
#include <syslog.h>             /* system logger                        */
#endif
#include "rfio.h"               /* remote file I/O definitions               */
#include <Cglobals.h>         /* thread local storage for global variables */
#include <Cnetdb.h>           /* thread-safe network database routines */
#include <osdep.h>
#ifdef CSEC
#include "Csec_api.h"
#endif

#ifndef _WIN32
#if defined(_REENTRANT) || defined(_THREAD_SAFE)
#define strtok(X,Y) strtok_r(X,Y,&last)
#endif /* _REENTRANT || _THREAD_SAFE */
#endif /* _WIN32 */

extern char     *getconfent();
extern char     *getenv();      /* get environmental variable value     */
char *rfio_lasthost _PROTO(()); /* returns last succesfully connected host     */
int rfio_newhost _PROTO((char *)); /* returns last succesfully connected host     */
extern int DLL_DECL isremote_sa _PROTO((struct sockaddr *, char *));

static int  last_host_key = -1; /* key to hold the last connect host name in TLS */

int DLL_DECL rfio_connect(node,remote)       /* Connect <node>'s rfio server */
char    *node;                  /* remote host to connect               */
int     *remote  ;              /* connected host is remote or not      */
{
   register int    s;           /* socket descriptor                    */
   struct addrinfo hints, *ai, *aitop; /* input and output from getaddrinfo call      */
   char strport[NI_MAXSERV];           /* string representation of port to connect to */
   int gaierrno;                /* return code from getaddrinfo         */
   struct in6_addr test6_addr;  /* used for checking for port number    */
   struct sockaddr_storage sin; /* keep address of connected server     */
   int isconnected, last_error; /* record error and connection status   */
#if defined(_WIN32)
   int last_wsa_error;          /* record error during connection       */
#endif
   char    *host;               /* host name chararcter string          */
   char    *p, *cp;             /* character string pointers            */
   register int    retrycnt;    /* number of NOMORERFIO retries         */
   register int    retryint;    /* interval between NOMORERFIO retries  */
   register int    crtycnt = 0; /* connect retry count                  */
   register int    crtyint = 0; /* connect retry interval               */
   register int    crtyattmpt = 0; /* connect retry attempts done       */
   register int    crtycnts = 0 ;
   struct    stat statbuf ; /* NOMORERFIO stat buffer              */
   char    nomorebuf1[BUFSIZ], nomorebuf2[BUFSIZ]; /* NOMORERFIO buffers */
   char *last_host = NULL;
   int   last_host_len = 256;
#ifndef _WIN32
#if defined(_REENTRANT) || defined(_THREAD_SAFE)
   char *last = NULL;
#endif
#endif
   int port = -1;
   int timeout;
#ifdef CSEC
   Csec_context_t ctx;
   struct rfio_api_thread_info *thip = NULL;
#endif
   char tmphost[CA_MAXHOSTNAMELEN+1];


   INIT_TRACE("RFIO_TRACE");

   /* make local copy of "node" string */
   p = NULL;
   if (strlen(node)>=sizeof(tmphost)) {
      TRACE(1,"rfio","host name too long");
      serrno = SENOSHOST;
      END_TRACE();
      return(-1);
   }
   strcpy(tmphost, node);
   node = tmphost;

   /* Check if a port number is present and remove if found
    * the host portion may be a hostname of IP address of the form
    * IPv4 [IPv4] [IPv6]
    * or IPv6 if there is no port number
    */
   if ((p = strrchr (node, ':'))) {
      char *p2;
      p2 = strchr (node, ':');
      if (p2 != p && !memchr (p2+1, ']', p-p2-1)) {
         p = NULL;
      }
   }
   if (p) {
      *p = '\0';
      port = atoi (p+1);
   }

/*
 * Should we use an alternate name ?
 */

/*
 * Under some circumstances (heavy load, use of inetd) the server fails
 * to accept a connection. A simple retry mechanism is therefore
 * implemented here.
 */
   if ( rfioreadopt(RFIO_NETRETRYOPT) != RFIO_NOTIME2RETRY ) {
      /*
       * If the retry count option is not specified use the default from
       * the config file. This option is used by the TACOS slave. IN2P3 
       */
      crtycnt = rfioreadopt(RFIO_CONNECT_RETRY_COUNT_OPT);
      if ( crtycnt <= 0 ) {
         if ( (p = getenv("RFIO_CONRETRY")) != NULL ||
            (p = getconfent("RFIO", "CONRETRY", 0)) != NULL )       {
          if ((crtycnt = atoi(p)) <= 0)     {
             crtycnt = 0;
          }
         }
      }
      serrno = 0 ;
      crtyint = rfioreadopt(RFIO_CONNECT_RETRY_INT_OPT);
      if ( crtyint <= 0 ) {
         if ( (p = getenv("RFIO_CONRETRYINT")) != NULL ||
            (p = getconfent("RFIO", "CONRETRYINT", 0)) != NULL)        {
          if ((crtyint = atoi(p)) <= 0)     {
             crtyint = 0;
          }
         }
      }
   }
   crtycnts = crtycnt ;
/*
 * When the NOMORERFIO file exists, or if NOMORERFIO.host file exists,
 * the RFIO service is suspended. By default it will retry for ever every
 * DEFRETRYINT seconds.
 */
   if ( (p = getenv("RFIO_RETRY")) == NULL && 
        (p=getconfent("RFIO", "RETRY", 0)) == NULL) {
      retrycnt=DEFRETRYCNT;
   }
   else    {
      retrycnt=atoi(p);
   }
   if ( (p = getenv("RFIO_RETRYINT")) == NULL &&
        (p=getconfent("RFIO", "RETRYINT", 0)) == NULL) {
      retryint=DEFRETRYINT;
   }
   else    {
      retryint=atoi(p);
   }

   if ( (p = getenv("RFIO_CONNTIMEOUT")) == NULL &&
        (p = getconfent("RFIO", "CONNTIMEOUT", 0)) == NULL) {
      timeout=DEFCONNTIMEOUT;
   }
   else    {
      timeout=atoi(p);
   }

   memset(strport, '\0', sizeof(strport));
   if (port < 0) {
      /* Try environment variable */
      TRACE(2, "rfio", "rfio_connect: getenv(%s)","RFIO_PORT");
      if ((p = getenv("RFIO_PORT")) != NULL)  {
         TRACE(2, "rfio", "rfio_connect: *** Warning: using port %s", p);
         strncpy(strport, p, sizeof(strport)-1);
      } else {
        /* Try CASTOR configuration file */
        TRACE(2, "rfio", "rfio_connect: getconfent(%s,%s,0)","RFIO","PORT");
        if ((p = getconfent("RFIO","PORT",0)) != NULL) {
          TRACE(2, "rfio", "rfio_connect: *** Warning: using port %s", p);
          strncpy(strport, p, sizeof(strport)-1);
        } else {
          /* Use default port number */
          TRACE(2, "rfio", "rfio_connect: using default port number %d", (int) RFIO_PORT);
          snprintf(strport, sizeof(strport), "%u", RFIO_PORT);
        }
      }
   } else
      snprintf(strport, sizeof(strport), "%u", port);

   /* Warning : the return value of getconfent is a pointer to a thread-specific     */
   /* content - overwriten at each getconfent. If we do not want to have a corrupted */
   /* host value, the following call to getconfent have to be the last one.          */
   /* Note that subsequent calls to getconfent after this routine are not of concern */
   /* because we return a socket value, and do not depend afterwards on this static  */
   /* thread-specific address used in getconfent().                                  */
   if ( rfioreadopt(RFIO_NETOPT) != RFIO_NONET ) {
      if ((host = getconfent("NET",node,1)) == NULL)  {
       host = node;
      }
      else {
       TRACE(3,"rfio","set of hosts: %s",host);
      }
   }
   else    {
      host = node;
   }

   serrno = 0; /* reset the errno could be SEENTRYNFND */
   rfio_errno = 0;

   TRACE(1, "rfio", "rfio_connect: connecting(%s)",host);

   cp = strtok(host," \t") ;
   if (cp == NULL ) {
      TRACE(1,"rfio","host specified incorrect");
      serrno = SENOSHOST;
      END_TRACE();
      return(-1);
   }

  conretryall:
   TRACE(2, "rfio", "rfio_connect: Cgetaddrinfo for host %s", cp);
   memset(&hints, '\0', sizeof(hints));
   hints.ai_family = PF_UNSPEC;
   hints.ai_socktype = SOCK_STREAM;
#ifdef AI_ADDRCONFIG
   hints.ai_flags |= AI_ADDRCONFIG;
#endif
   gaierrno = Cgetaddrinfo(cp, strport, &hints, &aitop);
   if (gaierrno == EAI_NONAME) {
      TRACE(2, "rfio", "rfio_connect: %s: no such host or service",cp);
      serrno = SENOSHOST;     /* No such host                 */
      END_TRACE();
      return(-1);
   } else if (gaierrno != 0) {
      TRACE(2, "rfio", "rfio_connect: Cgetaddrinfo error: %s",
#if defined(_WIN32)
           Cgai_strerror(gaierrno));
#else
           (gaierrno == EAI_SYSTEM) ? sstrerror(errno) : Cgai_strerror(gaierrno));
#endif
      END_TRACE();
      return(-1);
   }

#if defined(_WIN32)
   if (strncmp (NOMORERFIO, "%SystemRoot%\\", 13) == 0 &&
       (p = getenv ("SystemRoot")))
      sprintf (nomorebuf1, "%s%s", p, strchr (NOMORERFIO, '\\'));
#else
   strcpy(nomorebuf1, NOMORERFIO);
#endif
   sprintf(nomorebuf2, "%s.%s", nomorebuf1, cp);
  retry:
   if (!stat(nomorebuf1,&statbuf)) {
      if (retrycnt-- >=0)  {
       syslog(LOG_ALERT, "rfio: connect: all RFIO service suspended (pid=%d)\n", getpid());
       sleep(retryint);
       goto retry;
      } else {
       syslog(LOG_ALERT, "rfio: connect: all RFIO service suspended (pid=%d), retries exhausted\n", getpid());
       serrno=SERTYEXHAUST;
       return(-1);
      }
   }
   if (!stat(nomorebuf2, &statbuf)) {
      if (retrycnt-- >=0)  {
       syslog(LOG_ALERT, "rfio: connect: RFIO service to <%s> suspended (pid=%d)\n", cp, getpid());
       sleep(retryint);
       goto retry;
      } else {
       syslog(LOG_ALERT, "rfio: connect: RFIO service to <%s> suspended (pid=%d), retries exhausted\n", cp, getpid());
       serrno=SERTYEXHAUST;
       return(-1);
      }
   }

  conretry:
#if defined(_WIN32)
   last_wsa_error = 0;
#endif
   last_error = 0;
   isconnected = 0;
   for(ai = aitop; ai && !isconnected; ai=ai->ai_next) {
      TRACE(2, "rfio", "rfio_connect: socket(%d, %d, %d)", ai->ai_family, ai->ai_socktype, ai->ai_protocol);
      if ((s = socket(ai->ai_family, ai->ai_socktype, ai->ai_protocol)) < 0)  {
        TRACE(2, "rfio", "rfio_connect: socket(): ERROR occured (%s)", neterror());
        continue;
      }
      TRACE(2, "rfio", "rfio_connect: netconnect_timeout(%d, %x, %d, %d)", s, ai->ai_addr, ai->ai_addrlen, timeout);
      if (netconnect_timeout(s, ai->ai_addr, ai->ai_addrlen, timeout) < 0)   {
         TRACE(2, "rfio", "rfio_connect: connect(): ERROR occured (%s)", neterror());
#if defined(_WIN32)
         if (WSAGetLastError() == WSAEAFNOSUPPORT)
#else
         if (errno == EAFNOSUPPORT)
#endif
         {
           (void) close(s);
             continue;
         }

#if defined(_WIN32)
         last_wsa_error = WSAGetLastError();
#endif
         last_error = (serrno) ? serrno : errno;
       (void) close(s);
      } else {
         isconnected = 1;
         memcpy(&sin,ai->ai_addr,ai->ai_addrlen);
      }
   }
   freeaddrinfo(aitop);

   if (!isconnected) {
#if defined(_WIN32)
      if (last_wsa_error == WSAECONNREFUSED)
#else
      if (last_error == ECONNREFUSED)
#endif
      {
         syslog(LOG_ALERT, "rfio: connect: %d failed to connect %s", getpid(), cp);
         if (crtycnt-- > 0)       {
          if (crtyint) sleep(crtyint);
          syslog(LOG_ALERT, "rfio: connect: %d retrying to connect %s", getpid(), cp);
          crtyattmpt ++ ;
          goto conretry;
       }
       if ( ( cp = strtok(NULL," \t")) != NULL )      {
          crtycnt =  crtycnts ;
          syslog(LOG_ALERT, "rfio: connect: after ECONNREFUSED, changing host to %s", cp) ;
          TRACE(3,"rfio","rfio: connect: after ECONNREFUSED, changing host to %s", cp) ;
          goto conretryall;
       }
      }
#if defined(_WIN32)
      if (last_wsa_error==WSAENETUNREACH ||
          last_wsa_error==WSAETIMEDOUT || last_error == SETIMEDOUT )
#else
      if (last_error==EHOSTUNREACH || last_error==ETIMEDOUT || last_error == SETIMEDOUT )
#endif
      {
         if ( ( cp = strtok(NULL," \t")) != NULL )    {
          crtycnt =  crtycnts ;
#if defined(_WIN32)
          if (last_wsa_error == WSAENETUNREACH)
#else
          if (last_error == EHOSTUNREACH)
#endif
             syslog(LOG_ALERT, "rfio: connect: after EHOSTUNREACH, changing host to %s", cp);
          else
             syslog(LOG_ALERT, "rfio: connect: after ETIMEDOUT, changing host to %s", cp);
                              
          goto conretryall;
         }
      }
      END_TRACE();
      return(-1);
   }
   TRACE(3,"rfio", "rfio_connect: OK");
   if (crtyattmpt) {
      syslog(LOG_ALERT, "rfio: connect: %d recovered connection after %d secs with %s",
           getpid(), crtyattmpt*crtyint,cp) ;
   }
   TRACE(4,"rfio", "rfio_connect: calling isremote on node %s", node);
   {
     int sav_serrno = serrno;
     *remote = isremote_sa( (struct sockaddr *)&sin, node ) ;
     serrno = sav_serrno; /* Failure or not os isremote(), we continue */
   }
   TRACE(4,"rfio", "rfio_connect: after isremote");
   Cglobals_get(&last_host_key, (void**)&last_host, last_host_len);
   strcpy(last_host, cp); /* remember to fetch back remote errs     */
   TRACE(2, "rfio", "rfio_connect: connected");
   TRACE(2, "rfio", "rfio_connect: calling setnetio(%d)", s);
   if (setnetio(s) < 0)    {
      close(s);
      END_TRACE();
      return(-1);
   }

#ifdef CSEC
   serrno = 0;
   Csec_client_initContext(&ctx, CSEC_SERVICE_TYPE_HOST, NULL);
   if (rfio_apiinit (&thip) == 0 && thip->use_authorization_id &&
    *thip->Csec_mech && *thip->Csec_auth_id) {
      Csec_client_setAuthorizationId (&ctx, thip->Csec_mech, thip->Csec_auth_id);
      if (thip->voname && thip->fqan)
         Csec_client_setVOMS_data (&ctx, thip->voname, thip->fqan, thip->nbfqan);
   }
   if (Csec_client_establishContext(&ctx, s) < 0) {
      TRACE(2, "rfio", "Could not establish an authenticated connection: %s", Csec_getErrorMessage());
      (void) netclose(s);
      Csec_clearContext(&ctx);
      END_TRACE();
      return(-1);
   }
   Csec_clearContext(&ctx);
#endif
   TRACE(1, "rfio", "rfio_connect: return socket %d", s);
   END_TRACE();
   return(s);
}

char    *rfio_lasthost() /* returns last succesfully connected host     */
{
   char *last_host = NULL;
   int   last_host_len = 256;
   Cglobals_get(&last_host_key, (void**)&last_host, last_host_len);
   TRACE(4, "rfio", "connect: last_host_name: %s", last_host);
   return(last_host);
}

int rfio_newhost(newhost) /* returns last succesfully connected host     */
     char *newhost;
{
   char *last_host = NULL;
   int   last_host_len = 256;
   
   if (newhost == NULL || newhost[0] == '\0') return(-1);

   Cglobals_get(&last_host_key, (void**)&last_host, last_host_len);
   TRACE(4, "rfio", "connect: last_host_name: changed from %s to %s", last_host, newhost);
   strncpy(last_host, newhost, 256);
   last_host[255] = '\0';
   return(0);
}

Generated by  Doxygen 1.6.0   Back to index