EIO_Status Soaker(const string& url, const string& data, const STimeout* read_tmo, const STimeout* write_tmo) { static const STimeout kZeroTimeout = { 0 }; CConn_HttpStream http(url, fHTTP_AutoReconnect, write_tmo); http.SetTimeout(eIO_Close, read_tmo); http.SetTimeout(eIO_Read, read_tmo); http << data << flush; EIO_Status status = CONN_Wait(http.GetCONN(), eIO_Read, &kZeroTimeout); if (status != eIO_Success) { if (status != eIO_Timeout) return status; status = http.Status(eIO_Write); if (status != eIO_Success) return status; } CWStream null(new CNullWriter, 0, 0, CRWStreambuf::fOwnWriter); NcbiStreamCopy(null, http); status = http.Status(); if (status != eIO_Success && status != eIO_Closed) return status; status = http.Status(eIO_Read); if (status != eIO_Closed) return status; return eIO_Success; }
NLM_EXTERN EIO_Status VecScreenWaitForReply ( CONN conn ) { time_t currtime, starttime; time_t max = 0; EIO_Status status; STimeout timeout; #ifdef OS_MAC EventRecord currEvent; #endif if (conn == NULL) return eIO_Unknown; #ifdef OS_MAC timeout.sec = 0; timeout.usec = 0; #else timeout.sec = 100; timeout.usec = 0; #endif starttime = GetSecs (); while ((status = CONN_Wait (conn, eIO_Read, &timeout)) == eIO_Timeout && max < 300) { currtime = GetSecs (); max = currtime - starttime; #ifdef OS_MAC WaitNextEvent (0, &currEvent, 0, NULL); #endif } return status; }
NLM_EXTERN EIO_Status QUERY_SendQuery ( CONN conn ) { static const STimeout kPollTimeout = { 0 }; EIO_Status status; if (conn == NULL) return eIO_Closed; /* flush buffer, sending query, without waiting for response */ status = CONN_Wait (conn, eIO_Read, &kPollTimeout); return status == eIO_Timeout ? eIO_Success : status; }
NLM_EXTERN Nlm_Int4 QUERY_CheckQueue ( QUEUE* queue ) { static const STimeout kPollTimeout = { 0 }; Nlm_Int4 count = 0; QueuePtr curr; QueuePtr next; QueuePtr PNTR qptr; EIO_Status status; qptr = (QueuePtr PNTR) queue; if (qptr == NULL || *qptr == NULL) return 0; curr = *qptr; while (curr != NULL) { next = curr->next; if (curr->conn != NULL && (! curr->protect)) { status = CONN_Wait (curr->conn, eIO_Read, &kPollTimeout); if (status == eIO_Success || status == eIO_Closed) { /* protect against reentrant calls if resultproc is GUI and processes timer */ curr->protect = TRUE; if (curr->resultproc != NULL) { /* result could eventually be used to reconnect on timeout */ curr->resultproc (curr->conn, curr->userdata, status); } if (curr->closeConn) { CONN_Close (curr->conn); } QUERY_RemoveFromQueue (queue, curr->conn); } else { count++; } } curr = next; } return count; }
EIO_Status CConnTest::ExtraCheckOnFailure(void) { static const STimeout kTimeout = { 5, 0 }; static const STimeout kTimeSlice = { 0, 100000 }; static const struct { const char* host; const char* vhost; } kTests[] = { // 0. NCBI default { "", 0 }, // NCBI // 1. External server(s) { "www.google.com", 0 }, // NB: Google's public DNS (also @8.8.8.8), responds at :80 as well { "8.8.4.4", "www.google.com" }, // 2. NCBI servers, explicitly { "www.be-md.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI main { "www.st-va.ncbi.nlm.nih.gov", "www.ncbi.nlm.nih.gov" }, // NCBI colo { "130.14.29.110", "www.ncbi.nlm.nih.gov" }, // NCBI main { "165.112.7.20", "www.ncbi.nlm.nih.gov" } // NCBI colo }; m_CheckPoint.clear(); PreCheck(eNone, 0/*main*/, "Failback HTTP access check"); SConnNetInfo* net_info = ConnNetInfo_Create(0, eDebugPrintout_Data); if (!net_info) { PostCheck(eNone, 0/*main*/, eIO_Unknown, "Cannot create network info structure"); return eIO_Unknown; } net_info->req_method = eReqMethod_Head; net_info->timeout = &kTimeout; net_info->max_try = 0; m_Timeout = 0; CDeadline deadline(kTimeout.sec, kTimeout.usec * 1000); time_t sec; unsigned int nanosec; deadline.GetExpirationTime(&sec, &nanosec); ::sprintf(net_info->path, "/NcbiTest%08lX%08lX", (unsigned long) sec, (unsigned long) nanosec); vector< AutoPtr<CConn_HttpStream> > http; for (size_t n = 0; n < sizeof(kTests) / sizeof(kTests[0]); ++n) { char user_header[80]; _ASSERT(::strlen(kTests[n].host) < sizeof(net_info->host) - 1); if (kTests[n].host[0]) ::strcpy(net_info->host, kTests[n].host); if (kTests[n].vhost) { _ASSERT(::strlen(kTests[n].vhost) + 6 < sizeof(user_header) - 1); ::sprintf(user_header, "Host: %s", kTests[n].vhost); } else *user_header = '\0'; SAuxData* auxdata = new SAuxData(m_Canceled, 0); http.push_back(new CConn_HttpStream(net_info, user_header, s_AnyHeader, auxdata, s_Adjust, s_Cleanup)); http.back()->SetCanceledCallback(m_Canceled); } EIO_Status status = eIO_Success; do { if (!http.size()) break; ERASE_ITERATE(vector< AutoPtr<CConn_HttpStream> >, h, http) { CONN conn = (*h)->GetCONN(); if (!conn) { VECTOR_ERASE(h, http); if (status == eIO_Success) status = eIO_Unknown; continue; } EIO_Status readst = CONN_Wait(conn, eIO_Read, &kTimeSlice); if (readst > eIO_Timeout) { if (readst == eIO_Interrupt) { status = eIO_Interrupt; break; } if (status < readst && (*h)->GetStatusCode() != 404) status = readst; VECTOR_ERASE(h, http); continue; } } } while (status != eIO_Interrupt && !deadline.IsExpired()); if (status == eIO_Success && http.size()) status = eIO_Timeout; PostCheck(eNone, 0/*main*/, status, kEmptyStr); return status; }
void CONN_TestConnector (CONNECTOR connector, const STimeout* timeout, FILE* data_file, TTestConnFlags flags) { EIO_Status status; SConnector dummy; CONN conn; memset(&dummy, 0, sizeof(dummy)); TEST_LOG(eIO_Success, "[CONN_TestConnector] Starting..."); /* Fool around with dummy connector / connection */ assert(CONN_Create(0, &conn) != eIO_Success && !conn); assert(CONN_Create(&dummy, &conn) != eIO_Success && !conn); dummy.setup = s_DummySetup; assert(CONN_Create(&dummy, &conn) == eIO_Success); assert(CONN_Flush (conn) != eIO_Success); assert(CONN_ReInit(conn, 0) == eIO_Success); assert(CONN_ReInit(conn, 0) != eIO_Success); assert(CONN_ReInit(conn, &dummy) == eIO_Success); assert(CONN_Flush (conn) != eIO_Success); assert(CONN_ReInit(conn, &dummy) == eIO_Success); assert(CONN_ReInit(conn, 0) == eIO_Success); assert(CONN_Close (conn) == eIO_Success); /* CREATE new connection on the base of the connector, set * TIMEOUTs, try to RECONNECT, WAIT for the connection is writable */ assert(CONN_Create(connector, &conn) == eIO_Success); assert(CONN_SetTimeout(conn, eIO_Open, timeout) == eIO_Success); assert(CONN_SetTimeout(conn, eIO_ReadWrite, timeout) == eIO_Success); assert(CONN_SetTimeout(conn, eIO_Close, timeout) == eIO_Success); assert(CONN_ReInit(conn, connector) == eIO_Success); status = CONN_Wait(conn, eIO_Write, timeout); if (status != eIO_Success) { TEST_LOG(status, "[CONN_TestConnector] CONN_Wait(write) failed"); assert(status == eIO_Timeout); } /* Run the specified TESTs */ if ( !flags ) { flags = fTC_Everything; } if (flags & fTC_SingleBouncePrint) { s_SingleBouncePrint(conn, data_file); } if (flags & fTC_MultiBouncePrint) { s_MultiBouncePrint(conn, data_file); } if (flags & fTC_SingleBounceCheck) { s_SingleBounceCheck(conn, timeout, data_file); } /* And CLOSE the connection... */ assert(CONN_Close(conn) == eIO_Success); TEST_LOG(eIO_Success, "[CONN_TestConnector] Completed"); }
static void s_SingleBounceCheck (CONN conn, const STimeout* timeout, FILE* data_file) { static const char sym[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' }; EIO_Status status; char message[128]; #define TEST_N_LINES 200 #define TEST_BUF_SIZE (TEST_N_LINES * (TEST_N_LINES + 3) / 2) char buf[TEST_BUF_SIZE]; TEST_LOG(eIO_Success, "[s_SingleBounceCheck] Starting..."); /* WRITE to the connection: "0\n12\n345\n6789\n01234\n........" */ {{ size_t k = 0, j = 0; size_t i; for (i = 0; k != sizeof(buf); i++) { /* prepare output data */ size_t n_write, n_written; for (n_write = 0; n_write < i; n_write++, k++) { assert(k < sizeof(buf)); buf[n_write] = sym[j++ % sizeof(sym)]; } assert(k < sizeof(buf)); if ( n_write ) { buf[n_write++] = '\n'; k++; } buf[n_write] = '\0'; do { /* persistently */ /* WAIT... sometimes */ if (n_write % 5 == 3) { status = CONN_Wait(conn, eIO_Write, timeout); if (status != eIO_Success) { TEST_LOG(status, "[s_SingleBounceCheck] CONN_Wait(write)" " failed, retrying..."); assert(status == eIO_Timeout); } } /* WRITE */ status = CONN_Write(conn, buf, n_write, &n_written, eIO_WritePersist); if (status != eIO_Success) { TEST_LOG(status, "[s_SingleBounceCheck] CONN_Write(persistent)" " failed, retrying..."); assert(n_written < n_write); assert(status == eIO_Timeout); } else { assert(n_written == n_write); } } while (status != eIO_Success); } }} /* READ the "bounced" data from the connection, the first TEST_BUF_SIZE * bytes must be: "0\n12\n345\n6789\n01234\n........" */ {{ char* x_buf; size_t n_read, n_to_read; memset(buf, '\0', TEST_BUF_SIZE); /* PEEK until the 1st 1/3 of the "bounced" data is available */ x_buf = buf; n_to_read = TEST_BUF_SIZE/3; do { TEST_LOG(eIO_Success, "[s_SingleBounceCheck] 1/3 PEEK..."); status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPeek); if (status != eIO_Success) { TEST_LOG(status, "[s_SingleBounceCheck] 1/3 CONN_Read(peek)" " failed, retrying..."); assert(n_read < n_to_read); assert(status == eIO_Timeout); } if (n_read < n_to_read) { sprintf(message, "[s_SingleBounceCheck] 1/3 CONN_Read(peek)" " %lu byte%s peeked out of %lu byte%s, continuing...", (unsigned long) n_read, &"s"[n_read == 1], (unsigned long) n_to_read, &"s"[n_to_read == 1]); TEST_LOG(status, message); } } while (n_read != n_to_read); /* READ 1st 1/3 of "bounced" data, compare it with the PEEKed data */ TEST_LOG(eIO_Success, "[s_SingleBounceCheck] 1/3 READ..."); status = CONN_Read(conn, x_buf + n_to_read, n_to_read, &n_read, eIO_ReadPlain); if (status != eIO_Success) { TEST_LOG(status, "[s_SingleBounceCheck] 1/3 CONN_Read(plain) failed"); } assert(status == eIO_Success); assert(n_read == n_to_read); assert(memcmp(x_buf, x_buf + n_to_read, n_to_read) == 0); memset(x_buf + n_to_read, '\0', n_to_read); /* WAIT on read */ status = CONN_Wait(conn, eIO_Read, timeout); if (status != eIO_Success) { TEST_LOG(status, "[s_SingleBounceCheck] CONN_Wait(read) failed"); assert(status == eIO_Timeout); } /* READ the 2nd 1/3 of "bounced" data */ x_buf = buf + TEST_BUF_SIZE/3; n_to_read = TEST_BUF_SIZE/3; while ( n_to_read ) { TEST_LOG(eIO_Success, "[s_SingleBounceCheck] 2/3 READ..."); status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPlain); if (status != eIO_Success) { sprintf(message, "[s_SingleBounceCheck] 2/3 CONN_Read(plain)" " %lu byte%s read out of %lu byte%s, retrying...", (unsigned long) n_read, &"s"[n_read == 1], (unsigned long) n_to_read, &"s"[n_to_read == 1]); TEST_LOG(status, message); assert(n_read < n_to_read); assert(status == eIO_Timeout); } else { assert(n_read <= n_to_read); } n_to_read -= n_read; x_buf += n_read; } assert(status == eIO_Success); /* Persistently READ the 3rd 1/3 of "bounced" data */ n_to_read = TEST_BUF_SIZE - (x_buf - buf); TEST_LOG(eIO_Success, "[s_SingleBounceCheck] 3/3 READ..."); status = CONN_Read(conn, x_buf, n_to_read, &n_read, eIO_ReadPersist); if (status != eIO_Success) { sprintf(message, "[s_SingleBounceCheck] 3/3 CONN_Read(persistent)" " %lu byte%s read", (unsigned long) n_read, &"s"[n_read == 1]); TEST_LOG(status, message); assert(n_read < n_to_read); assert(0); } else { assert(n_read == n_to_read); } }} /* Check for the received "bounced" data is identical to the sent data */ {{ const char* x_buf = buf; size_t k = 0, j = 0; size_t i; for (i = 1; k != sizeof(buf); i++) { size_t n; for (n = 0; n < i; n++, k++) { if (k == sizeof(buf)) break; assert(*x_buf++ == sym[j++ % sizeof(sym)]); } assert(*x_buf++ == '\n'); k++; } }} /* Now when the "bounced" data is read and tested, READ an arbitrary extra * data sent in by the peer and print it out to LOG file */ if ( data_file ) { fprintf(data_file, "\ns_SingleBounceCheck(BEGIN EXTRA DATA)\n"); fflush(data_file); for (;;) { size_t n; TEST_LOG(eIO_Success, "[s_SingleBounceCheck] EXTRA READ..."); status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPersist); TEST_LOG(status, "[s_SingleBounceCheck] EXTRA CONN_Read(persistent)"); if ( n ) { assert(fwrite(buf, n, 1, data_file) == 1); fflush(data_file); } if (status == eIO_Closed || status == eIO_Timeout) break; /* okay */ assert(status == eIO_Success); } fprintf(data_file, "\ns_SingleBounceCheck(END EXTRA DATA)\n\n"); fflush(data_file); } TEST_LOG(eIO_Success, "[s_SingleBounceCheck] ...finished"); }
int main(int argc, const char* argv[]) { const char* service = argc > 1 && *argv[1] ? argv[1] : "bounce"; static char obuf[8192 + 2]; SConnNetInfo* net_info; CONNECTOR connector; EIO_Status status; char ibuf[1024]; CONN conn; size_t n; setlocale(LC_ALL, ""); g_NCBI_ConnectRandomSeed = (int) time(0) ^ NCBI_CONNECT_SRAND_ADDEND; srand(g_NCBI_ConnectRandomSeed); CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); net_info = ConnNetInfo_Create(service); ConnNetInfo_AppendArg(net_info, "testarg", "val"); ConnNetInfo_AppendArg(net_info, "service", "none"); ConnNetInfo_AppendArg(net_info, "platform", "none"); ConnNetInfo_AppendArg(net_info, "address", "2010"); ConnNetInfo_Log(net_info, eLOG_Note, CORE_GetLOG()); connector = SERVICE_CreateConnectorEx(service, fSERV_Any, net_info, 0); if (!connector) CORE_LOG(eLOG_Fatal, "Failed to create service connector"); if (CONN_Create(connector, &conn) != eIO_Success) CORE_LOG(eLOG_Fatal, "Failed to create connection"); if (argc > 2) { strncpy0(obuf, argv[2], sizeof(obuf) - 2); obuf[n = strlen(obuf)] = '\n'; obuf[++n] = '\0'; if (CONN_Write(conn, obuf, strlen(obuf), &n, eIO_WritePersist) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to connection"); } assert(n == strlen(obuf)); } else { for (n = 0; n < 10; n++) { size_t m; for (m = 0; m < sizeof(obuf) - 2; m++) obuf[m] = "0123456789\n"[rand() % 11]; obuf[m++] = '\n'; obuf[m] = '\0'; if (CONN_Write(conn, obuf, strlen(obuf), &m, eIO_WritePersist) != eIO_Success) { if (!n) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to connection"); } else break; } assert(m == strlen(obuf)); } } for (;;) { if (CONN_Wait(conn, eIO_Read, net_info->timeout) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Failed to wait for reading"); } status = CONN_Read(conn, ibuf, sizeof(ibuf), &n, eIO_ReadPersist); if (n) { char* descr = CONN_Description(conn); CORE_DATAF(eLOG_Note, ibuf, n, ("%lu bytes read from service (%s%s%s):", (unsigned long) n, CONN_GetType(conn), descr ? ", " : "", descr ? descr : "")); if (descr) free(descr); } if (status != eIO_Success) { if (status != eIO_Closed) CORE_LOGF(n ? eLOG_Error : eLOG_Fatal, ("Read error: %s", IO_StatusStr(status))); break; } } ConnNetInfo_Destroy(net_info); CONN_Close(conn); #if 0 CORE_LOG(eLOG_Note, "Trying ID1 service"); net_info = ConnNetInfo_Create(service); connector = SERVICE_CreateConnectorEx("ID1", fSERV_Any, net_info); ConnNetInfo_Destroy(net_info); if (!connector) CORE_LOG(eLOG_Fatal, "Service ID1 not available"); if (CONN_Create(connector, &conn) != eIO_Success) CORE_LOG(eLOG_Fatal, "Failed to create connection"); if (CONN_Write(conn, "\xA4\x80\x02\x01\x02\x00", 7, &n, eIO_WritePersist) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot write to service ID1"); } assert(n == 7); if (CONN_Read(conn, ibuf, sizeof(ibuf), &n, eIO_ReadPlain) != eIO_Success){ CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Cannot read from service ID1"); } CORE_LOGF(eLOG_Note, ("%d bytes read from service ID1", n)); CONN_Close(conn); #endif CORE_LOG(eLOG_Note, "TEST completed successfully"); CORE_SetLOG(0); return 0/*okay*/; }
streamsize CConn_Streambuf::showmanyc(void) { static const STimeout kZeroTmo = {0, 0}; _ASSERT(gptr() >= egptr()); if (!m_Conn) return -1L; // flush output buffer, if tied up to it if (m_Tie) x_sync(); const STimeout* tmo; const STimeout* timeout = CONN_GetTimeout(m_Conn, eIO_Read); if (timeout == kDefaultTimeout) { // HACK * HACK * HACK tmo = ((SMetaConnector*) m_Conn)->default_timeout; } else tmo = timeout; size_t x_read; bool backup = false; if (m_BufSize > 1) { if (eback() < gptr()) { x_Buf = gptr()[-1]; backup = true; } if (!tmo) _VERIFY(CONN_SetTimeout(m_Conn, eIO_Read, &kZeroTmo)==eIO_Success); m_Status = CONN_Read(m_Conn, m_ReadBuf + 1, m_BufSize - 1, &x_read, eIO_ReadPlain); if (!tmo) _VERIFY(CONN_SetTimeout(m_Conn, eIO_Read, timeout) ==eIO_Success); _ASSERT(x_read > 0 || m_Status != eIO_Success); } else { m_Status = CONN_Wait(m_Conn, eIO_Read, tmo ? tmo : &kZeroTmo); x_read = 0; } if (!x_read) { switch (m_Status) { case eIO_Success: _ASSERT(m_BufSize <= 1); return 1L; // can read at least 1 byte case eIO_Timeout: if (!tmo || !(tmo->sec | tmo->usec)) break; /*FALLTHRU*/ case eIO_Closed: return -1L; // EOF default: break; } return 0; // no data available immediately } m_ReadBuf[0] = x_Buf; _ASSERT(m_BufSize > 1); setg(m_ReadBuf + !backup, m_ReadBuf + 1, m_ReadBuf + 1 + x_read); x_GPos += x_read; return x_read; }