Esempio n. 1
0
int pbs_original_connect(

  char *server)  /* I (FORMAT:  NULL | '\0' | HOSTNAME | HOSTNAME:PORT )*/

  {
  struct sockaddr_in   server_addr;
  char                *if_name;
  struct addrinfo     *addr_info;
  int                  out;
  int                  i;
  int                  opt_value = 1;
  int                  rc = PBSE_NONE;
  int                  local_errno;

  struct sockaddr      preferred_addr; /* set if TRQ_IFNAME set in torque.cfg */
  struct passwd       *pw;
  int                  use_unixsock = 0;
  uid_t                pbs_current_uid;
  long                 sockflags;
  int                  retry = 1;

#ifdef ENABLE_UNIX_SOCKETS
  struct sockaddr_un  unserver_addr;
  char                hnamebuf[256];
#endif

  char               *ptr;

  memset(&server_addr, 0, sizeof(server_addr));

  /* Read the timeout from the environment */
  if ((ptr = getenv("PBSAPITIMEOUT")) != NULL)
    {
    pbs_tcp_timeout = strtol(ptr, NULL, 0);

    if (pbs_tcp_timeout <= 0)
      pbs_tcp_timeout = 300;

    if (pbs_tcp_timeout > 2)
      retry = 0;
    }
  else
    pbs_tcp_timeout = 300;

  /* reserve a connection state record */

  out = -1;

  for (i = 1;i < NCONNECTS;i++)
    {
    if (connection[i].ch_mutex == NULL)
      {
      connection[i].ch_mutex = (pthread_mutex_t *)calloc(1, sizeof(pthread_mutex_t));
      pthread_mutex_init(connection[i].ch_mutex,NULL);
      }

    pthread_mutex_lock(connection[i].ch_mutex);

    if (connection[i].ch_inuse == FALSE)
      {
      out = i;
      
      connection[out].ch_inuse  = TRUE;
      connection[out].ch_errno  = 0;
      connection[out].ch_socket = -1;
      connection[out].ch_errtxt = NULL;

      break;

      }

    pthread_mutex_unlock(connection[i].ch_mutex);
    }

  if (out < 0)
    {
    if (getenv("PBSDEBUG"))
      fprintf(stderr, "ALERT:  cannot locate free channel\n");

    /* FAILURE */
    /* no need to unlock mutex here - in this case no connection was found */

    return(PBSE_NOCONNECTS * -1);
    }

  /* get server host and port */

  server = PBS_get_server(server, &server_port);

  if (server == NULL)
    {
    connection[out].ch_inuse = FALSE;

    pthread_mutex_unlock(connection[out].ch_mutex);

    if (getenv("PBSDEBUG"))
      fprintf(stderr, "ALERT:  PBS_get_server() failed\n");

    rc = PBSE_NOSERVER * -1;
    goto cleanup_conn_lite;
    }

  /* determine who we are */

  pbs_current_uid = getuid();

  if ((pw = getpwuid(pbs_current_uid)) == NULL)
    {
    if (getenv("PBSDEBUG"))
      {
      fprintf(stderr, "ALERT:  cannot get password info for uid %ld\n",
              (long)pbs_current_uid);
      }

    rc = PBSE_NOSERVER * -1;
    goto cleanup_conn_lite;
    }

  snprintf(pbs_current_user, PBS_MAXUSER, "%s", pw->pw_name);

  pbs_server = server;    /* set for error messages from commands */


#ifdef ENABLE_UNIX_SOCKETS
  /* determine if we want to use unix domain socket */

  if (!strcmp(server, "localhost"))
    use_unixsock = 1;
  else if ((gethostname(hnamebuf, sizeof(hnamebuf) - 1) == 0) && !strcmp(hnamebuf, server))
    use_unixsock = 1;

  /* NOTE: if any part of using unix domain sockets fails,
   * we just cleanup and try again with inet sockets */

  /* get socket */

  if (use_unixsock)
    {
    connection[out].ch_socket = socket(AF_UNIX, SOCK_STREAM, 0);

    if (connection[out].ch_socket < 0)
      {
      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot create socket:  errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      connection[out].ch_inuse = FALSE;

      local_errno = PBSE_PROTOCOL;

      use_unixsock = 0;
      }
    }

  /* and connect... */

  if (use_unixsock)
    {
    unserver_addr.sun_family = AF_UNIX;
    strcpy(unserver_addr.sun_path, TSOCK_PATH);

    if (connect(
          connection[out].ch_socket,
          (struct sockaddr *)&unserver_addr,
          (strlen(unserver_addr.sun_path) + sizeof(unserver_addr.sun_family))) < 0)
      {
      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;
      local_errno = errno;

      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot connect to server, errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      use_unixsock = 0;  /* will try again with inet socket */
      }
    }

  if (use_unixsock)
    {
    if (!send_unix_creds(connection[out].ch_socket))
      {
      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot send unix creds to pbs_server:  errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;
      local_errno = PBSE_PROTOCOL;

      use_unixsock = 0;  /* will try again with inet socket */
      }
    }

#endif /* END ENABLE_UNIX_SOCKETS */

  if (!use_unixsock)
    {
    int         retries = 0;
    std::string err_msg;
    /* at this point, either using unix sockets failed, or we determined not to
     * try */
    do
      {
      connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0);

      if (connection[out].ch_socket < 0)
        {
        if (getenv("PBSDEBUG"))
          {
          if (!retry || retries >= MAX_RETRIES)
            fprintf(stderr, "ERROR:  cannot connect to server \"%s\", errno=%d (%s)\n",
                  server,
                  errno,
                  strerror(errno));
          }

          retries++;

        if (!retry || retries >= MAX_RETRIES)
          {
          rc = PBSE_SYSTEM * -1;
          goto cleanup_conn;
          }
        else
          {
          connection[out].ch_inuse = FALSE;
          pthread_mutex_unlock(connection[out].ch_mutex);

          usleep(1000);
          continue;
          }
        }

      if (setsockopt(connection[out].ch_socket, SOL_SOCKET, SO_REUSEADDR, &opt_value, sizeof(opt_value)))
        perror("Couldn't set socket option");

      /* This is probably an IPv4 solution for the if_name and preferred_addr
         We need to see what ioctl call we need for IPv6 */
      if_name = trq_get_if_name();
      if (if_name)
        {
        rc = trq_set_preferred_network_interface(if_name, &preferred_addr);
        if (rc != PBSE_NONE)
          {
          if (!retry || retries >= MAX_RETRIES)
            fprintf(stderr, "could not set preferred network interface (%s): %d\n",
                  if_name, rc);

          if (if_name)
            free(if_name);

          retries++;

          if (!retry || retries >= MAX_RETRIES)
            {
            rc = rc * -1;
            goto cleanup_conn;
            }
          else
            {
            connection[out].ch_inuse = FALSE;
            pthread_mutex_unlock(connection[out].ch_mutex);

            usleep(1000);
            continue;
            }
          }

        rc = bind(connection[out].ch_socket, &preferred_addr, sizeof(struct sockaddr));
        if (rc < 0)
          {
          if (!retry || retries >= MAX_RETRIES)
            fprintf(stderr, "ERROR: could not bind preferred network interface (%s): errno: %d",
                  if_name, errno);

          if (if_name)
            free(if_name);

          retries++;

          if (!retry || retries >= MAX_RETRIES)
            {
            rc = PBSE_SYSTEM * -1;
            goto cleanup_conn;
            }
          else
            {
            close(connection[out].ch_socket);
            connection[out].ch_inuse = FALSE;

            usleep(1000);
            continue;
            }
          }
        }

      /* we are done with if_name at this point. trq_get_if_name allocated
         space for it. We need to free it */
      if (if_name)
        free(if_name);

      server_addr.sin_family = AF_INET;

      if ((rc = pbs_getaddrinfo(server, NULL, &addr_info)) != 0)
        {
        if (getenv("PBSDEBUG"))
          {
          if (!retry || retries >= MAX_RETRIES)
            fprintf(stderr, "ERROR:  cannot get servername (%s) errno=%d (%s)\n",
                  server,
                  errno,
                  strerror(errno));
          }

        retries++;
        if (!retry || retries >= MAX_RETRIES)
          {
          rc = PBSE_BADHOST * -1;
          goto cleanup_conn;
          }
        else
          {
          close(connection[out].ch_socket);
          connection[out].ch_inuse = FALSE;

          usleep(1000);
          continue;
          }
        }

      server_addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
      server_addr.sin_port = htons(server_port);

      /* Set the socket to non-blocking mode so we can timeout */
      if ((sockflags = fcntl(connection[out].ch_socket, F_GETFL, NULL)) < 0)
        {
        retries++;
        if (!retry || retries >= MAX_RETRIES)
          {
          if (getenv("PBSDEBUG"))
            fprintf(stderr, "ERROR:  getting socket flags failed\n");

          rc = errno * -1;
          goto cleanup_conn;
          }
        else
          {
          close(connection[out].ch_socket);
          connection[out].ch_inuse = FALSE;

          rc = sockflags;
          usleep(1000);
          continue;
          }
        }
      
      sockflags |= O_NONBLOCK;

      if ((rc = fcntl(connection[out].ch_socket, F_SETFL, sockflags)) < 0)
        {
        retries++;
        if (!retry || retries >= MAX_RETRIES)
          {
          if (getenv("PBSDEBUG"))
            fprintf(stderr, "ERROR:  setting socket flags failed\n");

          rc = errno * -1;
          goto cleanup_conn;
          }
        else
          {
          close(connection[out].ch_socket);
          connection[out].ch_inuse = FALSE;

          usleep(1000);
          continue;
          }
        }

      int sock = connection[out].ch_socket;
      int conn_retries = 0;

      while (((rc = connect(sock, (struct sockaddr *)&server_addr, sizeof(server_addr))) != 0) &&
             (conn_retries < MAX_RETRIES))
        {
        rc = socket_wait_for_write(sock);

        if (rc == PERMANENT_SOCKET_FAIL)
          {
          rc = errno;
          break;
          }

        conn_retries++;
        }

      if (rc != 0)
        {
        close(sock);
        retries++;
        continue;
        }

      // if we are at this point, connect has succeeded, proceed to authorize
      /* Set the socket back to blocking so read()s actually work */
      sockflags &= (~O_NONBLOCK);
      
      if ((rc = fcntl(connection[out].ch_socket, F_SETFL, sockflags)) < 0)
        {
        if (getenv("PBSDEBUG"))
          fprintf(stderr, "ERROR: setting socket flags failed\n");

        retries++;
        if (!retry || retries >= MAX_RETRIES)
          {
          rc = PBSE_SOCKET_FAULT * -1;
          goto cleanup_conn;
          }
        else
          {
          close(connection[out].ch_socket);
          connection[out].ch_inuse = FALSE;
          
          usleep(1000);
          continue;
          }
        }

    /* FIXME: is this necessary?  Contributed by one user that fixes a problem,
       but doesn't fix the same problem for another user! */
#if 0
#if defined(__hpux)
    /*HP-UX : avoiding socket caching */
    send(connection[out].ch_socket, '?', 1, MSG_OOB);

#endif
#endif

#ifdef MUNGE_AUTH
      rc = PBSD_munge_authenticate(connection[out].ch_socket, out);
      if (rc != 0)
        {

        if (rc == PBSE_MUNGE_NOT_FOUND)
          {
          local_errno = PBSE_MUNGE_NOT_FOUND;
          
          if (getenv("PBSDEBUG"))
            {
            fprintf(stderr, "ERROR:  cannot find munge executable\n");
            }

          rc = -1 * local_errno;
          goto cleanup_conn;
          }
        else
          {
          retries++;
          if (!retry || retries >= MAX_RETRIES)
            {
            local_errno = PBSE_PERM;
            
            if (getenv("PBSDEBUG"))
              {
              fprintf(stderr, "ERROR:  cannot authenticate connection to server \"%s\", errno=%d (%s)\n",
                server,
                errno,
                strerror(errno));
              }
            
            rc = -1 * local_errno;
            goto cleanup_conn;
            }
          else
            {
            close(connection[out].ch_socket);
            connection[out].ch_inuse = FALSE;
            
            usleep(1000);
            continue;
            }
          }
        }
#else  
      /* new version of iff using daemon */
      if ((ENABLE_TRUSTED_AUTH == FALSE) &&
          ((rc = validate_socket(connection[out].ch_socket, err_msg)) != PBSE_NONE))
        {
        if (!retry || retries >= MAX_RETRIES)
          {
          if (getenv("PBSDEBUG"))
            {
            const char *tmp_err_msg = "";

            if (rc > 0)
              tmp_err_msg = pbs_strerror(rc);

            fprintf(stderr, 
              "ERROR:  cannot authenticate connection to server \"%s\", errno=%d (%s)\n",
              server, rc, tmp_err_msg);
            }

          local_errno = PBSE_SOCKET_FAULT;
          rc = -1 * local_errno;
          goto cleanup_conn;
          }
        else
          {
          close(connection[out].ch_socket);
          connection[out].ch_inuse = FALSE;

          retries++;
          usleep(1000);
          continue;
          }
        }
#endif /* ifdef MUNGE_AUTH */
      } while ((rc != PBSE_NONE) && (retries < MAX_RETRIES));

    if (rc != PBSE_NONE)
      {
      fprintf(stderr, "%s\n", err_msg.c_str());
      goto cleanup_conn;
      }
    } /* END if !use_unixsock */

  pthread_mutex_unlock(connection[out].ch_mutex);

  return(out);

cleanup_conn:
  
  if (connection[out].ch_socket >= 0)
    close(connection[out].ch_socket);

cleanup_conn_lite:
  connection[out].ch_inuse = FALSE;
  pthread_mutex_unlock(connection[out].ch_mutex);

  return(rc < 0 ? rc : rc * -1);
  }  /* END pbs_original_connect() */
Esempio n. 2
0
int pbs_original_connect(

  char *server)  /* I (FORMAT:  NULL | '\0' | HOSTNAME | HOSTNAME:PORT )*/

  {
  struct sockaddr_in server_addr;
  char *if_name;
  struct addrinfo *addr_info;
  int out;
  int i;
  int rc;
  int local_errno;

  struct sockaddr preferred_addr; /* set if TRQ_IFNAME set in torque.cfg */
  struct passwd *pw;
  int use_unixsock = 0;
  uid_t pbs_current_uid;

#ifdef ENABLE_UNIX_SOCKETS
  struct sockaddr_un unserver_addr;
  char hnamebuf[256];
#endif

  char  *ptr;

  /* reserve a connection state record */

  out = -1;

  for (i = 1;i < NCONNECTS;i++)
    {
    if (connection[i].ch_mutex == NULL)
      {
      connection[i].ch_mutex = calloc(1, sizeof(pthread_mutex_t));
      pthread_mutex_init(connection[i].ch_mutex,NULL);
      }

    pthread_mutex_lock(connection[i].ch_mutex);

    if (connection[i].ch_inuse == FALSE)
      {
      out = i;
      
      connection[out].ch_inuse  = TRUE;
      connection[out].ch_errno  = 0;
      connection[out].ch_socket = -1;
      connection[out].ch_errtxt = NULL;

      break;
      }

    pthread_mutex_unlock(connection[i].ch_mutex);
    }

  if (out < 0)
    {
    if (getenv("PBSDEBUG"))
      fprintf(stderr, "ALERT:  cannot locate free channel\n");

    /* FAILURE */
    /* no need to unlock mutex here - in this case no connection was found */

    return(PBSE_NOCONNECTS * -1);
    }

  /* get server host and port */

  server = PBS_get_server(server, &server_port);

  if (server == NULL)
    {
    connection[out].ch_inuse = FALSE;

    pthread_mutex_unlock(connection[out].ch_mutex);

    if (getenv("PBSDEBUG"))
      fprintf(stderr, "ALERT:  PBS_get_server() failed\n");

    return(PBSE_NOSERVER * -1);
    }

  /* determine who we are */

  pbs_current_uid = getuid();

  if ((pw = getpwuid(pbs_current_uid)) == NULL)
    {
    if (getenv("PBSDEBUG"))
      {
      fprintf(stderr, "ALERT:  cannot get password info for uid %ld\n",
              (long)pbs_current_uid);
      }

    pthread_mutex_unlock(connection[out].ch_mutex);

    return(PBSE_SYSTEM * -1);
    }

  strcpy(pbs_current_user, pw->pw_name);

  pbs_server = server;    /* set for error messages from commands */


#ifdef ENABLE_UNIX_SOCKETS
  /* determine if we want to use unix domain socket */

  if (!strcmp(server, "localhost"))
    use_unixsock = 1;
  else if ((gethostname(hnamebuf, sizeof(hnamebuf) - 1) == 0) && !strcmp(hnamebuf, server))
    use_unixsock = 1;

  /* NOTE: if any part of using unix domain sockets fails,
   * we just cleanup and try again with inet sockets */

  /* get socket */

  if (use_unixsock)
    {
    connection[out].ch_socket = socket(AF_UNIX, SOCK_STREAM, 0);

    if (connection[out].ch_socket < 0)
      {
      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot create socket:  errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      connection[out].ch_inuse = FALSE;

      local_errno = PBSE_PROTOCOL;

      use_unixsock = 0;
      }
    }

  /* and connect... */

  if (use_unixsock)
    {
    unserver_addr.sun_family = AF_UNIX;
    strcpy(unserver_addr.sun_path, TSOCK_PATH);

    if (connect(
          connection[out].ch_socket,
          (struct sockaddr *)&unserver_addr,
          (strlen(unserver_addr.sun_path) + sizeof(unserver_addr.sun_family))) < 0)
      {
      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;
      local_errno = errno;

      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot connect to server, errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      use_unixsock = 0;  /* will try again with inet socket */
      }
    }

  if (use_unixsock)
    {
    if (!send_unix_creds(connection[out].ch_socket))
      {
      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot send unix creds to pbs_server:  errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;
      local_errno = PBSE_PROTOCOL;

      use_unixsock = 0;  /* will try again with inet socket */
      }
    }

#endif /* END ENABLE_UNIX_SOCKETS */

  if (!use_unixsock)
    {

    /* at this point, either using unix sockets failed, or we determined not to
     * try */

    connection[out].ch_socket = socket(AF_INET, SOCK_STREAM, 0);

    if (connection[out].ch_socket < 0)
      {
      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot connect to server \"%s\", errno=%d (%s)\n",
                server,
                errno,
                strerror(errno));
        }

      connection[out].ch_inuse = FALSE;

      pthread_mutex_unlock(connection[out].ch_mutex);

      return(PBSE_PROTOCOL * -1);
      }

    /* This is probably an IPv4 solution for the if_name and preferred_addr
       We need to see what ioctl call we need for IPv6 */
    if_name = trq_get_if_name();
    if (if_name)
      {
      rc = trq_set_preferred_network_interface(if_name, &preferred_addr);
      if (rc != PBSE_NONE)
        {
        fprintf(stderr, "could not set preferred network interface (%s): %d\n",
                if_name, rc);
        if(if_name)
          free(if_name);
        return(rc);
        }

      rc = bind(connection[out].ch_socket, &preferred_addr, sizeof(struct sockaddr));
      if (rc < 0)
        {
        fprintf(stderr, "ERROR: could not bind preferred network interface (%s): errno: %d",
                if_name, errno);
        if (if_name)
          free(if_name);
        return(PBSE_SYSTEM * -1);
        }
      }

    /* we are done with if_name at this point. trq_get_if_name allocated
       space for it. We need to free it */
    if (if_name)
      free(if_name);

    server_addr.sin_family = AF_INET;

    if (getaddrinfo(server, NULL, NULL, &addr_info) != 0)
      {
      close(connection[out].ch_socket);
      connection[out].ch_inuse = FALSE;

      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot get servername (%s) errno=%d (%s)\n",
                (server != NULL) ? server : "NULL",
                errno,
                strerror(errno));
        }

      pthread_mutex_unlock(connection[out].ch_mutex);

      return(PBSE_BADHOST * -1);
      }

    server_addr.sin_addr = ((struct sockaddr_in *)addr_info->ai_addr)->sin_addr;
    freeaddrinfo(addr_info);

    server_addr.sin_port = htons(server_port);

    if (connect(
          connection[out].ch_socket,
          (struct sockaddr *)&server_addr,
          sizeof(server_addr)) < 0)
      {
      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;

      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot connect to server, errno=%d (%s)\n",
                errno,
                strerror(errno));
        }

      pthread_mutex_unlock(connection[out].ch_mutex);

      return(errno * -1);
      }

    /* FIXME: is this necessary?  Contributed by one user that fixes a problem,
       but doesn't fix the same problem for another user! */
#if 0
#if defined(__hpux)
    /*HP-UX : avoiding socket caching */
    send(connection[out].ch_socket, '?', 1, MSG_OOB);

#endif
#endif

#ifdef MUNGE_AUTH
    rc = PBSD_munge_authenticate(connection[out].ch_socket, out);

    if (rc != 0)
      {
      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;

      if (rc == PBSE_MUNGE_NOT_FOUND)
        {
        local_errno = PBSE_MUNGE_NOT_FOUND;
        
        if (getenv("PBSDEBUG"))
          {
          fprintf(stderr, "ERROR:  cannot find munge executable\n");
          }
        }
      else
        {
        local_errno = PBSE_PERM;
        
        if (getenv("PBSDEBUG"))
          {
          fprintf(stderr, "ERROR:  cannot authenticate connection to server \"%s\", errno=%d (%s)\n",
            server,
            errno,
            strerror(errno));
          }
        }

      pthread_mutex_unlock(connection[out].ch_mutex);

      return(-1 * local_errno);
      }
    
    
#else  
    /* new version of iff using daemon */
    if ((ENABLE_TRUSTED_AUTH == FALSE) && ((rc = validate_socket(connection[out].ch_socket)) != PBSE_NONE))
      {
      close(connection[out].ch_socket);

      connection[out].ch_inuse = FALSE;

      if (getenv("PBSDEBUG"))
        {
        fprintf(stderr, "ERROR:  cannot authenticate connection to server \"%s\", errno=%d (%s)\n",
                server, rc, pbs_strerror(rc));
        }
      
      local_errno = PBSE_SOCKET_FAULT;

      pthread_mutex_unlock(connection[out].ch_mutex);

      return(-1 * local_errno);
      }
#endif /* ifdef MUNGE_AUTH */

    } /* END if !use_unixsock */

  /* setup DIS support routines for following pbs_* calls */

  if ((ptr = getenv("PBSAPITIMEOUT")) != NULL)
    {
    pbs_tcp_timeout = strtol(ptr, NULL, 0);

    if (pbs_tcp_timeout <= 0)
      {
      pbs_tcp_timeout = 10800;      /* set for 3 hour time out */
      }
    }
  else
    {
    pbs_tcp_timeout = 10800;      /* set for 3 hour time out */
    }

  pthread_mutex_unlock(connection[out].ch_mutex);

  return(out);
  }  /* END pbs_original_connect() */