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; }
static EIO_Status s_VT_Status (CONNECTOR connector, EIO_Event dir) { SHttpConnector* uuu = (SHttpConnector*) connector->handle; return uuu->sock ? SOCK_Status(uuu->sock, dir) : (uuu->can_connect == eCC_None ? eIO_Closed : eIO_Success); }
static EIO_Status s_VT_Status (CONNECTOR connector, EIO_Event dir) { SSockConnector* xxx = (SSockConnector*) connector->handle; assert(xxx->sock); return SOCK_Status(xxx->sock, dir); }
/* Read non-header data from connection */ static EIO_Status s_Read(SHttpConnector* uuu, void* buf, size_t size, size_t* n_read) { EIO_Status status; assert(uuu->sock); if (uuu->flags & fHCC_UrlDecodeInput) { /* read and URL-decode */ size_t n_peeked, n_decoded; size_t peek_size = 3 * size; void* peek_buf = malloc(peek_size); /* peek the data */ status= SOCK_Read(uuu->sock,peek_buf,peek_size,&n_peeked,eIO_ReadPeek); if (status != eIO_Success) { assert(!n_peeked); *n_read = 0; } else { if (URL_Decode(peek_buf,n_peeked,&n_decoded,buf,size,n_read)) { /* decode, then discard successfully decoded data from input */ if (n_decoded) { SOCK_Read(uuu->sock,0,n_decoded,&n_peeked,eIO_ReadPersist); assert(n_peeked == n_decoded); uuu->received += n_decoded; status = eIO_Success; } else if (SOCK_Status(uuu->sock, eIO_Read) == eIO_Closed) { /* we are at EOF, and remaining data cannot be decoded */ status = eIO_Unknown; } } else status = eIO_Unknown; if (status != eIO_Success) CORE_LOG_X(16, eLOG_Error, "[HTTP] Cannot URL-decode data"); } free(peek_buf); } else { /* just read, with no URL-decoding */ status = SOCK_Read(uuu->sock, buf, size, n_read, eIO_ReadPlain); uuu->received += *n_read; } if (uuu->expected) { if (uuu->received > uuu->expected) return eIO_Unknown/*received too much*/; if (uuu->expected != (size_t)(-1L)) { if (status == eIO_Closed && uuu->expected > uuu->received) return eIO_Unknown/*received too little*/; } else if (uuu->received) return eIO_Unknown/*received too much*/; } return status; }
/* 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; }
static void TEST__client_1(SOCK sock) { EIO_Status status; size_t n_io, n_io_done; char buf[TEST_BUFSIZE]; CORE_LOG(eLOG_Note, "TEST__client_1(TC1)"); /* Send a short string */ SOCK_SetDataLoggingAPI(eOn); {{ const char* x_C1 = s_C1; n_io = strlen(x_C1) + 1; status = SOCK_Write(sock, x_C1, n_io, &n_io_done, eIO_WritePersist); }} assert(status == eIO_Success && n_io == n_io_done); /* Read the string back (it must be bounced by the server) */ SOCK_SetDataLoggingAPI(eOff); SOCK_SetDataLogging(sock, eOn); n_io = strlen(s_S1) + 1; status = SOCK_Read(sock, buf, n_io, &n_io_done, eIO_ReadPeek); status = SOCK_Read(sock, buf, n_io, &n_io_done, eIO_ReadPlain); if (status == eIO_Closed) CORE_LOG(eLOG_Fatal, "TC1:: connection closed"); assert(status == eIO_Success && n_io == n_io_done); assert(strcmp(buf, s_S1) == 0); assert(SOCK_PushBack(sock, buf, n_io_done) == eIO_Success); memset(buf, '\xFF', n_io_done); assert(SOCK_Read(sock, buf, n_io_done, &n_io_done, eIO_ReadPlain) == eIO_Success); assert(SOCK_Status(sock, eIO_Read) == eIO_Success); assert(strcmp(buf, s_S1) == 0); SOCK_SetDataLogging(sock, eDefault); /* Send a very big binary blob */ {{ size_t i; unsigned char* blob = (unsigned char*) malloc(BIG_BLOB_SIZE); for (i = 0; i < BIG_BLOB_SIZE; blob[i] = (unsigned char) i, i++) continue; for (i = 0; i < 10; i++) { status = SOCK_Write(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, &n_io_done, eIO_WritePersist); assert(status == eIO_Success && n_io_done==SUB_BLOB_SIZE); } free(blob); }} /* Send a very big binary blob with read on write */ /* (it must be bounced by the server) */ {{ size_t i; unsigned char* blob = (unsigned char*) malloc(BIG_BLOB_SIZE); SOCK_SetReadOnWrite(sock, eOn); for (i = 0; i < BIG_BLOB_SIZE; blob[i] = (unsigned char) i, i++) continue; for (i = 0; i < 10; i++) { status = SOCK_Write(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, &n_io_done, eIO_WritePersist); assert(status == eIO_Success && n_io_done == SUB_BLOB_SIZE); } /* Receive back a very big binary blob, and check its content */ memset(blob,0,BIG_BLOB_SIZE); for (i = 0; i < 10; i++) { status = SOCK_Read(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, &n_io_done, eIO_ReadPersist); assert(status == eIO_Success && n_io_done == SUB_BLOB_SIZE); } for (n_io = 0; n_io < BIG_BLOB_SIZE; n_io++) assert(blob[n_io] == (unsigned char) n_io); free(blob); }} /* Try to read more data (must hit EOF as the peer is shut down) */ assert(SOCK_Read(sock, buf, 1, &n_io_done, eIO_ReadPeek) == eIO_Closed); assert(SOCK_Status(sock, eIO_Read) == eIO_Closed); assert(SOCK_Read(sock, buf, 1, &n_io_done, eIO_ReadPlain) == eIO_Closed); assert(SOCK_Status(sock, eIO_Read) == eIO_Closed); /* Shutdown on read */ assert(SOCK_Shutdown(sock, eIO_Read) == eIO_Success); assert(SOCK_Status (sock, eIO_Write) == eIO_Success); assert(SOCK_Status (sock, eIO_Read) == eIO_Closed); assert(SOCK_Read (sock, 0, 0, &n_io_done, eIO_ReadPlain) == eIO_Closed); assert(SOCK_Read (sock, 0, 0, &n_io_done, eIO_ReadPeek) == eIO_Closed); assert(SOCK_Status (sock, eIO_Read) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Success); assert(SOCK_Read (sock, buf, 1,&n_io_done,eIO_ReadPlain) == eIO_Closed); assert(SOCK_Read (sock, buf, 1,&n_io_done,eIO_ReadPeek) == eIO_Closed); assert(SOCK_Status (sock, eIO_Read) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Success); /* Shutdown on write */ assert(SOCK_Shutdown(sock, eIO_Write) == eIO_Success); assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); assert(SOCK_Write (sock, 0, 0, &n_io_done, eIO_WritePersist) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); assert(SOCK_Write (sock, buf, 1, &n_io_done, eIO_WritePersist) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); /* Double shutdown should be okay */ assert(SOCK_Shutdown(sock, eIO_Read) == eIO_Success); assert(SOCK_Shutdown(sock, eIO_ReadWrite) == eIO_Success); assert(SOCK_Shutdown(sock, eIO_Write) == eIO_Success); assert(SOCK_Status (sock, eIO_Read) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); assert(SOCK_Status (sock, eIO_ReadWrite) == eIO_InvalidArg); }
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; } } }
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); } }
static void TEST__server_1(SOCK sock) { EIO_Status status; size_t n_io, n_io_done; char buf[TEST_BUFSIZE]; CORE_LOG(eLOG_Note, "TEST__server_1(TS1)"); /* Receive and send back a short string */ SOCK_SetDataLogging(sock, eOn); n_io = strlen(s_C1) + 1; status = SOCK_Read(sock, buf, n_io, &n_io_done, eIO_ReadPlain); assert(status == eIO_Success && n_io == n_io_done); assert(strcmp(buf, s_C1) == 0 || strcmp(buf, s_M1) == 0); SOCK_SetDataLogging(sock, eDefault); SOCK_SetDataLoggingAPI(eOn); n_io = strlen(s_S1) + 1; status = SOCK_Write(sock, s_S1, n_io, &n_io_done, eIO_WritePersist); assert(status == eIO_Success && n_io == n_io_done); SOCK_SetDataLoggingAPI(eOff); /* Receive a very big binary blob, and check its content */ {{ #define DO_LOG_SIZE 300 #define DONT_LOG_SIZE BIG_BLOB_SIZE - DO_LOG_SIZE unsigned char* blob = (unsigned char*) malloc(BIG_BLOB_SIZE); status = SOCK_Read(sock,blob,DONT_LOG_SIZE,&n_io_done,eIO_ReadPersist); assert(status == eIO_Success && n_io_done == DONT_LOG_SIZE); SOCK_SetDataLogging(sock, eOn); status = SOCK_Read(sock, blob + DONT_LOG_SIZE, DO_LOG_SIZE, &n_io_done, eIO_ReadPersist); assert(status == eIO_Success && n_io_done == DO_LOG_SIZE); SOCK_SetDataLogging(sock, eDefault); for (n_io = 0; n_io < BIG_BLOB_SIZE; n_io++) assert(blob[n_io] == (unsigned char) n_io); free(blob); }} /* Receive a very big binary blob, and write data back */ {{ unsigned char* blob = (unsigned char*) malloc(BIG_BLOB_SIZE); int i; for (i = 0; i < 10; i++) { /* X_SLEEP(1);*/ status = SOCK_Read(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, &n_io_done, eIO_ReadPersist); assert(status == eIO_Success && n_io_done == SUB_BLOB_SIZE); status = SOCK_Write(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, &n_io_done, eIO_WritePersist); assert(status == eIO_Success && n_io_done == SUB_BLOB_SIZE); } for (n_io = 0; n_io < BIG_BLOB_SIZE; n_io++) assert(blob[n_io] == (unsigned char) n_io); free(blob); }} /* Shutdown on write */ #ifdef NCBI_OS_MSWIN assert(SOCK_Shutdown(sock, eIO_ReadWrite) == eIO_Success); #else assert(SOCK_Shutdown(sock, eIO_Write) == eIO_Success); #endif assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); assert(SOCK_Write (sock, 0, 0, &n_io_done, eIO_WritePersist) == eIO_Closed); assert(SOCK_Status (sock, eIO_Write) == eIO_Closed); #ifdef NCBI_OS_MSWIN assert(SOCK_Status (sock, eIO_Read) == eIO_Closed); #else assert(SOCK_Status (sock, eIO_Read) == eIO_Success); #endif assert(SOCK_Close (sock) == eIO_Success); }