uint8_t SOCK_Socket(uint8_t sock, uint8_t eth_protocol, uint16_t tcp_port) { uint8_t val, retval = 0; if (sock!=0) { return retval; } /* Make sure we close the socket first */ if (W5100_MemReadByte(W5100_S0_SR, &val)!=ERR_OK) { return 0; /* failure */ } if (val==W5100_SOCK_CLOSED) { SOCK_Close(sock); } /* Assigned Socket 0 Mode Register */ W5100_MemWriteByte(W5100_S0_MR, eth_protocol); /* Now open the Socket 0 */ W5100_MemWriteWord(W5100_S0_PORT, tcp_port); W5100_MemWriteByte(W5100_S0_CR, W5100_CR_OPEN); /* Open Socket */ /* Wait for Opening Process */ do { W5100_MemReadByte(W5100_S0_CR, &val); } while(val!=0); /* Check for Init Status */ W5100_MemReadByte(W5100_S0_SR, &val); if (val==W5100_SOCK_INIT) { retval = 1; } else { SOCK_Close(sock); } return retval; }
EIO_Status CListeningSocket::Accept(CSocket*& sock, const STimeout* timeout, TSOCK_Flags flags) const { if ( !m_Socket ) { sock = 0; return eIO_Closed; } SOCK x_sock; EIO_Status status; status = LSOCK_AcceptEx(m_Socket, timeout, &x_sock, flags); assert(!x_sock ^ !(status != eIO_Success)); if (status == eIO_Success) { try { sock = new CSocket; } catch (...) { sock = 0; SOCK_Abort(x_sock); SOCK_Close(x_sock); throw; } sock->Reset(x_sock, eTakeOwnership, eCopyTimeoutsToSOCK); } else sock = 0; 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 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 Int2 s_ServiceDisconnect(NI_HandPtr mhp) { s_EndServices(mhp->disp); SOCK_Close((SOCK)mhp->extra_proc_info); AsnIoClose(mhp->raip); AsnIoClose(mhp->waip); MemFree(mhp->hostname); MemFree(mhp); return 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; }
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; }
/* 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"); }
uint8_t SOCK_Listen(uint8_t sock) { uint8_t val, retval = 0; if (sock!=0) { return retval; } W5100_MemReadByte(W5100_S0_SR, &val); if (val==W5100_SOCK_INIT) { /* Send the LISTEN Command */ W5100_MemWriteByte(W5100_S0_CR, W5100_CR_LISTEN); /* Wait for Listening Process */ do { W5100_MemReadByte(W5100_S0_CR, &val); } while(val!=0); /* Check for Listen Status */ W5100_MemReadByte(W5100_S0_SR, &val); if (val==W5100_SOCK_LISTEN) { retval = 1; } else { SOCK_Close(sock); } } return retval; }
CSocket::~CSocket() { if (m_Socket && m_IsOwned != eNoOwnership) SOCK_Close(m_Socket); }
static CConn_IOStream::TConn_Pair s_SocketConnectorBuilder(const SConnNetInfo* net_info, const STimeout* timeout, const void* data, size_t size, TSOCK_Flags flags) { EIO_Status status = eIO_Success; bool proxy = false; SOCK sock = 0; _ASSERT(net_info); if ((flags & (fSOCK_LogOn | fSOCK_LogDefault)) == fSOCK_LogDefault && net_info->debug_printout == eDebugPrintout_Data) { flags &= ~fSOCK_LogDefault; flags |= fSOCK_LogOn; } if (*net_info->http_proxy_host && net_info->http_proxy_port) { status = HTTP_CreateTunnel(net_info, fHTTP_NoAutoRetry, &sock); _ASSERT(!sock ^ !(status != eIO_Success)); if (status == eIO_Success && ((flags & ~(fSOCK_LogOn | fSOCK_LogDefault)) || size)) { SOCK s; status = SOCK_CreateOnTopEx(sock, 0, &s, data, size, flags); _ASSERT(!s ^ !(status != eIO_Success)); SOCK_Destroy(sock); sock = s; } proxy = true; } if (!sock && (!proxy || net_info->http_proxy_leak)) { const char* host = (net_info->firewall && *net_info->proxy_host ? net_info->proxy_host : net_info->host); if (timeout == kDefaultTimeout) timeout = net_info->timeout; if (!proxy && net_info->debug_printout) { SConnNetInfo* x_net_info = ConnNetInfo_Clone(net_info); if (x_net_info) { x_net_info->req_method = eReqMethod_Any; x_net_info->stateless = 0; x_net_info->lb_disable = 0; x_net_info->http_proxy_host[0] = '\0'; x_net_info->http_proxy_port = 0; x_net_info->http_proxy_user[0] = '\0'; x_net_info->http_proxy_pass[0] = '\0'; x_net_info->proxy_host[0] = '\0'; ConnNetInfo_SetUserHeader(x_net_info, 0); if (x_net_info->http_referer) { free((void*) x_net_info->http_referer); x_net_info->http_referer = 0; } x_net_info->timeout = timeout; } ConnNetInfo_Log(x_net_info, eLOG_Note, CORE_GetLOG()); ConnNetInfo_Destroy(x_net_info); } status = SOCK_CreateEx(host, net_info->port, timeout, &sock, data, size, flags); _ASSERT(!sock ^ !(status != eIO_Success)); } string hostport(net_info->host); hostport += ':'; hostport += NStr::UIntToString(net_info->port); CONNECTOR c = SOCK_CreateConnectorOnTopEx(sock, 1/*own*/, hostport.c_str()); if (!c) { SOCK_Abort(sock); SOCK_Close(sock); status = eIO_Unknown; } return CConn_IOStream::TConn_Pair(c, status); }
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__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); }
int main(int argc, char** argv) { /* Prepare to connect: parse and check cmd.-line args, etc. */ const char* host = argc > 1 ? argv[1] : ""; unsigned short port = argc > 2 ? atoi(argv[2]) : CONN_PORT_HTTP; const char* path = argc > 3 ? argv[3] : ""; const char* args = argc > 4 ? argv[4] : ""; const char* inp_file = argc > 5 ? argv[5] : ""; const char* user_header = argc > 6 ? argv[6] : ""; size_t content_length; STimeout timeout; SOCK sock; EIO_Status status; char buffer[10000]; CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); SOCK_SetupSSL(NcbiSetupTls); fprintf(stderr, "Running...\n" " Executable: '%s'\n" " URL host: '%s'\n" " URL port: %hu\n" " URL path: '%s'\n" " URL args: '%s'\n" " Input data file: '%s'\n" " User header: '%s'\n" "Response(if any) from the hit URL goes to standard output.\n\n", argv[0], host, port, path, args, inp_file, user_header); if ( argc < 4 ) { fprintf(stderr, "Usage: %s host port path args inp_file [user_header]\n", argv[0]); CORE_LOG(eLOG_Fatal, "Two few arguments"); return 1; } {{ FILE *fp = fopen(inp_file, "rb"); long offset; if ( !fp ) { CORE_LOGF(eLOG_Fatal, ("Non-existent file '%s'", inp_file)); return 2; } if ( fseek(fp, 0, SEEK_END) != 0 || (offset = ftell(fp)) < 0 ) { CORE_LOGF(eLOG_Fatal, ("Cannot obtain size of file '%s'", inp_file)); return 2; } fclose(fp); content_length = (size_t) offset; }} timeout.sec = 10; timeout.usec = 0; /* Connect */ sock = URL_Connect(host, port, path, args, /*NCBI_FAKE_WARNING*/ eReqMethod_Any, content_length, &timeout, &timeout, user_header, 1/*true*/, port == CONN_PORT_HTTPS ? fSOCK_LogDefault | fSOCK_Secure : fSOCK_LogDefault); if ( !sock ) return 3; {{ /* Pump data from the input file to socket */ FILE* fp = fopen(inp_file, "rb"); if ( !fp ) { CORE_LOGF(eLOG_Fatal, ("Cannot open file '%s' for reading", inp_file)); return 4; } for (;;) { size_t n_written; size_t n_read = fread(buffer, 1, sizeof(buffer), fp); if ( n_read <= 0 ) { if ( content_length ) { CORE_LOGF(eLOG_Fatal, ("Cannot read last %lu bytes from file '%s'", (unsigned long) content_length, inp_file)); return 5; } break; } assert(content_length >= n_read); content_length -= n_read; status = SOCK_Write(sock, buffer, n_read, &n_written, eIO_WritePersist); if ( status != eIO_Success ) { CORE_LOGF(eLOG_Fatal, ("Error writing to socket: %s", IO_StatusStr(status))); return 6; } } fclose(fp); }} /* Read reply from socket, write it to STDOUT */ {{ size_t n_read; for (;;) { status = SOCK_Read(sock, buffer, sizeof(buffer), &n_read, eIO_ReadPlain); if (status != eIO_Success) break; fwrite(buffer, 1, n_read, stdout); } if ( status != eIO_Closed ) { CORE_LOGF(eLOG_Error, ("Read error after %ld byte(s) from socket: %s", (long) content_length, IO_StatusStr(status))); } fprintf(stdout, "\n"); }} /* Success: close the socket, cleanup, and exit */ SOCK_Close(sock); CORE_LOG(eLOG_Note, "TEST completed successfully"); CORE_SetLOG(0); return 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; }