/*** Copyright (c), The Regents of the University of California *** *** For more information please refer to files in the COPYRIGHT directory ***/ /* rcConnect.c - client connect call to server * */ #include "rcConnect.h" #include "rcGlobal.h" #ifdef windows_platform #include "startsock.h" #endif #ifdef USE_BOOST #include #else #ifndef windows_platform #include #endif #endif rcComm_t * rcConnect (char *rodsHost, int rodsPort, char *userName, char *rodsZone, int reconnFlag, rErrMsg_t *errMsg) { rcComm_t *conn; #ifdef windows_platform if(0 != startWinsock()) { conn = NULL; /*error -34*/ return conn; } #endif #ifndef windows_platform if (reconnFlag != RECONN_TIMEOUT && getenv (RECONNECT_ENV) != NULL) { reconnFlag = RECONN_TIMEOUT; } #endif conn = _rcConnect (rodsHost, rodsPort, userName, rodsZone, NULL, NULL, errMsg, 0, reconnFlag); return (conn); } rcComm_t * _rcConnect (char *rodsHost, int rodsPort, char *proxyUserName, char *proxyRodsZone, char *clientUserName, char *clientRodsZone, rErrMsg_t *errMsg, int connectCnt, int reconnFlag) { rcComm_t *conn; int status; char *tmpStr; #ifndef windows_platform if (ProcessType == CLIENT_PT) signal (SIGPIPE, (void (*)(int)) rcPipSigHandler); #endif conn = (rcComm_t*)malloc (sizeof (rcComm_t)); memset (conn, 0, sizeof (rcComm_t)); if (errMsg != NULL) { memset (errMsg, 0, sizeof (rErrMsg_t)); } if ((tmpStr = getenv (IRODS_PROT)) != NULL) { conn->irodsProt = (irodsProt_t)atoi(tmpStr); } else { conn->irodsProt = NATIVE_PROT; } status = setUserInfo (proxyUserName, proxyRodsZone, clientUserName, clientRodsZone, &conn->clientUser, &conn->proxyUser); if (status < 0) { if (errMsg != NULL) { errMsg->status = status; snprintf (errMsg->msg, ERR_MSG_LEN - 1, "_rcConnect: setUserInfo failed\n"); } free (conn); return NULL; } status = setRhostInfo (conn, rodsHost, rodsPort); if (status < 0) { if (errMsg != NULL) { rodsLogError (LOG_ERROR, status, "_rcConnect: setRhostInfo error, irodHost is probably not set correctly"); errMsg->status = status; snprintf (errMsg->msg, ERR_MSG_LEN - 1, "_rcConnect: setRhostInfo failed\n"); } free (conn); return NULL; } status = connectToRhost (conn, connectCnt, reconnFlag); if (status < 0) { if (getIrodsErrno (status) == SYS_SOCK_READ_TIMEDOUT) { /* timed out. try again */ rodsLog (LOG_ERROR, "_rcConnect: connectToRhost timedout retrying"); status = connectToRhost (conn, connectCnt, reconnFlag); } } if (status < 0) { rodsLogError (LOG_ERROR, status, "_rcConnect: connectToRhost error, server on %s is probably down", conn->host); if (errMsg != NULL) { errMsg->status = status; snprintf (errMsg->msg, ERR_MSG_LEN - 1, "_rcConnect: connectToRhost failed\n"); } free (conn); return NULL; } #ifndef windows_platform if (reconnFlag == RECONN_TIMEOUT && conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { if (strcmp ( conn->svrVersion->reconnAddr, "127.0.0.1") == 0 || strcmp ( conn->svrVersion->reconnAddr , "0.0.0.0") == 0 || strcmp ( conn->svrVersion->reconnAddr , "localhost")) { /* localhost. just use conn->host */ rstrcpy (conn->svrVersion->reconnAddr, conn->host, NAME_LEN); } #ifdef USE_BOOST conn->exit_flg = false; conn->lock = new boost::mutex; conn->cond = new boost::condition_variable; conn->reconnThr = new boost::thread( cliReconnManager, conn ); #else pthread_mutex_init (&conn->lock, NULL); pthread_cond_init (&conn->cond, NULL); status = pthread_create (&conn->reconnThr, pthread_attr_default, (void *(*)(void *)) cliReconnManager, (void *) conn); #endif if (status < 0) { rodsLog (LOG_ERROR, "_rcConnect: pthread_create failed, stat=%d", status); } } #endif return (conn); } int setUserInfo ( char *proxyUserName, char *proxyRodsZone, char *clientUserName, char *clientRodsZone, userInfo_t *clientUser, userInfo_t *proxyUser) { char *myUserName; char *myRodsZone; rstrcpy (proxyUser->userName, proxyUserName, NAME_LEN); if (clientUserName != NULL) { rstrcpy (clientUser->userName, clientUserName, NAME_LEN); } else if ((myUserName = getenv (CLIENT_USER_NAME_KEYWD)) != NULL) { rstrcpy (clientUser->userName, myUserName, NAME_LEN); } else { rstrcpy (clientUser->userName, proxyUserName, NAME_LEN); } rstrcpy (proxyUser->rodsZone, proxyRodsZone, NAME_LEN); if (clientRodsZone != NULL) { rstrcpy (clientUser->rodsZone, clientRodsZone, NAME_LEN); } else if ((myRodsZone = getenv (CLIENT_RODS_ZONE_KEYWD)) != NULL) { rstrcpy (clientUser->rodsZone, myRodsZone, NAME_LEN); } else { rstrcpy (clientUser->rodsZone, proxyRodsZone, NAME_LEN); } return (0); } /* YYYY - setAuthInfo - this routine is corrently not used */ int setAuthInfo (char *rodsAuthScheme, char *authStr, char *rodsServerDn, userInfo_t *clientUser, userInfo_t *proxyUser, int flag) { int authScheme; /* do some sanity check */ if (strcmp (rodsAuthScheme, PASSWORD_AUTH_KEYWD) == 0) { if (authStr == NULL || strlen (authStr) == 0) return (USER_AUTH_STRING_EMPTY); authScheme = PASSWORD; } else { return (USER_AUTH_SCHEME_ERR); } rstrcpy (proxyUser->authInfo.authScheme, rodsAuthScheme, NAME_LEN); rstrcpy (clientUser->authInfo.authScheme, rodsAuthScheme, NAME_LEN); proxyUser->authInfo.flag = flag; clientUser->authInfo.flag = flag; if (authScheme == PASSWORD) { rstrcpy (proxyUser->authInfo.authStr, authStr, NAME_LEN); rstrcpy (clientUser->authInfo.authStr, authStr, NAME_LEN); } return (0); } int setRhostInfo (rcComm_t *conn, char *rodsHost, int rodsPort) { int status; if (rodsHost == NULL || strlen (rodsHost) == 0) { return (USER_RODS_HOST_EMPTY); } rstrcpy (conn->host, rodsHost, NAME_LEN); conn->portNum = rodsPort; status = setSockAddr (&conn->remoteAddr, rodsHost, rodsPort); return (status); } int setSockAddr (struct sockaddr_in *remoteAddr, char *rodsHost, int rodsPort) { struct hostent *myHostent; myHostent = gethostbyname (rodsHost); if (myHostent == NULL || myHostent->h_addrtype != AF_INET) { rodsLog (LOG_ERROR, "unknown hostname: %s", rodsHost); return (USER_RODS_HOSTNAME_ERR - errno); } memcpy (&remoteAddr->sin_addr, myHostent->h_addr, myHostent->h_length); remoteAddr->sin_family = AF_INET; remoteAddr->sin_port = htons((unsigned short) (rodsPort)); return (0); } int rcDisconnect (rcComm_t *conn) { int status; if (conn == NULL) { return (0); } /* send disconnect msg to agent */ status = sendRodsMsg (conn->sock, RODS_DISCONNECT_T, NULL, NULL, NULL, 0, conn->irodsProt); /* need to call asio close if USE_BOOST_ASIO */ close (conn->sock); #ifdef USE_BOOST // FIXME:: Address Sockets Here As Well conn->exit_flg = true; // if( conn->reconnThr ) { //conn->reconnThr->interrupt(); // terminate at next interruption point boost::system_time until = boost::get_system_time() + boost::posix_time::seconds(2); conn->reconnThr->timed_join( until ); // force an interruption point } delete conn->reconnThr; delete conn->lock; delete conn->cond; #else //#ifdef windows_platform // closesocket(conn->sock); //#else if (conn->svrVersion->reconnPort > 0 && conn->reconnThr != 0) { pthread_cancel (conn->reconnThr); pthread_detach (conn->reconnThr); pthread_mutex_destroy (&conn->lock); pthread_cond_destroy (&conn->cond); } //#endif #endif status = freeRcComm (conn); return (status); } int freeRcComm (rcComm_t *conn) { int status; if (conn == NULL) { return (0); } status = cleanRcComm (conn); free (conn); return status; } int cleanRcComm (rcComm_t *conn) { if (conn == NULL) { return (0); } freeRError (conn->rError); conn->rError = NULL; if (conn->svrVersion != NULL) { free (conn->svrVersion); conn->svrVersion = NULL; } return (0); } void rcPipSigHandler () { fprintf (stderr, "Client Caught broken pipe signal. Connection to server may be down\n"); } rcComm_t * rcConnectXmsg (rodsEnv *myRodsEnv, rErrMsg_t *errMsg) { rcComm_t *conn; if (myRodsEnv == NULL) { fprintf (stderr, "rcConnectXmsg: NULL myRodsEnv input\n"); return (NULL); } conn = rcConnect (myRodsEnv->xmsgHost, myRodsEnv->xmsgPort, myRodsEnv->rodsUserName, myRodsEnv->rodsZone, 0, errMsg); return (conn); } #ifndef windows_platform void cliReconnManager (rcComm_t *conn) { int status; struct sockaddr_in remoteAddr; struct hostent *myHostent; reconnMsg_t reconnMsg; reconnMsg_t *reconnMsgOut = NULL; if (conn == NULL || conn->svrVersion == NULL || conn->svrVersion->reconnPort <= 0) { return; } conn->reconnTime = time (0) + RECONN_TIMEOUT_TIME; #ifdef USE_BOOST while ( !conn->exit_flg ) { /* JMC */ #else while (1) { #endif time_t curTime = time (0); if (curTime < conn->reconnTime) rodsSleep (conn->reconnTime - curTime, 0); #ifdef USE_BOOST boost::unique_lock boost_lock( *conn->lock ); #else pthread_mutex_lock (&conn->lock); #endif /* need to check clientState */ while (conn->clientState != PROCESSING_STATE) { /* have to wait until the client stop sending */ conn->reconnThrState = CONN_WAIT_STATE; rodsLog (LOG_DEBUG, "cliReconnManager: clientState = %d", conn->clientState); #ifdef USE_BOOST conn->cond->wait( boost_lock ); #else pthread_cond_wait (&conn->cond, &conn->lock); #endif } rodsLog (LOG_DEBUG, "cliReconnManager: Reconnecting clientState = %d", conn->clientState); conn->reconnThrState = PROCESSING_STATE; /* connect to server's reconn thread */ myHostent = gethostbyname (conn->svrVersion->reconnAddr); if (myHostent == NULL || myHostent->h_addrtype != AF_INET) { rodsLog (LOG_ERROR, "cliReconnManager: unknown hostname: %s", conn->svrVersion->reconnAddr); return; } memcpy (&remoteAddr.sin_addr, myHostent->h_addr, myHostent->h_length); remoteAddr.sin_family = AF_INET; remoteAddr.sin_port = htons((unsigned short) conn->svrVersion->reconnPort); conn->reconnectedSock = connectToRhostWithRaddr (&remoteAddr, conn->windowSize, 0); if (conn->reconnectedSock < 0) { #ifdef USE_BOOST conn->cond->notify_all(); boost_lock.unlock(); #else pthread_cond_signal (&conn->cond); pthread_mutex_unlock (&conn->lock); #endif rodsLog (LOG_ERROR, "cliReconnManager: connect to host %s failed, status = %d", conn->svrVersion->reconnAddr, conn->reconnectedSock); rodsSleep (RECONNECT_SLEEP_TIME, 0); continue; } bzero (&reconnMsg, sizeof (procState_t)); reconnMsg.procState = conn->clientState; reconnMsg.cookie = conn->svrVersion->cookie; status = sendReconnMsg (conn->reconnectedSock, &reconnMsg); if (status < 0) { close (conn->reconnectedSock); conn->reconnectedSock = 0; #ifdef USE_BOOST conn->cond->notify_all(); boost_lock.unlock(); #else pthread_cond_signal (&conn->cond); pthread_mutex_unlock (&conn->lock); #endif rodsLog (LOG_ERROR, "cliReconnManager: sendReconnMsg to host %s failed, status = %d", conn->svrVersion->reconnAddr, status); rodsSleep (RECONNECT_SLEEP_TIME, 0); continue; } if ((status = readReconMsg (conn->reconnectedSock, &reconnMsgOut)) < 0) { close (conn->reconnectedSock); conn->reconnectedSock = 0; #ifdef USE_BOOST conn->cond->notify_all(); boost_lock.unlock(); #else pthread_cond_signal (&conn->cond); pthread_mutex_unlock (&conn->lock); #endif rodsLog (LOG_ERROR, "cliReconnManager: readReconMsg to host %s failed, status = %d", conn->svrVersion->reconnAddr, status); rodsSleep (RECONNECT_SLEEP_TIME, 0); continue; } conn->agentState = reconnMsgOut->procState; free (reconnMsgOut); reconnMsgOut = NULL; conn->reconnTime = time (0) + RECONN_TIMEOUT_TIME; if (conn->clientState == PROCESSING_STATE) { rodsLog (LOG_DEBUG, "cliReconnManager: svrSwitchConnect. cliState = %d,agState=%d", conn->clientState, conn->agentState); cliSwitchConnect (conn); } else { rodsLog (LOG_DEBUG, "cliReconnManager: Not calling svrSwitchConnect, clientState = %d", conn->clientState); } #ifdef USE_BOOST conn->cond->notify_all(); boost_lock.unlock(); #else pthread_cond_signal (&conn->cond); pthread_mutex_unlock (&conn->lock); #endif } } int cliChkReconnAtSendStart (rcComm_t *conn) { if (conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { /* handle reconn */ #ifdef USE_BOOST boost::unique_lock boost_lock( *conn->lock ); #else pthread_mutex_lock (&conn->lock); #endif if (conn->reconnThrState == CONN_WAIT_STATE) { rodsLog (LOG_DEBUG, "cliChkReconnAtSendStart:ThrState=CONN_WAIT_STATE,clientState=%d", conn->clientState); conn->clientState = PROCESSING_STATE; #ifdef USE_BOOST conn->cond->notify_all(); /* wait for reconnManager to get done */ conn->cond->wait( boost_lock ); #else pthread_cond_signal (&conn->cond); /* wait for reconnManager to get done */ pthread_cond_wait (&conn->cond, &conn->lock); #endif } conn->clientState = SENDING_STATE; #ifdef USE_BOOST boost_lock.unlock(); #else pthread_mutex_unlock (&conn->lock); #endif } return 0; } int cliChkReconnAtSendEnd (rcComm_t *conn) { if (conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { /* handle reconn */ #ifdef USE_BOOST boost::unique_lock boost_lock( *conn->lock ); #else pthread_mutex_lock (&conn->lock); #endif conn->clientState = PROCESSING_STATE; if (conn->reconnThrState == CONN_WAIT_STATE) { #ifdef USE_BOOST conn->cond->notify_all(); #else pthread_cond_signal (&conn->cond); #endif } #ifdef USE_BOOST boost_lock.unlock(); #else pthread_mutex_unlock (&conn->lock); #endif } return 0; } int cliChkReconnAtReadStart (rcComm_t *conn) { if (conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { /* handle reconn */ #ifdef USE_BOOST boost::unique_lock boost_lock( *conn->lock ); conn->clientState = RECEIVING_STATE; boost_lock.unlock(); #else pthread_mutex_lock (&conn->lock); conn->clientState = RECEIVING_STATE; pthread_mutex_unlock (&conn->lock); #endif } return 0; } int cliChkReconnAtReadEnd (rcComm_t *conn) { #ifdef USE_BOOST if (conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { /* handle reconn */ boost::unique_lock boost_lock( *conn->lock ); conn->clientState = PROCESSING_STATE; if (conn->reconnThrState == CONN_WAIT_STATE) { rodsLog (LOG_DEBUG, "cliChkReconnAtReadEnd:ThrState=CONN_WAIT_STATE, clientState=%d", conn->clientState); conn->cond->notify_all(); /* wait for reconnManager to get done */ conn->cond->wait( boost_lock ); } boost_lock.unlock(); } #else if (conn->svrVersion != NULL && conn->svrVersion->reconnPort > 0) { /* handle reconn */ pthread_mutex_lock (&conn->lock); conn->clientState = PROCESSING_STATE; if (conn->reconnThrState == CONN_WAIT_STATE) { rodsLog (LOG_DEBUG, "cliChkReconnAtReadEnd:ThrState=CONN_WAIT_STATE, clientState=%d", conn->clientState); pthread_cond_signal (&conn->cond); /* wait for reconnManager to get done */ pthread_cond_wait (&conn->cond, &conn->lock); } pthread_mutex_unlock (&conn->lock); } #endif return 0; } #endif