예제 #1
0
ssize_t XPlat_SocketUtils_send(XPlat_Socket s, const void *buf, size_t count)
{
    if( count == 0 )
        return 0;

    xplat_dbg(5, xplat_printf(FLF, stderr, 
                 "writing %"PRIszt" bytes to fd=%d)\n",
                 count, s));

    int flags = 0;
#if defined(os_linux)
    // don't generate SIGPIPE
    flags = MSG_NOSIGNAL;
#endif

    ssize_t bytes_written = 0;

    while( bytes_written !=  (ssize_t) count ) {

        ssize_t ret = send( s, ((const char*)buf) + bytes_written,
                            count - bytes_written,
                            flags );

        int err = errno;

        if( ret == -1 ) {
            if( (err == EINTR) || (err == EAGAIN) || (err == EWOULDBLOCK) ) {
                continue;
            }
            else {
                xplat_dbg(3, xplat_printf(FLF, stderr,
                         "Warning: premature return from send(). "
                         "Wrote %"PRIsszt" of %"PRIszt" bytes ('%s')\n",
                         bytes_written, count, strerror(err)));
                return bytes_written;
            }
        }
        else {
            bytes_written += ret;
            if( bytes_written < (ssize_t) count ) {
                continue;
            }
            else {
                xplat_dbg(5, xplat_printf(FLF, stderr, "returning %"PRIsszt"\n",
                                          bytes_written));
                return bytes_written;
            }
        }
    }
    assert(!"XPlat_SocketUtils_send - invalid code path");
    return -1;
}
예제 #2
0
ssize_t XPlat_SocketUtils_recv(XPlat_Socket s, void *buf, size_t count)
{
    if( count == 0 )
        return 0;

    ssize_t bytes_recvd = 0;

    while( bytes_recvd != (ssize_t) count ) {

        ssize_t ret = recv( s, ((char*)buf) + bytes_recvd,
                            count - bytes_recvd, 0 );

        int err = errno;

        if( ret == -1 ) {
            if( (err == EINTR) || (err == EAGAIN) ) {
                continue;
            }
            else {
                xplat_dbg(3, xplat_printf(FLF, stderr,
                             "Warning: premature return from recv(). "
                             "Got %" PRIsszt " of %" PRIszt " bytes ('%s')\n",
                             bytes_recvd, count, strerror(err)));
                return bytes_recvd;
            }
        }
        else if( ret == 0 ) {
            // the remote endpoint has gone away
            xplat_dbg(3, xplat_printf(FLF, stderr, 
                         "recv() returned 0 (peer likely gone)\n"));
            return -1;
        }
        else {
            bytes_recvd += ret;
            if( bytes_recvd < (ssize_t) count ) {
                continue;
            }
            else {
                xplat_dbg(5, xplat_printf(FLF, stderr, "returning %" PRIsszt "\n",
                                          bytes_recvd));
                return bytes_recvd;
            }
        }
    }
    assert(!"XPlat_SocketUtils_recv - invalid code path");
    return -1;
}
예제 #3
0
int
PthreadMonitorData::Unlock( void )
{
    int rc = pthread_mutex_unlock( &mutex ); 
    if( rc ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                      "Error: pthread_mutex_unlock() returned '%s'\n",
                      strerror( rc )));
        fflush(stderr);
    }
    return rc;
}
예제 #4
0
static bool_t SetTcpNoDelay( XPlat_Socket sock )
{
#if defined(TCP_NODELAY)
    // turn off Nagle algorithm for coalescing packets
    int optval = 1;
    bool_t soret = XPlat_SocketUtils_SetOption( sock, 
                                                IPPROTO_TCP, 
                                                TCP_NODELAY,
                                                (void*) &optval, 
                                                (socklen_t) sizeof(optval) );
    if( ! soret ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr, 
                              "failed to set option\n") );
        return false;
    }
#else
    xplat_dbg(1, xplat_printf(FLF, stderr,
                "WARNING: TCP_NODELAY not found! Performance WILL suffer.\n"));
#endif
    return true;
}
예제 #5
0
static bool_t SetCloseOnExec( XPlat_Socket sock )
{
#ifndef os_windows
    int fdflag, fret;
    fdflag = fcntl( sock, F_GETFD );
    if( fdflag == -1 ) {
        // failed to retrieve the socket descriptor flags
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to get flags\n") );     
	return false;
    }
    else {
        fret = fcntl( sock, F_SETFD, fdflag | FD_CLOEXEC );
        if( fret == -1 ) {
            // failed to set the socket descriptor flags
            xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to set flags\n") );
	    return false;
        }
    }
#endif
    return true;
}
예제 #6
0
static bool_t ClearFlag( XPlat_Socket sock, int flag )
{
    int fdflag = fcntl( sock, F_GETFL );
    if( -1 == fdflag ) {
        // failed to retrieve the socket status flags
        xplat_dbg( 1, xplat_printf(FLF, stderr, "failed to get flags\n") );
        return false;
    }
    else {
        int fret;
        fret = fcntl( sock, F_SETFL, fdflag & ~flag );
        if( -1 == fret ) {
            // failed to set the socket status flags
            return false;
        }
    }
    return true;
}
예제 #7
0
bool_t XPlat_SocketUtils_GetPort( const XPlat_Socket sock, 
                                  XPlat_Port* port )
{
    const char* err_str;
    int err;
    struct sockaddr_in local_addr;
    socklen_t sockaddr_len = sizeof( local_addr );
    if( -1 == getsockname(sock, (struct sockaddr*) &local_addr, &sockaddr_len) ) {
        err = XPlat_NetUtils_GetLastError();
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr, 
                              "getsockname(%d) failed with %s\n",
                              sock, err_str) );
        return false;
    }

    *port = ntohs( local_addr.sin_port );
    return 0;
}
예제 #8
0
Monitor::Monitor( void )
{
    static pthread_mutex_t init_mutex = PTHREAD_MUTEX_INITIALIZER;
    int ret;
    bool failed = false;
    pthread_mutex_lock( &init_mutex );

    data = new PthreadMonitorData;
    if(data == NULL) {
        failed = true;
        goto ctor_fail;
    }

ctor_fail:
    pthread_mutex_unlock( &init_mutex );
    if(failed) {
        xplat_dbg(1, xplat_printf(FLF, stderr, 
                     "Error: Failed to construct Monitor\n"));
        data = NULL;
    }
}
예제 #9
0
파일: Monitor-win.C 프로젝트: bwelton/mrnet
int
WinMonitorData::ConditionVariable::TimedWait( int milliseconds )
{
    int ret = -1;
    DWORD dwret;        // used for return value from Win32 calls
    DWORD msecs;        // used for time limit

    if(milliseconds <= 0) {
        xplat_dbg(1, xplat_printf(FLF, stderr, 
                    "Error: TimedWait received %d ms limit\n", milliseconds));
        return ret;
    }

    msecs = (DWORD)milliseconds;


    // We're going to be waiting, so bump the number of waiters.
    // Even though we currently have our owning Monitor's mutex locked,
    // we need to protect access to this variable because our access to 
    // this variable later in this file occur when we do *not* have it locked.
    EnterCriticalSection( &nWaitersMutex );
    nWaiters++;
    LeaveCriticalSection( &nWaitersMutex );

    // Atomically release our owning object's mutex and 
    // wait on our semaphore.  ("Signalling" a Win32 Mutex releases it.)
    dwret = SignalObjectAndWait( hMutex,            // obj to signal
                                    hWaitSemaphore, // obj to wait on
                                    msecs,   // timeout
                                    FALSE );    // alertable?
    if( dwret == WAIT_OBJECT_0 )
    {
        // We have been released from the semaphore.
        // At this point, we do *not* have the critical section mutex.

        EnterCriticalSection( &nWaitersMutex );
        nWaiters--;

        // check if we were released via a broadcast and we are
        // the last thread to be released
        bool signalBroadcaster = (waitReleasedByBroadcast && (nWaiters == 0));
        LeaveCriticalSection( &nWaitersMutex );

        if( signalBroadcaster )
        {
            // We were unblocked by a broadcast and we were the last
            // waiter to run.  We need to:
            //
            //   1. Signal the broadcaster that it should continue (and
            //      release the owning Monitor's mutex lock)
            //   2. Try to acquire the owning Monitor's mutex lock.
            //
            // We need to do both in the same atomic operation.
            dwret = SignalObjectAndWait( hAllWaitersReleasedEvent,  // obj to signal
                                            hMutex,         // obj to wait on
                                            INFINITE,       // timeout
                                            FALSE );        // alertable?
        }
        else
        {
            // We were unblocked by a signal operation, or we were not
            // the last waiter to run.  We just need to try to reacquire the
            // owning Monitor's mutex lock.
            dwret = WaitForSingleObject( hMutex, INFINITE );
        }

        if( dwret == WAIT_OBJECT_0 )
        {
            ret = 0;
        }
        else
        {
            // the wait or signalandwait failed
            // TODO how to indicate this to the user?
        }
    }
    else
    {
        // SignalObjectAndWait failed
        // TODO how to indicate the failure?
    }

    return ret;
}
예제 #10
0
// Returns -1 for a fatal error, 0 on success, and 1 if the time given in 
// milliseconds has expired before the condition variable has been signalled.
int
PthreadMonitorData::TimedWaitOnCondition( unsigned int cvid, int milliseconds )
{
    int gt_ret, ret = -1;

    if( milliseconds < 0 ) {
        return ret;
    }

    pthread_cond_t *cv = NULL;
    ConditionVariableMap::iterator iter = cvmap.find( cvid );
    if( iter != cvmap.end() ) {
        cv = cvmap[cvid];
        if( NULL == cv ) {
            xplat_dbg(1, xplat_printf(FLF, stderr, 
                                      "NULL condition variable\n"));
            return ret;
        }
    } 
    else {
        return ret;
    }

    // Get time of day for 'abstime' arg of pthread_cond_timedwait
    struct timeval tv;
    gt_ret = gettimeofday( &tv, NULL );
    if( -1 == gt_ret ) {
        int err = errno;
        xplat_dbg(1, xplat_printf(FLF, stderr,
                                  "gettimeofday() failed - %s\n", 
                                  strerror(err)));
        return ret;
    }

    time_t sec = milliseconds / 1000;
    long msec = milliseconds % 1000;
    long nanosec = msec * 1000000L; // ms -> ns
    sec += tv.tv_sec;
    nanosec += (tv.tv_usec * 1000L);
    if( nanosec >= 1000000000L ) {
        nanosec -= 1000000000L;
        sec++;
    }

    struct timespec ts;
    ts.tv_sec = sec;
    ts.tv_nsec = nanosec;

    ret = pthread_cond_timedwait( cv, &mutex, &ts );
    if( ETIMEDOUT == ret ) {
        xplat_dbg(3, xplat_printf(FLF, stderr,  "time out!\n"));
    }
    else if( ret ) {
        xplat_dbg(1, xplat_printf(FLF, stderr,
                                  "pthread_cond_timedwait() failed - %s\n", 
                                  strerror(ret)));
        ret = -1;
    }

    return ret;
}
예제 #11
0
bool_t XPlat_SocketUtils_Connect( const char* host,
                                  const XPlat_Port port,
                                  XPlat_Socket* sock,
                                  unsigned num_retry )
{
    unsigned nConnectTries = 0;
    int err, cret = -1;
    XPlat_Socket _sock = *sock;
    const char* err_str = NULL;
    struct hostent *server_hostent = NULL;
    struct sockaddr_in server_addr;

    xplat_dbg( 3, xplat_printf(FLF, stderr,
                          "host=%s port=%hu sock=%d\n",
                          host, port, _sock) );

    if( InvalidSocket == _sock ) {
        _sock = socket( AF_INET, SOCK_STREAM, 0 );
        if ( InvalidSocket == _sock ) {
            err = XPlat_NetUtils_GetLastError();
            err_str = XPlat_Error_GetErrorString(err);
            xplat_dbg( 1, xplat_printf(FLF, stderr,
                                  "socket() failed with '%s'\n", err_str) );
            return false;
        }
        xplat_dbg( 5, xplat_printf(FLF, stderr,
                              "socket() => %d\n", _sock) );
    }

    server_hostent = gethostbyname( host ); 
    if ( NULL == server_hostent ) {
        err = XPlat_NetUtils_GetLastError();
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "gethostbyname() failed with '%s'\n", err_str) );
        return false;
    } 

    memset( &server_addr, 0, sizeof(server_addr) );
    server_addr.sin_family = AF_INET;
    server_addr.sin_port = htons( port );
    memcpy( &server_addr.sin_addr, server_hostent->h_addr_list[0],
            sizeof(struct in_addr) );

    do {
        cret = connect( _sock, (struct sockaddr *) &server_addr, 
                        (socklen_t) sizeof(server_addr) );
        if( -1 == cret ) {
            err = XPlat_NetUtils_GetLastError();
            err_str = XPlat_Error_GetErrorString(err);
            xplat_dbg( 5, xplat_printf(FLF, stderr,
                                  "connect() failed with '%s'\n", err_str) );
            if( ! (XPlat_Error_ETimedOut(err) || 
                   XPlat_Error_EConnRefused(err)) ) {
                xplat_dbg(1, xplat_printf(FLF, stderr,
                                     "connect() to %s:%hu failed with '%s'\n", 
                                      host, port, err_str));
                return false;
            }

            nConnectTries++;
            xplat_dbg( 3, xplat_printf(FLF, stderr,
                                  "timed out %d times\n", nConnectTries) );
            if( (num_retry > 0) && (nConnectTries >= num_retry) )
                break;

            // delay before trying again (more each time)
            sleep( nConnectTries );
        }
    } while( -1 == cret );

    if( -1 == cret ) {
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "connect() to %s:%d failed with '%s'\n", 
                              host, port, err_str) );
        return false;
    }

    xplat_dbg( 5, xplat_printf(FLF, stderr,
                          "connected to %s:%d \n", host, port) );

    // Close socket on exec
    if( ! SetCloseOnExec(_sock) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr, "XPlat_SocketUtils_Connect - " 
                              "failed to set close-on-exec\n") );
    }

    // Turn off Nagle algorithm
    if( ! SetTcpNoDelay(_sock) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr, 
                              "failed to set TCP_NODELAY\n") );
    }

    xplat_dbg( 3, xplat_printf(FLF, stderr,             
                          "returning socket=%d\n", _sock) );
    *sock = _sock;
    return true;
}
예제 #12
0
bool_t XPlat_SocketUtils_AcceptConnection( XPlat_Socket listen_sock, 
                                           XPlat_Socket* connected_sock,
                                           int timeout_sec,
                                           bool_t nonblock )
{
    int err, maxfd, retval;
    XPlat_Socket connection;
    const char* err_str;
    fd_set readfds;
    struct timeval tv;

    xplat_dbg( 3, xplat_printf(FLF, stderr,
                          "listening on socket=%d\n", listen_sock) );

    *connected_sock = InvalidSocket;

    if( nonblock && (0 == timeout_sec) )
        timeout_sec = 1;

    do {
        if( timeout_sec > 0 ) {
            // use select with timeout
            FD_ZERO( &readfds );
            FD_SET( listen_sock, &readfds );
            
            tv.tv_sec = timeout_sec;
            tv.tv_usec = 0;
        
            maxfd = listen_sock + 1;
            retval = select( maxfd, &readfds, NULL, NULL, &tv );
            err = XPlat_NetUtils_GetLastError();
            if( retval == 0 ) { // timed-out
                return false; // let caller decide what's next
            }
            else if( retval < 0 ) {
                err_str = XPlat_Error_GetErrorString(err);
                xplat_dbg( 1, xplat_printf(FLF, stderr,
                                      "select() failed with '%s'\n", err_str) );
                return false;
            }
        }

        // now try to accept a connection
        connection = accept( listen_sock, NULL, NULL );
        if( -1 == connection ) {
            err = XPlat_NetUtils_GetLastError();
            if( nonblock && (EWOULDBLOCK == err) )
                return false; // let caller decide what's next
	    if( EWOULDBLOCK != err ) {
                err_str = XPlat_Error_GetErrorString(err);
                xplat_dbg( 1, xplat_printf(FLF, stderr,
                                      "accept() failed with '%s'\n", err_str) );
	    } 
            if( EINTR != err )
                return false;
        }
    } while( -1 == connection );

    // Set the socket to be blocking
    if( ! XPlat_SocketUtils_SetBlockingMode(connection, true) )
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to set blocking\n") );

    // Close socket on exec
    if( ! SetCloseOnExec(connection) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to set close-on-exec\n") );     
    }
    
    // Turn off Nagle algorithm
    if( ! SetTcpNoDelay(connection) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr, 
                              "failed to set TCP_NODELAY\n") );
    }

    xplat_dbg( 3, xplat_printf(FLF, stderr,
                          "returning socket=%d\n", connection) );
    *connected_sock = connection;
    return true;
}
예제 #13
0
bool_t XPlat_SocketUtils_CreateListening( XPlat_Socket* sock, 
                                          XPlat_Port* port, 
                                          bool_t nonblock )
{
    static int backlog = 128;
    int err, optval;
    bool_t soret, success;
    XPlat_Socket _sock;
    XPlat_Port _port = *port;
    const char* err_str = NULL;
    struct sockaddr_in local_addr;

    if( InvalidPort == _port )
        _port = 0;

    _sock = socket( AF_INET, SOCK_STREAM, 0 );
    if( -1 == _sock ) {
        err = XPlat_NetUtils_GetLastError();
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "socket() failed with '%s'\n", err_str) );
        return false;
    }

    xplat_dbg( 3, xplat_printf(FLF, stderr,
                          "sock:%d, port:%d\n",
                          _sock, _port) );

    // Close socket on exec
    if( ! SetCloseOnExec(_sock) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to set close-on-exec\n") );     
    }

    // Set listening socket to non-blocking if requested
    if( nonblock ) {
        if( ! XPlat_SocketUtils_SetBlockingMode(_sock, false) )
            xplat_dbg( 1, xplat_printf(FLF, stderr,
                                  "failed to set non-blocking\n") );
    }

#ifndef os_windows
    /* Set the socket so that it does not hold onto its port after
     * the process exits (needed because on at least some platforms we
     * use well-known ports when connecting sockets) */
    optval = 1;
    soret = XPlat_SocketUtils_SetOption( _sock, SOL_SOCKET, SO_REUSEADDR, 
                                         (void*) &optval, 
                                         (socklen_t) sizeof(optval) );
    if( ! soret ) {
        err = XPlat_NetUtils_GetLastError();
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "setsockopt() failed with '%s'\n", err_str) );
    }
#endif

    memset( &local_addr, 0, sizeof(local_addr) );
    local_addr.sin_family = AF_INET;
    local_addr.sin_addr.s_addr = htonl( INADDR_ANY );

    if( 0 != _port ) {
        // try to bind and listen using the supplied port
        local_addr.sin_port = htons( _port );
        if( -1 == bind(_sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) ) {
            err = XPlat_NetUtils_GetLastError();
            err_str = XPlat_Error_GetErrorString(err);
            xplat_dbg( 1, xplat_printf(FLF, stderr,
                                  "bind() to static port %d failed with '%s'\n",
                                   _port, err_str) );
            XPlat_SocketUtils_Close( _sock );
            return false;
        }
    }

#ifndef os_windows
    // else, the system will assign a port for us in listen
    if( -1 == listen(_sock, backlog) ) {
        err = XPlat_NetUtils_GetLastError();
        err_str = XPlat_Error_GetErrorString(err);
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "listen() failed with '%s'\n", err_str) );
        XPlat_SocketUtils_Close( _sock );
        return false;
    }
    // determine which port we were actually assigned to
    if( ! XPlat_SocketUtils_GetPort(_sock, &_port) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to obtain port from socket\n" ) );
        XPlat_SocketUtils_Close( _sock );
        return false;
    }
#else
    // try binding ports, starting from 1st dynamic port
    _port = 49152;
    success = false;
    do {
        local_addr.sin_port = htons( _port );
        if( -1 == bind(_sock, (struct sockaddr*)&local_addr, sizeof(local_addr)) ) {
            err = XPlat_NetUtils_GetLastError();
            if( XPlat_Error_EAddrInUse( err ) ) {
                ++_port;
                continue;
            }
            else {
                err_str = XPlat_Error_GetErrorString(err);
                xplat_dbg( 1, xplat_printf(FLF, stderr,
                                      "bind() to dynamic port %d failed with '%s'\n",
                                      _port, err_str) );
                XPlat_SocketUtils_Close( _sock );
                return false;
            }
        }
        else {
            if( -1 == listen(_sock, backlog) ) {
                err = XPlat_NetUtils_GetLastError();
                if( XPlat_Error_EAddrInUse( err ) ) {
                    ++_port;
                    continue;
                }
                else {
                    err_str = XPlat_Error_GetErrorString(err);
                    xplat_dbg( 1, xplat_printf(FLF, stderr,
                                          "listen() failed with '%s'\n", err_str) );
                    XPlat_SocketUtils_Close( _sock );
                    return false;
                }
            }
            success = true;
        }
    } while( ! success );
#endif

    // Turn off Nagle algorithm
    if( ! SetTcpNoDelay(_sock) ) {
        xplat_dbg( 1, xplat_printf(FLF, stderr,
                              "failed to set TCP_NODELAY\n") );
    }

    *port = _port;
    *sock = _sock;
    xplat_dbg( 3, xplat_printf(FLF, stderr,
                          "returning socket=%d, port=%hu\n", _sock, _port) );
 
    return true;
}