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() */
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() */