EIO_Status CUNIXSocket::Connect(const string&   path,
                                const STimeout* timeout,
                                TSOCK_Flags     flags)
{
    if ( m_Socket ) {
        if (SOCK_Status(m_Socket, eIO_Open) != eIO_Closed)
            return eIO_Unknown;
        if (m_IsOwned != eNoOwnership)
            SOCK_Close(m_Socket);
    }
    if (timeout != kDefaultTimeout) {
        if ( timeout ) {
            if (&oo_timeout != timeout)
                oo_timeout = *timeout;
            o_timeout = &oo_timeout;
        } else
            o_timeout = 0;
    }
    EIO_Status status = SOCK_CreateUNIX(path.c_str(), o_timeout,
                                        &m_Socket, 0, 0, flags);
    if (status == eIO_Success) {
        SOCK_SetTimeout(m_Socket, eIO_Read,  r_timeout);
        SOCK_SetTimeout(m_Socket, eIO_Write, w_timeout);
        SOCK_SetTimeout(m_Socket, eIO_Close, c_timeout);        
    } else
        assert(!m_Socket);
    return status;
}
void CSocket::Reset(SOCK sock, EOwnership if_to_own, ECopyTimeout whence)
{
    if (m_Socket  &&  m_IsOwned != eNoOwnership)
        SOCK_Close(m_Socket);
    m_Socket  = sock;
    m_IsOwned = if_to_own;
    if (whence == eCopyTimeoutsFromSOCK) {
        if ( sock ) {
            const STimeout* timeout;
            timeout = SOCK_GetTimeout(sock, eIO_Read);
            if ( timeout ) {
                rr_timeout = *timeout;
                r_timeout  = &rr_timeout;
            } else
                r_timeout  = 0;
            timeout = SOCK_GetTimeout(sock, eIO_Write);
            if ( timeout ) {
                ww_timeout = *timeout;
                w_timeout  = &ww_timeout;
            } else
                w_timeout  = 0;
            timeout = SOCK_GetTimeout(sock, eIO_Close);
            if ( timeout ) {
                cc_timeout = *timeout;
                c_timeout  = &cc_timeout;
            } else
                c_timeout  = 0;
        } else
            r_timeout = w_timeout = c_timeout = 0;
    } else if ( sock ) {
        SOCK_SetTimeout(sock, eIO_Read,  r_timeout);
        SOCK_SetTimeout(sock, eIO_Write, w_timeout);
        SOCK_SetTimeout(sock, eIO_Close, c_timeout);
    }
}
EIO_Status CSocket::SetTimeout(EIO_Event event, const STimeout* timeout)
{
    if (timeout == kDefaultTimeout)
        return eIO_Success;

    switch (event) {
    case eIO_Open:
        if ( timeout ) {
            if (&oo_timeout != timeout)
                oo_timeout = *timeout;
            o_timeout  = &oo_timeout;
        } else
            o_timeout  = 0;
        break;
    case eIO_Read:
        if ( timeout ) {
            if (&rr_timeout != timeout)
                rr_timeout = *timeout;
            r_timeout  = &rr_timeout;
        } else
            r_timeout  = 0;
        break;
    case eIO_Write:
        if ( timeout ) {
            if (&ww_timeout != timeout)
                ww_timeout = *timeout;
            w_timeout  = &ww_timeout;
        } else
            w_timeout  = 0;
        break;
    case eIO_ReadWrite:
        if ( timeout ) {
            if (&rr_timeout != timeout)
                rr_timeout = *timeout;
            r_timeout  = &rr_timeout;
            if (&ww_timeout != timeout)
                ww_timeout = *timeout;
            w_timeout  = &ww_timeout;
        } else {
            r_timeout  = 0;
            w_timeout  = 0;
        }
        break;
    case eIO_Close:
        if ( timeout ) {
            if (&cc_timeout != timeout)
                cc_timeout = *timeout;
            c_timeout  = &cc_timeout;
        } else
            c_timeout  = 0;
        break;
    default:
        return eIO_InvalidArg;
    }
    return m_Socket ? SOCK_SetTimeout(m_Socket, event, timeout) : eIO_Success;
}
Example #4
0
/* Unconditionally drop the connection; timeout may specify time allowance */
static void s_DropConnection(SHttpConnector* uuu, const STimeout* timeout)
{
    size_t http_size = BUF_Size(uuu->http);
    assert(uuu->sock);
    if (http_size  &&  BUF_Read(uuu->http, 0, http_size) != http_size) {
        CORE_LOG_X(4, eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");
        assert(0);
    }
    SOCK_SetTimeout(uuu->sock, eIO_Close, timeout);
    SOCK_Close(uuu->sock);
    uuu->sock = 0;
}
Example #5
0
static EIO_Status s_VT_Read
(CONNECTOR       connector,
 void*           buf,
 size_t          size,
 size_t*         n_read,
 const STimeout* timeout)
{
    SSockConnector* xxx = (SSockConnector*) connector->handle;
    assert(xxx->sock);
    verify(SOCK_SetTimeout(xxx->sock, eIO_Read, timeout) == eIO_Success);
    return SOCK_Read(xxx->sock, buf, size, n_read, eIO_ReadPlain);
}
Example #6
0
static EIO_Status s_VT_Write
(CONNECTOR       connector,
 const void*     buf,
 size_t          size,
 size_t*         n_written,
 const STimeout* timeout)
{
    SSockConnector* xxx = (SSockConnector*) connector->handle;
    assert(xxx->sock);
    verify(SOCK_SetTimeout(xxx->sock, eIO_Write, timeout) == eIO_Success);
    return SOCK_Write(xxx->sock, buf, size, n_written, eIO_WritePlain);
}
Example #7
0
/* Skeletons for the socket i/o test:
 *   TEST__client(...)
 *   TEST__server(...)
 *   establish and close connection;  call test i/o functions like
 *     TEST__[client|server]_[1|2|...] (...)
 */
static void TEST__client(const char*     server_host,
                         unsigned short  server_port,
                         const STimeout* timeout)
{
    SOCK       sock;
    EIO_Status status;
    char       tmo[80];

    if ( timeout )
        sprintf(tmo, "%u.%06u", timeout->sec, timeout->usec);
    else
        strcpy(tmo, "INFINITE");
    CORE_LOGF(eLOG_Note,
              ("TEST__client(host = \"%s\", port = %hu, timeout = %s",
               server_host, server_port, tmo));

    /* Connect to server */
    status = SOCK_Create(server_host, server_port, timeout, &sock);
    assert(status == eIO_Success);
    verify(SOCK_SetTimeout(sock, eIO_ReadWrite, timeout) == eIO_Success);
    verify(SOCK_SetTimeout(sock, eIO_Close,     timeout) == eIO_Success);

    /* Test the simplest randezvous(plain request-reply)
     * The two peer functions are:
     *      "TEST__[client|server]_1(SOCK sock)"
     */
    TEST__client_1(sock);

    /* Test a more complex case
     * The two peer functions are:
     *      "TEST__[client|server]_2(SOCK sock)"
     */
    TEST__client_2(sock);

    /* Close connection and exit */
    status = SOCK_Close(sock);
    assert(status == eIO_Success  ||  status == eIO_Closed);

    CORE_LOG(eLOG_Note, "TEST completed successfully");
}
Example #8
0
/* Prepare connector for reading. Open socket if necessary and
 * make initial connect and send, re-trying if possible until success.
 * Return codes:
 *   eIO_Success = success, connector is ready for reading (uuu->sock != NULL);
 *   eIO_Timeout = maybe (check uuu->sock) connected and no data yet available;
 *   other code  = error, not connected (uuu->sock == NULL).
 */
static EIO_Status s_PreRead(SHttpConnector* uuu,
                            const STimeout* timeout,
                            EReadMode       read_mode)
{
    EIO_Status status;
    char* retry;

    for (;;) {
        status = s_ConnectAndSend(uuu, read_mode);
        if (!uuu->sock) {
            assert(status != eIO_Success);
            break;
        }
        if (status != eIO_Success) {
            if (status != eIO_Timeout  ||
                status == SOCK_Status(uuu->sock, eIO_Read)/*pending*/)
                break;
        }

        /* set timeout */
        SOCK_SetTimeout(uuu->sock, eIO_Read, timeout);

        if (!uuu->read_header)
            break;

        if ((status = s_ReadHeader(uuu, &retry, read_mode)) == eIO_Success) {
            size_t w_size = BUF_Size(uuu->w_buf);
            assert(!uuu->read_header  &&  !retry);
            /* pending output data no longer needed */
            if (BUF_Read(uuu->w_buf, 0, w_size) != w_size) {
                CORE_LOG_X(15, eLOG_Error,
                           "[HTTP]  Cannot discard output buffer");
                assert(0);
            }
            break;
        }
        /* if polling then bail out with eIO_Timeout */
        if(status == eIO_Timeout && timeout && !(timeout->sec | timeout->usec))
            break;

        /* HTTP header read error; disconnect and try to use another server */
        SOCK_Abort(uuu->sock);
        s_DropConnection(uuu, 0/*no wait*/);
        if (!s_Adjust(uuu, &retry, read_mode)) {
            uuu->can_connect = eCC_None;
            break;
        }
    }

    return status;
}
Example #9
0
static EIO_Status s_VT_Close
(CONNECTOR       connector,
 const STimeout* timeout)
{
    SSockConnector* xxx = (SSockConnector*) connector->handle;
    EIO_Status status = eIO_Success;
    assert(xxx->sock);
    if (xxx->try_own) {
        SOCK_SetTimeout(xxx->sock, eIO_Close, timeout);
        status = SOCK_Close(xxx->sock);
    }
    xxx->sock = 0;
    return status;
}
Example #10
0
/* Parse HTTP header */
static EIO_Status s_ReadHeader(SHttpConnector* uuu,
                               char**          retry,
                               EReadMode       read_mode)
{
    ERetry     redirect = eRetry_None; 
    int        server_error = 0;
    int        http_status;
    EIO_Status status;
    char*      header;
    size_t     size;

    assert(uuu->sock  &&  uuu->read_header);
    *retry = 0;

    /* line by line HTTP header input */
    for (;;) {
        /* do we have full header yet? */
        size = BUF_Size(uuu->http);
        if (!(header = (char*) malloc(size + 1))) {
            CORE_LOGF_X(7, eLOG_Error,
                        ("[HTTP]  Cannot allocate header, %lu bytes",
                         (unsigned long) size));
            return eIO_Unknown;
        }
        verify(BUF_Peek(uuu->http, header, size) == size);
        header[size] = '\0';
        if (size >= 4  &&  strcmp(&header[size - 4], "\r\n\r\n") == 0)
            break/*full header captured*/;
        free(header);

        status = SOCK_StripToPattern(uuu->sock, "\r\n", 2, &uuu->http, 0);
        if (status != eIO_Success) {
            ELOG_Level level;
            if (status == eIO_Timeout) {
                const STimeout* tmo = SOCK_GetTimeout(uuu->sock, eIO_Read);
                if (!tmo)
                    level = eLOG_Error;
                else if (tmo->sec | tmo->usec)
                    level = eLOG_Warning;
                else if (read_mode != eRM_WaitCalled)
                    level = eLOG_Trace;
                else
                    return status;
            } else
                level = eLOG_Error;
            CORE_LOGF_X(8, level, ("[HTTP]  Error reading header (%s)",
                                   IO_StatusStr(status)));
            return status;
        }
    }
    /* the entire header has been read */
    uuu->read_header = 0/*false*/;
    status = eIO_Success;

    if (BUF_Read(uuu->http, 0, size) != size) {
        CORE_LOG_X(9, eLOG_Error, "[HTTP]  Cannot discard HTTP header buffer");
        status = eIO_Unknown;
        assert(0);
    }

    /* HTTP status must come on the first line of the response */
    if (sscanf(header, "HTTP/%*d.%*d %d ", &http_status) != 1 || !http_status)
        http_status = -1;
    if (http_status < 200  ||  299 < http_status) {
        server_error = http_status;
        if      (http_status == 301  ||  http_status == 302)
            redirect = eRetry_Redirect;
        else if (http_status == 401)
            redirect = eRetry_Authenticate;
        else if (http_status == 407)
            redirect = eRetry_ProxyAuthenticate;
        else if (http_status < 0  ||  http_status == 403 || http_status == 404)
            uuu->net_info->max_try = 0;
    }
    uuu->code = http_status < 0 ? -1 : http_status;

    if ((server_error  ||  !uuu->error_header)
        &&  uuu->net_info->debug_printout == eDebugPrintout_Some) {
        /* HTTP header gets printed as part of data logging when
           uuu->net_info->debug_printout == eDebugPrintout_Data. */
        const char* header_header;
        if (!server_error)
            header_header = "HTTP header";
        else if (uuu->flags & fHCC_KeepHeader)
            header_header = "HTTP header (error)";
        else if (uuu->code == 301  ||  uuu->code == 302)
            header_header = "HTTP header (moved)";
        else if (!uuu->net_info->max_try)
            header_header = "HTTP header (unrecoverable error)";
        else
            header_header = "HTTP header (server error, can retry)";
        CORE_DATA_X(19, header, size, header_header);
    }

    {{
        /* parsing "NCBI-Message" tag */
        static const char kNcbiMessageTag[] = "\n" HTTP_NCBI_MESSAGE " ";
        const char* s;
        for (s = strchr(header, '\n');  s  &&  *s;  s = strchr(s + 1, '\n')) {
            if (strncasecmp(s, kNcbiMessageTag, sizeof(kNcbiMessageTag)-1)==0){
                const char* message = s + sizeof(kNcbiMessageTag) - 1;
                while (*message  &&  isspace((unsigned char)(*message)))
                    message++;
                if (!(s = strchr(message, '\r')))
                    s = strchr(message, '\n');
                assert(s);
                do {
                    if (!isspace((unsigned char) s[-1]))
                        break;
                } while (--s > message);
                if (message != s) {
                    if (s_MessageHook) {
                        if (s_MessageIssued <= 0) {
                            s_MessageIssued = 1;
                            s_MessageHook(message);
                        }
                    } else {
                        s_MessageIssued = -1;
                        CORE_LOGF_X(10, eLOG_Critical,
                                    ("[NCBI-MESSAGE]  %.*s",
                                     (int)(s - message), message));
                    }
                }
                break;
            }
        }
    }}

    if (uuu->flags & fHCC_KeepHeader) {
        if (!BUF_Write(&uuu->r_buf, header, size)) {
            CORE_LOG_X(11, eLOG_Error, "[HTTP]  Cannot keep HTTP header");
            status = eIO_Unknown;
        }
        free(header);
        return status;
    }

    if (uuu->parse_http_hdr
        &&  !(*uuu->parse_http_hdr)(header, uuu->adjust_data, server_error)) {
        server_error = 1/*fake, but still boolean true*/;
    }

    if (redirect == eRetry_Redirect) {
        /* parsing "Location" pointer */
        static const char kLocationTag[] = "\nLocation: ";
        char* s;
        for (s = strchr(header, '\n');  s  &&  *s;  s = strchr(s + 1, '\n')) {
            if (strncasecmp(s, kLocationTag, sizeof(kLocationTag) - 1) == 0) {
                char* location = s + sizeof(kLocationTag) - 1;
                while (*location  &&  isspace((unsigned char)(*location)))
                    location++;
                if (!(s = strchr(location, '\r')))
                    s = strchr(location, '\n');
                assert(s);
                do {
                    if (!isspace((unsigned char) s[-1]))
                        break;
                } while (--s > location);
                if (s != location) {
                    size_t len = (size_t)(s - location);
                    memmove(header, location, len);
                    header[len] = '\0';
                    *retry = header;
                }
                break;
            }
        }
    } else if (redirect != eRetry_None) {
        /* parsing "Authenticate" tags */
        static const char kAuthenticateTag[] = "-Authenticate: ";
        char* s;
        for (s = strchr(header, '\n');  s  &&  *s;  s = strchr(s + 1, '\n')) {
            if (strncasecmp(s + (redirect == eRetry_Authenticate ? 4 : 6),
                            kAuthenticateTag, sizeof(kAuthenticateTag)-1)==0){
                if ((redirect == eRetry_Authenticate
                     &&  strncasecmp(s, "\nWWW",   4) != 0)  ||
                    (redirect == eRetry_ProxyAuthenticate
                     &&  strncasecmp(s, "\nProxy", 6) != 0)) {
                    continue;
                }
                /* TODO */
            }
        }
    } else if (!server_error) {
        static const char kContentLengthTag[] = "\nContent-Length: ";
        const char* s;
        for (s = strchr(header, '\n');  s  &&  *s;  s = strchr(s + 1, '\n')) {
            if (!strncasecmp(s,kContentLengthTag,sizeof(kContentLengthTag)-1)){
                const char* expected = s + sizeof(kContentLengthTag) - 1;
                while (*expected  &&  isspace((unsigned char)(*expected)))
                    expected++;
                if (!(s = strchr(expected, '\r')))
                    s = strchr(expected, '\n');
                assert(s);
                do {
                    if (!isspace((unsigned char) s[-1]))
                        break;
                } while (--s > expected);
                if (s != expected) {
                    char* e;
                    errno = 0;
                    uuu->expected = (size_t) strtol(expected, &e, 10);
                    if (errno  ||  e != s)
                        uuu->expected = 0;
                    else if (!uuu->expected)
                        uuu->expected = (size_t)(-1L);
                }
                break;
            }
        }
    }
    if (!*retry)
        free(header);

    /* skip & printout the content, if server error was flagged */
    if (server_error && uuu->net_info->debug_printout == eDebugPrintout_Some) {
        BUF   buf = 0;
        char* body;

        SOCK_SetTimeout(uuu->sock, eIO_Read, 0);
        /* read until EOF */
        SOCK_StripToPattern(uuu->sock, 0, 0, &buf, 0);
        if (!(size = BUF_Size(buf))) {
            CORE_LOG_X(12, eLOG_Trace,
                       "[HTTP]  No HTTP body received with this error");
        } else if ((body = (char*) malloc(size)) != 0) {
            size_t n = BUF_Read(buf, body, size);
            if (n != size) {
                CORE_LOGF_X(13, eLOG_Error,
                            ("[HTTP]  Cannot read server error "
                             "body from buffer (%lu out of %lu)",
                             (unsigned long) n, (unsigned long) size));
            }
            CORE_DATA_X(20, body, n, "Server error body");
            free(body);
        } else {
            CORE_LOGF_X(14, eLOG_Error,
                        ("[HTTP]  Cannot allocate server error "
                         "body, %lu bytes", (unsigned long) size));
        }
        BUF_Destroy(buf);
    }

    return server_error ? eIO_Unknown : status;
}
Example #11
0
/* Connect to the server specified by uuu->net_info, then compose and form
 * relevant HTTP header, and flush the accumulated output data(uuu->w_buf)
 * after the HTTP header. If connection/write unsuccessful, retry to reconnect
 * and send the data again until permitted by s_Adjust().
 */
static EIO_Status s_ConnectAndSend(SHttpConnector* uuu,
                                   EReadMode       read_mode)
{
    EIO_Status status;

    for (;;) {
        char* null = 0;

        if (!uuu->sock) {
            if ((status = s_Connect(uuu, read_mode)) != eIO_Success)
                break;
            assert(uuu->sock);
            uuu->read_header = 1/*true*/;
            uuu->shut_down = 0/*false*/;
            uuu->expected = 0;
            uuu->received = 0;
            uuu->code = 0;
        } else
            status = eIO_Success;

        if (uuu->w_len) {
            size_t off = BUF_Size(uuu->w_buf) - uuu->w_len;

            SOCK_SetTimeout(uuu->sock, eIO_Write, uuu->w_timeout);
            do {
                char   buf[4096];
                size_t n_written;
                size_t n_write = BUF_PeekAt(uuu->w_buf, off, buf, sizeof(buf));
                status = SOCK_Write(uuu->sock, buf, n_write,
                                    &n_written, eIO_WritePlain);
                if (status != eIO_Success)
                    break;
                uuu->w_len -= n_written;
                off        += n_written;
            } while (uuu->w_len);
        } else if (!uuu->shut_down)
            status = SOCK_Write(uuu->sock, 0, 0, 0, eIO_WritePlain);

        if (status == eIO_Success) {
            assert(uuu->w_len == 0);
            if (!uuu->shut_down) {
                /* 10/07/03: While this call here is perfectly legal, it could
                 * cause connection severed by a buggy CISCO load-balancer. */
                /* 10/28/03: CISCO's beta patch for their LB shows that the
                 * problem has been fixed; no more 2'30" drops in connections
                 * that shut down for write.  We still leave this commented
                 * out to allow unpatched clients to work seamlessly... */ 
                /*SOCK_Shutdown(uuu->sock, eIO_Write);*/
                uuu->shut_down = 1;
            }
            break;
        }

        if (status == eIO_Timeout  &&  uuu->w_timeout  &&
            !(uuu->w_timeout->sec | uuu->w_timeout->usec)) {
            break;
        }
        CORE_LOGF_X(6, eLOG_Error,
                    ("[HTTP]  Error writing body at offset %lu (%s)",
                     (unsigned long)(BUF_Size(uuu->w_buf) - uuu->w_len),
                     IO_StatusStr(status)));

        /* write failed; close and try to use another server */
        SOCK_Abort(uuu->sock);
        s_DropConnection(uuu, 0/*no wait*/);
        if (!s_Adjust(uuu, &null, read_mode)) {
            uuu->can_connect = eCC_None;
            status = eIO_Closed;
            break;
        }
    }

    return status;
}
Example #12
0
static void TEST__server_2(SOCK sock, LSOCK lsock)
{
    EIO_Status status;
    size_t     n_io, n_io_done;
    char       buf[TEST_BUFSIZE];
    STimeout   r_to, w_to, rc_to;
    size_t     i;

    CORE_LOG(eLOG_Note, "TEST__server_2(TS2)");

    r_to.sec   = 0;
    r_to.usec  = 0;
    w_to = r_to;

    rc_to.sec  = 30;
    rc_to.usec = 123456;

    /* goto */
 l_reconnect: /* reconnection loopback */
    SOCK_SetDataLogging(sock, eOn);

    status = SOCK_SetTimeout(sock, eIO_Read,  &r_to);
    assert(status == eIO_Success);
    status = SOCK_SetTimeout(sock, eIO_Write, &w_to);
    assert(status == eIO_Success);

    for (i = 0;  ;  i++) {
        char* x_buf;

        /* read data from socket */
        n_io = sizeof(buf);
        status = SOCK_Read(sock, buf, n_io, &n_io_done, eIO_ReadPlain);
        switch ( status ) {
        case eIO_Success:
            CORE_LOGF(eLOG_Note,
                      ("TS2::read:"
                       " [%lu], status=%7s, n_io=%5lu, n_io_done=%5lu",
                       (unsigned long)i, IO_StatusStr(status),
                       (unsigned long)n_io, (unsigned long)n_io_done));
            assert(n_io_done > 0);
            break;

        case eIO_Closed:
            CORE_LOG(eLOG_Note, "TS2::read: connection closed");
            assert(SOCK_Status(sock, eIO_Read) == eIO_Closed);
            /* close connection */
            status = SOCK_Close(sock);
            assert(status == eIO_Success  ||  status == eIO_Closed);
            /* reconnect */
            if ( !lsock )
                return;

            CORE_LOG(eLOG_Note, "TS2::reconnect");
            if ((status = LSOCK_Accept(lsock, &rc_to, &sock)) != eIO_Success)
                return;
            assert(SOCK_Status(sock, eIO_Read) == eIO_Success);
            /* !!! */
            goto l_reconnect;

        case eIO_Timeout:
            CORE_LOGF(eLOG_Note,
                      ("TS2::read:"
                       " [%lu] timeout expired: %5u sec, %6u usec",
                       (unsigned long)i, r_to.sec, r_to.usec));
            assert(n_io_done == 0);
            s_DoubleTimeout(&r_to);
            status = SOCK_SetTimeout(sock, eIO_Read, &r_to);
            assert(status == eIO_Success);
            assert(SOCK_Status(sock, eIO_Read) == eIO_Timeout);
            break;

        default:
            CORE_LOGF(eLOG_Fatal,
                      ("TS2::read: status = %d", (int) status));
        } /* switch */

        /* write(just the same) data back to client */
        n_io  = n_io_done;
        x_buf = buf;
        while ( n_io ) {
            status = SOCK_Write(sock, buf, n_io, &n_io_done, eIO_WritePersist);
            switch ( status ) {
            case eIO_Success:
                CORE_LOGF(eLOG_Note,
                          ("TS2::write:"
                           " [%lu], status=%7s, n_io=%5lu, n_io_done=%5lu",
                           (unsigned long)i, IO_StatusStr(status),
                           (unsigned long)n_io, (unsigned long)n_io_done));
                assert(n_io_done > 0);
                break;
            case eIO_Closed:
                CORE_LOG(eLOG_Fatal, "TS2::write: connection closed");
                return;
            case eIO_Timeout:
                CORE_LOGF(eLOG_Note,
                          ("TS2::write:"
                           " [%lu] timeout expired: %5u sec, %6u usec",
                           (unsigned long)i, w_to.sec, w_to.usec));
                assert(n_io_done == 0);
                s_DoubleTimeout(&w_to);
                status = SOCK_SetTimeout(sock, eIO_Write, &w_to);
                assert(status == eIO_Success);
                break;
            default:
                CORE_LOGF(eLOG_Fatal,
                          ("TS2::write: status = %d", (int) status));
            } /* switch */

            n_io  -= n_io_done;
            x_buf += n_io_done;
        }
    }
}
Example #13
0
static void TEST__client_2(SOCK sock)
{
#define W_FIELD  10
#define N_FIELD  1000
#define N_REPEAT 10
#define N_RECONNECT 3
    EIO_Status status;
    size_t     n_io, n_io_done, i;
    char       buf[W_FIELD * N_FIELD + 1];

    CORE_LOGF(eLOG_Note,
              ("TEST__client_2(TC2) @:%hu",
               SOCK_GetLocalPort(sock, eNH_HostByteOrder)));

    /* fill out a buffer to send to server */
    memset(buf, 0, sizeof(buf));
    for (i = 0;  i < N_FIELD;  i++) {
        sprintf(buf + i * W_FIELD, "%10lu", (unsigned long)i);
    }

    /* send the buffer to server, then get it back */
    for (i = 0;  i < N_REPEAT;  i++) {
        char        buf1[sizeof(buf)];
        STimeout    w_to, r_to;
        int/*bool*/ w_timeout_on = (int)(i%2); /* if to start from     */
        int/*bool*/ r_timeout_on = (int)(i%2); /* zero or inf. timeout */
        char*       x_buf;

        /* set timeout */
        w_to.sec  = 0;
        w_to.usec = 0;
        status = SOCK_SetTimeout(sock, eIO_Write, w_timeout_on ? &w_to : 0);
        assert(status == eIO_Success);

        /* reconnect */
        if ((i % N_RECONNECT) == 0) {
            size_t j = i / N_RECONNECT;
            do {
                SOCK_SetDataLogging(sock, eOn);
                status = SOCK_Reconnect(sock, 0, 0, 0);
                SOCK_SetDataLogging(sock, eDefault);
                CORE_LOGF(eLOG_Note,
                          ("TC2::reconnect @:%hu: i=%lu, j=%lu, status=%s",
                           SOCK_GetLocalPort(sock, eNH_HostByteOrder),
                           (unsigned long) i, (unsigned long) j,
                           IO_StatusStr(status)));
                assert(status == eIO_Success);
                assert(SOCK_Status(sock, eIO_Read)  == eIO_Success);
                assert(SOCK_Status(sock, eIO_Write) == eIO_Success);

                /* give a break to let server reset the listening socket */
                X_SLEEP(1);
            } while ( j-- );
        }

        /* send */
        x_buf = buf;
        n_io = sizeof(buf);
        do {
            X_SLEEP(1);
            status = SOCK_Write(sock, x_buf, n_io,
                                &n_io_done, eIO_WritePersist);
            if (status == eIO_Closed)
                CORE_LOG(eLOG_Fatal, "TC2::write: connection closed");

            CORE_LOGF(eLOG_Note,
                      ("TC2::write:"
                       " i=%d, status=%7s, n_io=%5lu, n_io_done=%5lu"
                       " timeout(%d): %5u.%06us",
                       (int) i, IO_StatusStr(status),
                       (unsigned long) n_io, (unsigned long) n_io_done,
                       (int) w_timeout_on, w_to.sec, w_to.usec));
            if ( !w_timeout_on ) {
                assert(status == eIO_Success  &&  n_io_done == n_io);
            } else {
                const STimeout* x_to;
                assert(status == eIO_Success  ||  status == eIO_Timeout);
                x_to = SOCK_GetTimeout(sock, eIO_Write);
                assert(w_to.sec == x_to->sec  &&  w_to.usec == x_to->usec);
            }
            n_io  -= n_io_done;
            x_buf += n_io_done;
            if (status == eIO_Timeout)
                s_DoubleTimeout(&w_to);
            status = SOCK_SetTimeout(sock, eIO_Write, &w_to);
            assert(status == eIO_Success);
            w_timeout_on = 1/*true*/;
        } while ( n_io );

        /* get back the just sent data */
        r_to.sec  = 0;
        r_to.usec = 0;
        status = SOCK_SetTimeout(sock, eIO_Read, r_timeout_on ? &r_to : 0);
        assert(status == eIO_Success);

        x_buf = buf1;
        n_io = sizeof(buf1);
        do {
            if (i%2 == 0) {
                /* peek a little piece twice and compare */
                char   xx_buf1[128], xx_buf2[128];
                size_t xx_io_done1, xx_io_done2;
                if (SOCK_Read(sock, xx_buf1, sizeof(xx_buf1), &xx_io_done1,
                              eIO_ReadPeek) == eIO_Success  &&
                    SOCK_Read(sock, xx_buf2, xx_io_done1, &xx_io_done2,
                              eIO_ReadPeek) == eIO_Success) {
                    assert(xx_io_done1 >= xx_io_done2);
                    assert(memcmp(xx_buf1, xx_buf2, xx_io_done2) == 0);
                }
            }
            status = SOCK_Read(sock, x_buf, n_io, &n_io_done, eIO_ReadPlain);
            if (status == eIO_Closed) {
                assert(SOCK_Status(sock, eIO_Read) == eIO_Closed);
                CORE_LOG(eLOG_Fatal, "TC2::read: connection closed");
            }
            CORE_LOGF(eLOG_Note,
                      ("TC2::read: "
                       " i=%d, status=%7s, n_io=%5lu, n_io_done=%5lu"
                       " timeout(%d): %5u.%06us",
                       (int) i, IO_StatusStr(status),
                       (unsigned long) n_io, (unsigned long) n_io_done,
                       (int) r_timeout_on, r_to.sec, r_to.usec));
            if ( !r_timeout_on ) {
                assert(status == eIO_Success  &&  n_io_done > 0);
            } else {
                const STimeout* x_to;
                assert(status == eIO_Success  ||  status == eIO_Timeout);
                x_to = SOCK_GetTimeout(sock, eIO_Read);
                assert(r_to.sec == x_to->sec  &&  r_to.usec == x_to->usec);
            }

            n_io  -= n_io_done;
            x_buf += n_io_done;
            if (status == eIO_Timeout)
                s_DoubleTimeout(&r_to);
            status = SOCK_SetTimeout(sock, eIO_Read, &r_to);
            assert(status == eIO_Success);
            r_timeout_on = 1/*true*/;
        } while ( n_io );

        assert(memcmp(buf, buf1, sizeof(buf)) == 0);
    }
}
Example #14
0
const char* CORE_SendMailEx(const char*          to,
                            const char*          subject,
                            const char*          body,
                            const SSendMailInfo* uinfo)
{
    static const STimeout zero = {0, 0};
    const SSendMailInfo* info;
    SSendMailInfo ainfo;
    char buffer[1024];
    SOCK sock = 0;

    info = uinfo ? uinfo : SendMailInfo_Init(&ainfo);
    if (info->magic_number != MX_MAGIC_NUMBER)
        SENDMAIL_RETURN(6, "Invalid magic number");

    if ((!to         ||  !*to)        &&
        (!info->cc   ||  !*info->cc)  &&
        (!info->bcc  ||  !*info->bcc)) {
        SENDMAIL_RETURN(7, "At least one message recipient must be specified");
    }

    /* Open connection to sendmail */
    if (SOCK_Create(info->mx_host, info->mx_port, &info->mx_timeout, &sock)
        != eIO_Success) {
        SENDMAIL_RETURN(8, "Cannot connect to sendmail");
    }
    SOCK_SetTimeout(sock, eIO_ReadWrite, &info->mx_timeout);

    /* Follow the protocol conversation, RFC821 */
    if (!SENDMAIL_READ_RESPONSE(220, 0, buffer))
        SENDMAIL_RETURN2(9, "Protocol error in connection init", buffer);

    if ((!(info->mx_options & fSendMail_StripNonFQDNHost)  ||
         !SOCK_gethostbyaddr(0, buffer, sizeof(buffer)))  &&
        SOCK_gethostname(buffer, sizeof(buffer)) != 0) {
        SENDMAIL_RETURN(10, "Unable to get local host name");
    }
    if (!s_SockWrite(sock, "HELO ", 0)  ||
        !s_SockWrite(sock, buffer, 0)   ||
        !s_SockWrite(sock, MX_CRLF, 2)) {
        SENDMAIL_RETURN(11, "Write error in HELO command");
    }
    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
        SENDMAIL_RETURN2(12, "Protocol error in HELO command", buffer);

    if (!s_SockWrite(sock, "MAIL FROM: <", 0)             ||
        !s_SockWrite(sock, info->from, s_FromSize(info))  ||
        !s_SockWrite(sock, ">" MX_CRLF, 1 + 2)) {
        SENDMAIL_RETURN(13, "Write error in MAIL command");
    }
    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
        SENDMAIL_RETURN2(14, "Protocol error in MAIL command", buffer);

    if (to && *to) {
        const char* error = SENDMAIL_SENDRCPT("To", to, buffer);
        if (error)
            return error;
    }

    if (info->cc && *info->cc) {
        const char* error = SENDMAIL_SENDRCPT("Cc", info->cc, buffer);
        if (error)
            return error;
    }

    if (info->bcc && *info->bcc) {
        const char* error = SENDMAIL_SENDRCPT("Bcc", info->bcc, buffer);
        if (error)
            return error;
    }

    if (!s_SockWrite(sock, "DATA" MX_CRLF, 0))
        SENDMAIL_RETURN(15, "Write error in DATA command");
    if (!SENDMAIL_READ_RESPONSE(354, 0, buffer))
        SENDMAIL_RETURN2(16, "Protocol error in DATA command", buffer);

    if (!(info->mx_options & fSendMail_NoMxHeader)) {
        /* Follow RFC822 to compose message headers. Note that
         * 'Date:'and 'From:' are both added by sendmail automagically.
         */ 
        if (!s_SockWrite(sock, "Subject: ", 0)             ||
            (subject  &&  !s_SockWrite(sock, subject, 0))  ||
            !s_SockWrite(sock, MX_CRLF, 2))
            SENDMAIL_RETURN(17, "Write error in sending subject");

        if (to  &&  *to) {
            if (!s_SockWrite(sock, "To: ", 0)              ||
                !s_SockWrite(sock, to, 0)                  ||
                !s_SockWrite(sock, MX_CRLF, 2))
                SENDMAIL_RETURN(18, "Write error in sending To");
        }

        if (info->cc  &&  *info->cc) {
            if (!s_SockWrite(sock, "Cc: ", 0)              ||
                !s_SockWrite(sock, info->cc, 0)            ||
                !s_SockWrite(sock, MX_CRLF, 2))
                SENDMAIL_RETURN(19, "Write error in sending Cc");
        }
    } else if (subject && *subject)
        CORE_LOG_X(2, eLOG_Warning,
                   "[SendMail]  Subject ignored in as-is messages");

    if (!s_SockWrite(sock, "X-Mailer: CORE_SendMail (NCBI "
                     NCBI_SENDMAIL_TOOLKIT " Toolkit)" MX_CRLF, 0)) {
        SENDMAIL_RETURN(20, "Write error in sending mailer information");
    }

    assert(sizeof(buffer) > sizeof(MX_CRLF) && sizeof(MX_CRLF) >= 3);

    if (info->header && *info->header) {
        size_t n = 0, m = strlen(info->header);
        int/*bool*/ newline = 0/*false*/;
        while (n < m) {
            size_t k = 0;
            if (SOCK_Wait(sock, eIO_Read, &zero) != eIO_Timeout)
                break;
            while (k < sizeof(buffer) - sizeof(MX_CRLF)) {
                if (info->header[n] == '\n') {
                    memcpy(&buffer[k], MX_CRLF, sizeof(MX_CRLF) - 1);
                    k += sizeof(MX_CRLF) - 1;
                    newline = 1/*true*/;
                } else {
                    if (info->header[n] != '\r'  ||  info->header[n+1] != '\n')
                        buffer[k++] = info->header[n];
                    newline = 0/*false*/;
                }
                if (++n >= m)
                    break;
            }
            buffer[k] = '\0'/*just in case*/;
            if (!s_SockWrite(sock, buffer, k))
                SENDMAIL_RETURN(21, "Write error while sending custom header");
        }
        if (n < m)
            SENDMAIL_RETURN(22, "Header write error");
        if (!newline && !s_SockWrite(sock, MX_CRLF, 2))
            SENDMAIL_RETURN(23, "Write error while finalizing custom header");
    }

    if (body) {
        size_t n = 0, m = info->body_size ? info->body_size : strlen(body);
        int/*bool*/ newline = 0/*false*/;
        if (!(info->mx_options & fSendMail_NoMxHeader)  &&  m) {
            if (!s_SockWrite(sock, MX_CRLF, 2))
                SENDMAIL_RETURN(24, "Write error in message body delimiter");
        }
        while (n < m) {
            size_t k = 0;
            if (SOCK_Wait(sock, eIO_Read, &zero) != eIO_Timeout)
                break;
            while (k < sizeof(buffer) - sizeof(MX_CRLF)) {
                if (body[n] == '\n') {
                    memcpy(&buffer[k], MX_CRLF, sizeof(MX_CRLF) - 1);
                    k += sizeof(MX_CRLF) - 1;
                    newline = 1/*true*/;
                } else {
                    if (body[n] != '\r'  ||  (n+1 < m  &&  body[n+1] != '\n')){
                        if (body[n] == '.'  &&  (newline  ||  !n)) {
                            buffer[k++] = '.';
                            buffer[k++] = '.';
                        } else
                            buffer[k++] = body[n];
                    }
                    newline = 0/*false*/;
                }
                if (++n >= m)
                    break;
            }
            buffer[k] = '\0'/*just in case*/;
            if (!s_SockWrite(sock, buffer, k))
                SENDMAIL_RETURN(25, "Write error while sending message body");
        }
        if (n < m)
            SENDMAIL_RETURN(26, "Body write error");
        if ((!newline  &&  m  &&  !s_SockWrite(sock, MX_CRLF, 2))
            ||  !s_SockWrite(sock, "." MX_CRLF, 1 + 2)) {
            SENDMAIL_RETURN(27, "Write error while finalizing message body");
        }
    } else if (!s_SockWrite(sock, "." MX_CRLF, 1 + 2))
        SENDMAIL_RETURN(28, "Write error while finalizing message");

    if (!SENDMAIL_READ_RESPONSE(250, 0, buffer))
        SENDMAIL_RETURN2(29, "Protocol error in sending message", buffer);

    if (!s_SockWrite(sock, "QUIT" MX_CRLF, 0))
        SENDMAIL_RETURN(30, "Write error in QUIT command");
    if (!SENDMAIL_READ_RESPONSE(221, 0, buffer))
        SENDMAIL_RETURN2(31, "Protocol error in QUIT command", buffer);

    SOCK_Close(sock);
    return 0;
}