diff options
Diffstat (limited to 'connect')
51 files changed, 2917 insertions, 2688 deletions
diff --git a/connect/ncbi_ansi_ext.h b/connect/ncbi_ansi_ext.h index 4f4a60a9..82b985b4 100644 --- a/connect/ncbi_ansi_ext.h +++ b/connect/ncbi_ansi_ext.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_ANSI_EXT__H #define CONNECT___NCBI_ANSI_EXT__H -/* $Id: ncbi_ansi_ext.h,v 6.12 2004/03/12 23:25:37 gorelenk Exp $ +/* $Id: ncbi_ansi_ext.h,v 6.13 2005/04/20 18:12:16 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -54,7 +54,7 @@ extern "C" { * Return an identical malloc'ed string, which must be explicitly freed * by free() when no longer needed. */ -extern char* strdup(const char* str); +extern NCBI_XCONNECT_EXPORT char* strdup(const char* str); #endif /*HAVE_STRDUP*/ @@ -120,6 +120,9 @@ extern NCBI_XCONNECT_EXPORT char* strncpy0(char* s1, const char* s2, size_t n); /* * -------------------------------------------------------------------------- * $Log: ncbi_ansi_ext.h,v $ + * Revision 6.13 2005/04/20 18:12:16 lavr + * strdup() has got NCBI_XCONNECT_EXPORT + * * Revision 6.12 2004/03/12 23:25:37 gorelenk * Added export prefixes. * diff --git a/connect/ncbi_assert.h b/connect/ncbi_assert.h new file mode 100644 index 00000000..5bf02e5d --- /dev/null +++ b/connect/ncbi_assert.h @@ -0,0 +1,67 @@ +#ifndef CONNECT___NCBI_ASSERT__H +#define CONNECT___NCBI_ASSERT__H + +/* $Id: ncbi_assert.h,v 1.1 2005/04/20 18:11:23 lavr Exp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * Run-time debugging + */ + +#include "ncbi_config.h" + +#if defined(verify) +#undef verify +#endif + +#if !defined(NDEBUG) && !defined(_DEBUG) +# define NDEBUG +#endif +#include <assert.h> +#if defined(NDEBUG) +# define verify(expr) (void)(expr) +#else +# ifdef NCBI_COMPILER_METROWERKS + /* The following 2 headers are only required for Codewarrior + * on Mac to prototype printf() and abort() respectively */ +# include <stdio.h> +# include <stdlib.h> +# endif +# define verify(expr) assert(expr) +#endif + + +/* + * -------------------------------------------------------------------------- + * $Log: ncbi_assert.h,v $ + * Revision 1.1 2005/04/20 18:11:23 lavr + * Initial revision + * + * ========================================================================== + */ + +#endif /* CONNECT___NCBI_ASSERT__H */ diff --git a/connect/ncbi_buffer.c b/connect/ncbi_buffer.c index 404f97c1..4807ffd3 100644 --- a/connect/ncbi_buffer.c +++ b/connect/ncbi_buffer.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_buffer.c,v 6.13 2003/12/05 17:31:04 ucko Exp $ +/* $Id: ncbi_buffer.c,v 6.16 2004/11/17 20:44:32 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -51,7 +51,7 @@ typedef struct SBufChunkTag { size_t size; /* of data (including the discarded "n_skip" bytes) */ size_t alloc_size; /* maximum available (allocated) size of "data" */ size_t n_skip; /* # of bytes already discarded(read) from the chunk */ - char data[1]; /* data stored in this chunk */ + char* data; /* data stored in this chunk */ } SBufChunk; @@ -98,12 +98,12 @@ extern size_t BUF_Size(BUF buf) /* Create a new chunk. * Allocate at least "chunk_size" bytes, but no less than "size" bytes. + * Special case: "size" == 0 results in no data storage allocation. */ static SBufChunk* s_AllocChunk(size_t size, size_t chunk_size) { size_t alloc_size = ((size + chunk_size - 1) / chunk_size) * chunk_size; - SBufChunk* pChunk = (SBufChunk*) - malloc((size_t) (&(((SBufChunk*)0)->data)) + alloc_size); + SBufChunk* pChunk = (SBufChunk*) malloc(sizeof(*pChunk) + alloc_size); if ( !pChunk ) return 0; @@ -111,19 +111,74 @@ static SBufChunk* s_AllocChunk(size_t size, size_t chunk_size) pChunk->size = 0; pChunk->alloc_size = alloc_size; pChunk->n_skip = 0; + pChunk->data = alloc_size ? (char*) pChunk + sizeof(*pChunk) : 0; return pChunk; } +extern int/*bool*/ BUF_Append(BUF* pBuf, const void* data, size_t size) +{ + SBufChunk* pChunk; + if ( !size ) + return 1/*true*/; + + /* init the buffer internals, if not init'd yet */ + if (!*pBuf && !BUF_SetChunkSize(pBuf, 0)) + return 0/*false*/; + + pChunk = s_AllocChunk(0, (*pBuf)->chunk_size); + if ( !pChunk ) + return 0/*false*/; + + assert( !pChunk->data ); + pChunk->alloc_size = size; + pChunk->size = size; + pChunk->data = (char*) data; + + if ( (*pBuf)->last ) + (*pBuf)->last->next = pChunk; + else + (*pBuf)->list = pChunk; + (*pBuf)->last = pChunk; + return 1/*true*/; +} + + +extern int/*bool*/ BUF_Prepend(BUF* pBuf, const void* data, size_t size) +{ + SBufChunk* pChunk; + if ( !size ) + return 1/*true*/; + + /* init the buffer internals, if not init'd yet */ + if (!*pBuf && !BUF_SetChunkSize(pBuf, 0)) + return 0/*false*/; + + pChunk = s_AllocChunk(0, (*pBuf)->chunk_size); + if ( !pChunk ) + return 0/*false*/; + + assert( !pChunk->data ); + pChunk->alloc_size = size; + pChunk->size = size; + pChunk->data = (char*) data; + + if ( (*pBuf)->list ) + pChunk->next = (*pBuf)->list; + (*pBuf)->list = pChunk; + return 1/*true*/; +} + + extern int/*bool*/ BUF_Write(BUF* pBuf, const void* data, size_t size) { - SBufChunk *pChunk, *pTail; + SBufChunk* pChunk, *pTail; if ( !size ) - return 1 /* true */; + return 1/*true*/; /* init the buffer internals, if not init'd yet */ - if (!*pBuf && !BUF_SetChunkSize(pBuf, 0) ) - return 0 /* false */; + if (!*pBuf && !BUF_SetChunkSize(pBuf, 0)) + return 0/*false*/; /* find the last allocated chunk */ pTail = (*pBuf)->last; @@ -143,7 +198,7 @@ extern int/*bool*/ BUF_Write(BUF* pBuf, const void* data, size_t size) if ( size ) { pChunk = s_AllocChunk(size, (*pBuf)->chunk_size); if ( !pChunk ) - return 0 /* false */; + return 0/*false*/; pChunk->n_skip = 0; pChunk->size = size; memcpy(pChunk->data, data, size); @@ -155,7 +210,7 @@ extern int/*bool*/ BUF_Write(BUF* pBuf, const void* data, size_t size) (*pBuf)->list = pChunk; (*pBuf)->last = pChunk; } - return 1 /* true */; + return 1/*true*/; } @@ -163,11 +218,11 @@ extern int/*bool*/ BUF_PushBack(BUF* pBuf, const void* data, size_t size) { SBufChunk* pChunk; if ( !size ) - return 1 /* true */; + return 1/*true*/; /* init the buffer internals, if not init'd yet */ if (!*pBuf && !BUF_SetChunkSize(pBuf, 0) ) - return 0 /* false */; + return 0/*false*/; pChunk = (*pBuf)->list; @@ -175,7 +230,7 @@ extern int/*bool*/ BUF_PushBack(BUF* pBuf, const void* data, size_t size) if (!pChunk || size > pChunk->n_skip) { pChunk = s_AllocChunk(size, (*pBuf)->chunk_size); if ( !pChunk ) - return 0 /* false */; + return 0/*false*/; pChunk->n_skip = pChunk->size = pChunk->alloc_size; pChunk->next = (*pBuf)->list; (*pBuf)->list = pChunk; @@ -188,7 +243,7 @@ extern int/*bool*/ BUF_PushBack(BUF* pBuf, const void* data, size_t size) assert(pChunk->n_skip >= size); pChunk->n_skip -= size; memcpy(pChunk->data + pChunk->n_skip, data, size); - return 1 /* true */; + return 1/*true*/; } @@ -278,7 +333,7 @@ extern size_t BUF_Read(BUF buf, void* data, size_t size) } -extern void BUF_Destroy(BUF buf) +extern void BUF_Erase(BUF buf) { if ( !buf ) return; @@ -288,14 +343,31 @@ extern void BUF_Destroy(BUF buf) buf->list = pChunk->next; free(pChunk); } + buf->last = 0; +} + - free(buf); +extern void BUF_Destroy(BUF buf) +{ + if (buf) { + BUF_Erase(buf); + free(buf); + } } /* * --------------------------------------------------------------------------- * $Log: ncbi_buffer.c,v $ + * Revision 6.16 2004/11/17 20:44:32 lavr + * Slight source code formatting change + * + * Revision 6.15 2004/10/27 18:43:50 lavr + * +BUF_Erase() + * + * Revision 6.14 2004/10/27 18:09:58 lavr + * +BUF_Prepend(), +BUF_Append() + * * Revision 6.13 2003/12/05 17:31:04 ucko * Add a tail pointer to BUF_struct to avoid having to walk the entire * list in BUF_Write. diff --git a/connect/ncbi_buffer.h b/connect/ncbi_buffer.h index ae85ff77..3b2acf53 100644 --- a/connect/ncbi_buffer.h +++ b/connect/ncbi_buffer.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_BUFFER__H #define CONNECT___NCBI_BUFFER__H -/* $Id: ncbi_buffer.h,v 6.9 2003/04/10 12:52:15 siyan Exp $ +/* $Id: ncbi_buffer.h,v 6.11 2004/10/27 18:43:45 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,6 +36,8 @@ * Functions: * BUF_SetChunkSize * BUF_Size + * BUF_Prepend + * BUF_Append * BUF_Write * BUF_PushBack * BUF_Peek @@ -68,7 +70,8 @@ struct BUF_tag; typedef struct BUF_tag* BUF; /* handle of a buffer */ -/* Set minimal size of a buffer memory chunk. +/*! + * Set minimal size of a buffer memory chunk. * Return the actually set chunk size on success; zero on error * NOTE: if "*pBuf" == NULL then create it * if "chunk_size" is passed 0 then set it to BUF_DEF_CHUNK_SIZE @@ -80,13 +83,43 @@ extern NCBI_XCONNECT_EXPORT size_t BUF_SetChunkSize ); -/* Return the number of bytes stored in "buf". +/*! + * Return the number of bytes stored in "buf". * NOTE: return 0 if "buf" == NULL */ extern NCBI_XCONNECT_EXPORT size_t BUF_Size(BUF buf); -/* Add new data to the end of "*pBuf" (to be read last). +/*! + * Prepend a block of data (of the specified size) to the + * beginning of the buffer (to be read first). Note that unlike + * BUF_Pushback(), in this call the data is not copied into the buffer + * but instead is just linked in from the original location. + * Return non-zero (true) if succeeded, zero (false) if failed. + */ +extern NCBI_XCONNECT_EXPORT int/*bool*/ BUF_Prepend +(BUF* pBuf, + const void* data, + size_t size +); + + +/*! + * Append a block of data (of the specified size) past the end + * of the buffer (to be read last). Note that unlike + * BUF_Write(), in this call the data is not copied to the buffer + * but instead is just linked in from the original location. + * Return non-zero (true) if succeeded, zero (false) if failed. + */ +extern NCBI_XCONNECT_EXPORT int/*bool*/ BUF_Append +(BUF* pBuf, + const void* data, + size_t size + ); + + +/*! + * Add new data to the end of "*pBuf" (to be read last). * On error (failed memory allocation), return zero value. * NOTE: if "*pBuf" == NULL then create it. */ @@ -97,7 +130,8 @@ extern NCBI_XCONNECT_EXPORT /*bool*/int BUF_Write ); -/* Write the data to the very beginning of "*pBuf" (to be read first). +/*! + * Write the data to the very beginning of "*pBuf" (to be read first). * On error (failed memory allocation), return zero value. * NOTE: if "*pBuf" == NULL then create it. */ @@ -108,7 +142,8 @@ extern NCBI_XCONNECT_EXPORT /*bool*/int BUF_PushBack ); -/* Equivalent to "BUF_PeekAt(buf, 0, data, size)", see description below. +/*! + * Equivalent to "BUF_PeekAt(buf, 0, data, size)", see description below. */ extern NCBI_XCONNECT_EXPORT size_t BUF_Peek (BUF buf, @@ -117,7 +152,8 @@ extern NCBI_XCONNECT_EXPORT size_t BUF_Peek ); -/* Copy up to "size" bytes stored in "buf" (starting at position "pos") +/*! + * Copy up to "size" bytes stored in "buf" (starting at position "pos") * to "data". * Return the # of copied bytes (can be less than "size"). * Return zero and do nothing if "buf" is NULL or "pos" >= BUF_Size(buf). @@ -131,7 +167,8 @@ extern NCBI_XCONNECT_EXPORT size_t BUF_PeekAt ); -/* Copy up to "size" bytes stored in "buf" to "data" and remove +/*! + * Copy up to "size" bytes stored in "buf" to "data" and remove * copied data from the "buf". * Return the # of copied-and/or-removed bytes(can be less than "size") * NOTE: if "buf" == NULL then do nothing and return 0 @@ -144,7 +181,14 @@ extern NCBI_XCONNECT_EXPORT size_t BUF_Read ); -/* Destroy all internal data. +/*! + * Make the buffer empty. + */ +extern NCBI_XCONNECT_EXPORT void BUF_Erase(BUF buf); + + +/*! + * Destroy all internal data. * NOTE: do nothing if "buf" == NULL */ extern NCBI_XCONNECT_EXPORT void BUF_Destroy(BUF buf); @@ -161,6 +205,12 @@ extern NCBI_XCONNECT_EXPORT void BUF_Destroy(BUF buf); /* * --------------------------------------------------------------------------- * $Log: ncbi_buffer.h,v $ + * Revision 6.11 2004/10/27 18:43:45 lavr + * +BUF_Erase() + * + * Revision 6.10 2004/10/27 18:09:57 lavr + * +BUF_Prepend(), +BUF_Append() + * * Revision 6.9 2003/04/10 12:52:15 siyan * Changed group name for doxygen * diff --git a/connect/ncbi_comm.h b/connect/ncbi_comm.h index 95254e1b..fde68503 100644 --- a/connect/ncbi_comm.h +++ b/connect/ncbi_comm.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_COMM__H #define CONNECT___NCBI_COMM__H -/* $Id: ncbi_comm.h,v 6.9 2004/08/02 16:52:42 lavr Exp $ +/* $Id: ncbi_comm.h,v 6.10 2005/04/20 18:13:10 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,11 +35,6 @@ */ -#ifdef __cplusplus -extern "C" { -#endif - - #define NCBID_WEBPATH "/Service/ncbid.cgi" #define HTTP_CONNECTION_INFO "Connection-Info:" #define HTTP_DISP_FAILURES "Dispatcher-Failures:" @@ -49,6 +44,12 @@ extern "C" { #define DISP_PROTOCOL_VERSION "1.0" #define DISPD_MESSAGE_FILE ".dispd.msg" + +#ifdef __cplusplus +extern "C" { +#endif + + typedef unsigned int ticket_t; @@ -60,6 +61,9 @@ typedef unsigned int ticket_t; /* * -------------------------------------------------------------------------- * $Log: ncbi_comm.h,v $ + * Revision 6.10 2005/04/20 18:13:10 lavr + * extern "C" limited to code only (not preprocessor macros) + * * Revision 6.9 2004/08/02 16:52:42 lavr * +DISPD_MESSAGE_FILE * diff --git a/connect/ncbi_config.h b/connect/ncbi_config.h index c24b641a..0c857916 100644 --- a/connect/ncbi_config.h +++ b/connect/ncbi_config.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONFIG__H #define CONNECT___NCBI_CONFIG__H -/* $Id: ncbi_config.h,v 6.7 2003/04/02 16:20:53 rsmith Exp $ +/* $Id: ncbi_config.h,v 6.8 2004/10/19 19:33:51 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,21 +37,28 @@ */ #include <ncbilcl.h> +#ifdef NCBI_COMPILER_MW_MSL +# undef NCBI_COMPILER_MW_MSL +#endif + #if defined(OS_UNIX) # define NCBI_OS_UNIX 1 # ifdef OS_UNIX_IRIX -# define NCBI_OS_IRIX +# define NCBI_OS_IRIX # endif # ifdef OS_UNIX_SOL -# define NCBI_OS_SOLARIS +# define NCBI_OS_SOLARIS # endif # ifdef OS_UNIX_BEOS -# define NCBI_OS_BEOS +# define NCBI_OS_BEOS # endif # ifdef OS_UNIX_DARWIN -# define NCBI_OS_DARWIN 1 +# define NCBI_OS_DARWIN 1 # ifdef COMP_METRO # define NCBI_COMPILER_METROWERKS 1 +# if _MSL_USING_MW_C_HEADERS +# define NCBI_COMPILER_MW_MSL +# endif # endif # endif # if !defined(HAVE_GETHOSTBYNAME_R) @@ -65,6 +72,9 @@ # endif #elif defined(OS_MSWIN) # define NCBI_OS_MSWIN 1 +# ifdef COMP_METRO +# define NCBI_COMPILER_METROWERKS 1 +# endif #elif defined(OS_MAC) # define NCBI_OS_MAC 1 #endif diff --git a/connect/ncbi_connection.c b/connect/ncbi_connection.c index 5ef03d7c..3c8e405e 100644 --- a/connect/ncbi_connection.c +++ b/connect/ncbi_connection.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_connection.c,v 6.42 2004/05/26 16:00:06 lavr Exp $ +/* $Id: ncbi_connection.c,v 6.44 2004/11/15 19:33:42 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -454,7 +454,7 @@ extern EIO_Status CONN_Write if (!n_written) return eIO_InvalidArg; *n_written = 0; - if (size && !buf) + if (size && !buf) return eIO_InvalidArg; CONN_NOT_NULL(Write); @@ -540,11 +540,13 @@ static EIO_Status s_CONN_Read } /* read data from the internal peek buffer, if any */ - *n_read = peek - ? BUF_Peek(conn->buf, buf, size) : BUF_Read(conn->buf, buf, size); - if (*n_read == size) - return eIO_Success; - buf = (char*) buf + *n_read; + if ( size ) { + *n_read = peek + ? BUF_Peek(conn->buf, buf, size) : BUF_Read(conn->buf, buf, size); + if (*n_read == size) + return eIO_Success; + buf = (char*) buf + *n_read; + } /* read data from the connection */ {{ @@ -554,7 +556,7 @@ static EIO_Status s_CONN_Read conn->r_timeout == kDefaultTimeout ? conn->meta.default_timeout : conn->r_timeout); *n_read += x_read; - if (peek && x_read) /* save data in the internal peek buffer */ + if ( peek ) /* save data in the internal peek buffer */ verify(BUF_Write(&conn->buf, buf, x_read)); }} @@ -615,7 +617,7 @@ extern EIO_Status CONN_Read if (!n_read) return eIO_InvalidArg; *n_read = 0; - if (size && !buf) + if (size && !buf) return eIO_InvalidArg; CONN_NOT_NULL(Read); @@ -657,63 +659,62 @@ extern EIO_Status CONN_ReadLine size_t* n_read ) { - EIO_Status status = eIO_Success; - char w[1024]; - size_t len; + EIO_Status status = eIO_Success; + int/*bool*/ done = 0/*false*/; + size_t len; if (!n_read) return eIO_InvalidArg; *n_read = 0; - if (size && !line) + if (size && !line) return eIO_InvalidArg; CONN_NOT_NULL(ReadLine); /* perform open, if not opened yet */ - if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success) - return status; - assert(conn->state == eCONN_Open && conn->meta.list != 0); + if (conn->state != eCONN_Open) + status = s_Open(conn); - /* flush the unwritten output data (if any) */ - if ( conn->meta.flush ) { - conn->meta.flush(conn->meta.c_flush, - conn->r_timeout == kDefaultTimeout ? - conn->meta.default_timeout : conn->r_timeout); + if (status == eIO_Success) { + assert(conn->state == eCONN_Open && conn->meta.list != 0); + /* flush the unwritten output data (if any) */ + if ( conn->meta.flush ) { + conn->meta.flush(conn->meta.c_flush, + conn->r_timeout == kDefaultTimeout ? + conn->meta.default_timeout : conn->r_timeout); + } } len = 0; - while (len < size) { + while (status == eIO_Success) { size_t i; + char w[1024]; size_t x_read = 0; size_t x_size = BUF_Size(conn->buf); - char* buf = size - len < sizeof(w) ? w : &line[len]; - if (x_size == 0 || x_size > sizeof(w)) + char* x_buf = size - len < sizeof(w) ? w : line + len; + if (x_size == 0 || x_size > sizeof(w)) x_size = sizeof(w); - status = s_CONN_Read(conn, buf, x_size, &x_read, 0); - for (i = 0; i < x_read; i++) { - if (buf == w) - line[len] = buf[i]; - if (buf[i] == '\n') { - line[len] = '\0'; - i++; - break; - } else if (++len >= size) { + status = s_CONN_Read(conn, x_buf, size ? x_size : 0, &x_read, 0); + for (i = 0; i < x_read && len < size; i++) { + char c = x_buf[i]; + if (c == '\n') { + done = 1/*true*/; i++; break; } + if (x_buf == w) + line[len] = c; + len++; } - if (i < x_read) { - if (!BUF_PushBack(&conn->buf, &buf[i], x_read - i)) - status = eIO_Unknown; + if (i < x_read && !BUF_PushBack(&conn->buf, x_buf + i, x_read - i)) + status = eIO_Unknown; + if (done || len >= size) break; - } else if (status != eIO_Success) { - if (len < size) - line[len] = '\0'; - break; - } } - + if (len < size) + line[len] = '\0'; *n_read = len; + return status; } @@ -854,6 +855,12 @@ extern EIO_Status CONN_WaitAsync /* * -------------------------------------------------------------------------- * $Log: ncbi_connection.c,v $ + * Revision 6.44 2004/11/15 19:33:42 lavr + * Speed-up CONN_ReadLine() + * + * Revision 6.43 2004/11/15 17:39:26 lavr + * Fix CONN_ReadLine() to always perform connector's read method + * * Revision 6.42 2004/05/26 16:00:06 lavr * Minor status fixes in CONN_SetTimeout() and CONN_ReadLine() * diff --git a/connect/ncbi_connection.h b/connect/ncbi_connection.h index 20a6ca94..1881bcc2 100644 --- a/connect/ncbi_connection.h +++ b/connect/ncbi_connection.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONNECTION__H #define CONNECT___NCBI_CONNECTION__H -/* $Id: ncbi_connection.h,v 6.20 2004/06/09 14:03:06 jcherry Exp $ +/* $Id: ncbi_connection.h,v 6.21 2004/10/26 14:47:42 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -194,7 +194,7 @@ extern NCBI_XCONNECT_EXPORT EIO_Status CONN_PushBack * So does CONN_Close() but only if connection is was open before. */ extern NCBI_XCONNECT_EXPORT EIO_Status CONN_Flush -(CONN conn /* [in] connection handle */ +(CONN conn /* [in] connection handle */ ); @@ -326,6 +326,9 @@ extern EIO_Status CONN_WaitAsync /* * --------------------------------------------------------------------------- * $Log: ncbi_connection.h,v $ + * Revision 6.21 2004/10/26 14:47:42 lavr + * Slight formatting + * * Revision 6.20 2004/06/09 14:03:06 jcherry * Moved #define out of enum body (SWIG was choking on this) * diff --git a/connect/ncbi_connutil.c b/connect/ncbi_connutil.c index e127bfcb..4091611d 100644 --- a/connect/ncbi_connutil.c +++ b/connect/ncbi_connutil.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_connutil.c,v 6.65 2004/10/14 13:51:42 lavr Exp $ +/* $Id: ncbi_connutil.c,v 6.72 2005/04/20 15:50:30 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,7 +43,7 @@ static const char* s_GetValue(const char* service, const char* param, char* value, size_t value_size, const char* def_value) { - char key[250]; + char key[256]; char* sec; const char* val; @@ -105,7 +105,7 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) (service && *service ? strlen(service) + 1 : 0)); /* aux. storage for the string-to-int conversions, etc. */ - char str[32]; + char str[256]; int val; double dbl; char* s; @@ -146,8 +146,7 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) info->timeout = 0; } else { info->timeout = &info->tmo; - dbl = atof(str); - if (dbl <= 0.0) + if (!*str || (dbl = atof(str)) < 0.0) dbl = DEF_CONN_TIMEOUT; info->timeout->sec = (unsigned int) dbl; info->timeout->usec = (unsigned int) @@ -210,8 +209,19 @@ extern SConnNetInfo* ConnNetInfo_Create(const char* service) strcasecmp(str, "true") == 0 || strcasecmp(str, "yes" ) == 0)); - /* has no user header yet... */ - info->http_user_header = 0; + /* user header (with optional '\r\n' added automagically) */ + REG_VALUE(REG_CONN_HTTP_USER_HEADER, str, DEF_CONN_HTTP_USER_HEADER); + if (*str) { + size_t len = strlen(str); + if (str[len - 1] != '\n' && len < sizeof(str) - 2) { + str[len++] = '\r'; + str[len++] = '\n'; + str[len] = '\0'; + } + info->http_user_header = strdup(str); + } else + info->http_user_header = 0; + /* not adjusted yet... */ info->http_proxy_adjusted = 0/*false*/; /* store service name for which this structure has been created */ @@ -332,7 +342,7 @@ extern int/*bool*/ ConnNetInfo_ParseURL(SConnNetInfo* info, const char* url) extern int/*bool*/ ConnNetInfo_SetUserHeader(SConnNetInfo* info, - const char* user_header) + const char* user_header) { if (info->http_user_header) free((void*) info->http_user_header); @@ -703,7 +713,7 @@ extern void ConnNetInfo_Log(const SConnNetInfo* info, LOG lg) s_SaveString (s, "path", info->path); s_SaveString (s, "args", info->args); s_SaveString (s, "req_method", (info->req_method == eReqMethod_Any - ? DEF_CONN_REQ_METHOD + ? "ANY" : (info->req_method == eReqMethod_Get ? "GET" @@ -783,10 +793,15 @@ extern SOCK URL_Connect return 0/*error*/; } + /* select request method and its verbal representation */ + if (req_method == eReqMethod_Any) { + req_method = content_length ? eReqMethod_Post : eReqMethod_Get; + } else if (req_method == eReqMethod_Get && content_length) { + CORE_LOG(eLOG_Warning, + "[URL_Connect] Content length ignored with method GET"); + content_length = 0; + } switch (req_method) { - case eReqMethod_Any: - x_req_r = DEF_CONN_REQ_METHOD " "; - break; case eReqMethod_Post: x_req_r = "POST "; break; @@ -799,11 +814,6 @@ extern SOCK URL_Connect assert(0); return 0/*error*/; } - if (content_length && strcasecmp(x_req_r, "GET ") == 0) { - CORE_LOG(eLOG_Warning, - "[URL_Connect] Content length ignored with GET"); - content_length = 0; - } /* URL-encode "args", if any specified */ if (args && *args) { @@ -1250,6 +1260,163 @@ extern void URL_Encode +extern void BASE64_Encode +(const void* src_buf, + size_t src_size, + size_t* src_read, + void* dst_buf, + size_t dst_size, + size_t* dst_written, + size_t* line_len) +{ + static const char syms[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" /*26*/ + "abcdefghijklmnopqrstuvwxyz" /*52*/ + "0123456789+/"; /*64*/ + const size_t max_len = line_len ? *line_len : 76; + const size_t max_src = + ((dst_size - (max_len ? dst_size/(max_len + 1) : 0)) >> 2) * 3; + unsigned char* src = (unsigned char*) src_buf; + unsigned char* dst = (unsigned char*) dst_buf; + size_t len = 0, i = 0, j = 0; + unsigned char shift = 2; + unsigned char temp = 0; + if (!max_src) { + *src_read = 0; + *dst_written = 0; + if (dst_size > 0) { + *dst = '\0'; + } + return; + } + if (src_size > max_src) { + src_size = max_src; + } + for (;;) { + unsigned char c = i < src_size ? src[i] : 0; + unsigned char bits = (c >> shift) & 0x3F; + assert((temp | bits) < sizeof(syms) - 1); + dst[j++] = syms[temp | bits]; + if (max_len && ++len >= max_len) { + dst[j++] = '\n'; + len = 0; + } + if (i >= src_size) { + break; + } + shift += 2; + shift &= 7; + if (shift) { + i++; + } + temp = (c << (8 - shift)) & 0x3F; + } + assert(j <= dst_size); + *src_read = i; + for (i = 0; i < (3 - src_size % 3) % 3; i++) { + dst[j++] = '='; + if (max_len && ++len >= max_len) { + dst[j++] = '\n'; + len = 0; + } + } + assert(j <= dst_size); + *dst_written = j; + if (j < dst_size) { + dst[j] = '\0'; + } +} + + +extern int/*bool*/ BASE64_Decode +(const void* src_buf, + size_t src_size, + size_t* src_read, + void* dst_buf, + size_t dst_size, + size_t* dst_written) +{ + unsigned char* src = (unsigned char*) src_buf; + unsigned char* dst = (unsigned char*) dst_buf; + size_t i = 0, j = 0, k = 0, l; + unsigned int temp = 0; + if (src_size < 4 || dst_size < 3) { + *src_read = 0; + *dst_written = 0; + return 0/*false*/; + } + for (;;) { + unsigned char c = i < src_size ? src[i++] : '='; + if (c == '=') { + c = 64; /*end*/ + } else if (c >= 'A' && c <= 'Z') { + c -= 'A'; + } else if (c >= 'a' && c <= 'z') { + c -= 'a' - 26; + } else if (c >= '0' && c <= '9') { + c -= '0' - 52; + } else if (c == '+') { + c = 62; + } else if (c == '/') { + c = 63; + } else { + continue; + } + temp <<= 6; + temp |= c & 0x3F; + if (!(++k & 3) || c == 64) { + if (c == 64) { + if (k < 2) { + --i; + break; + } + switch (k) { + case 2: + temp >>= 4; + break; + case 3: + temp >>= 10; + break; + case 4: + temp >>= 8; + break; + default: + break; + } + for (l = k; l < 4; l++) { + if (i < src_size && src[i] == '=') { + i++; + } + } + } else { + k = 0; + } + switch (k) { + case 0: + dst[j++] = (temp & 0xFF0000) >> 16; + /*FALLTHRU*/; + case 4: + dst[j++] = (temp & 0xFF00) >> 8; + /*FALLTHRU*/ + case 3: + dst[j++] = (temp & 0xFF); + break; + default: + break; + } + if (j + 3 >= dst_size || c == 64) { + break; + } + temp = 0; + } + } + *src_read = i; + *dst_written = j; + return i ? 1/*true*/ : 0/*false*/; +} + + + /**************************************************************************** * NCBI-specific MIME content type and sub-types */ @@ -1497,6 +1664,28 @@ extern size_t HostPortToString(unsigned int host, /* * -------------------------------------------------------------------------- * $Log: ncbi_connutil.c,v $ + * Revision 6.72 2005/04/20 15:50:30 lavr + * ConnNetInfo_Create(): Allow zero timeout + * URL_Connect(): Automagically figure out ANY method based upon body size + * + * Revision 6.71 2005/03/21 17:10:03 lavr + * BASE64_Decode(): unnecessary re-init of "k" removed + * + * Revision 6.70 2005/03/21 17:04:35 lavr + * BASE64_{En|De}code few bugs fixed + * + * Revision 6.69 2005/03/19 02:13:55 lavr + * +BASE64_{En|De}code + * + * Revision 6.68 2005/02/28 17:58:31 lavr + * Cosmetics + * + * Revision 6.67 2005/02/24 19:03:11 lavr + * Always init SConnNetInfo::http_user_header + * + * Revision 6.66 2005/02/24 19:00:45 lavr + * +CONN_HTTP_USER_HEADER + * * Revision 6.65 2004/10/14 13:51:42 lavr * StringToHostPort() to allow NULL ptrs * diff --git a/connect/ncbi_connutil.h b/connect/ncbi_connutil.h index 344326bd..2a8c6a92 100644 --- a/connect/ncbi_connutil.h +++ b/connect/ncbi_connutil.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CONNUTIL__H #define CONNECT___NCBI_CONNUTIL__H -/* $Id: ncbi_connutil.h,v 6.36 2004/09/16 16:19:16 lavr Exp $ +/* $Id: ncbi_connutil.h,v 6.42 2005/04/20 15:47:24 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -56,23 +56,27 @@ * URL_Connect() * * 3.Perform URL encoding/decoding of data: + * URL_Encode() * URL_Decode() * URL_DecodeEx() - * URL_Encode() * - * 4.Compose or parse NCBI-specific Content-Type's: + * 4.Perform BASE64 (RFC 1521) encoding/decoding of data: + * BASE64_Encode() + * BASE64_Decode() + * + * 5.Compose or parse NCBI-specific Content-Type's: * EMIME_Type * EMIME_SubType * EMIME_Encoding * MIME_ComposeContentType() * MIME_ParseContentType() * - * 5.Search for a token in the input stream (either CONN or SOCK): + * 6.Search for a token in the input stream (either CONN or SOCK): * CONN_StripToPattern() * SOCK_StripToPattern() * BUF_StripToPattern() * - * 6.Convert "[host][:port]" from verbal into binary form and vice versa: + * 7.Convert "[host][:port]" from verbal into binary form and vice versa: * StringToHostPort() * HostPortToString() * @@ -155,7 +159,7 @@ typedef struct { #define DEF_CONN_ARGS "" #define REG_CONN_REQ_METHOD "REQ_METHOD" -#define DEF_CONN_REQ_METHOD "POST" +#define DEF_CONN_REQ_METHOD "ANY" #define REG_CONN_TIMEOUT "TIMEOUT" #define DEF_CONN_TIMEOUT 30.0 @@ -184,6 +188,9 @@ typedef struct { #define REG_CONN_LB_DISABLE "LB_DISABLE" #define DEF_CONN_LB_DISABLE "" +#define REG_CONN_HTTP_USER_HEADER "HTTP_USER_HEADER" +#define DEF_CONN_HTTP_USER_HEADER 0 + /* This function to fill out the "*info" structure using * registry entries named (see above) in macros REG_CONN_<NAME>: @@ -204,6 +211,7 @@ typedef struct { * debug_printout DEBUG_PRINTOUT * client_mode CLIENT_MODE * lb_disable LB_DISABLE + * http_user_header HTTP_USER_HEADER "\r\n" if missing is appended * * A value of the field NAME is first looked for in the environment variable * of the form service_CONN_NAME; then in the current corelib registry, @@ -361,6 +369,7 @@ extern NCBI_XCONNECT_EXPORT void ConnNetInfo_Log extern NCBI_XCONNECT_EXPORT void ConnNetInfo_Destroy(SConnNetInfo* info); + /* Hit URL "http://host:port/path?args" with: * {POST|GET} <path>?<args> HTTP/1.0\r\n * <user_header\r\n> @@ -401,6 +410,7 @@ extern NCBI_XCONNECT_EXPORT SOCK URL_Connect ); + /* Discard all input data before(and including) the first occurrence of * "pattern". If "buf" is not NULL then add the discarded data(including * the "pattern") to it. If "n_discarded" is not NULL then "*n_discarded" @@ -432,12 +442,29 @@ extern NCBI_XCONNECT_EXPORT EIO_Status BUF_StripToPattern ); + +/* URL-encode up to "src_size" symbols(bytes) from buffer "src_buf". + * Write the encoded data to buffer "dst_buf", but no more than "dst_size" + * bytes. + * Assign "*src_read" to the # of bytes successfully encoded from "src_buf". + * Assign "*dst_written" to the # of bytes written to buffer "dst_buf". + */ +extern NCBI_XCONNECT_EXPORT void URL_Encode +(const void* src_buf, /* [in] non-NULL */ + size_t src_size, /* [in] */ + size_t* src_read, /* [out] non-NULL */ + void* dst_buf, /* [in/out] non-NULL */ + size_t dst_size, /* [in] */ + size_t* dst_written /* [out] non-NULL */ + ); + + /* URL-decode up to "src_size" symbols(bytes) from buffer "src_buf". * Write the decoded data to buffer "dst_buf", but no more than "dst_size" * bytes. * Assign "*src_read" to the # of bytes successfully decoded from "src_buf". * Assign "*dst_written" to the # of bytes written to buffer "dst_buf". - * Return FALSE only if cannot decode nothing, and an unrecoverable + * Return FALSE (0) only if cannot decode anything, and an unrecoverable * URL-encoding error (such as an invalid symbol or a bad "%.." sequence) * has occurred. * NOTE: the unfinished "%.." sequence is fine -- return TRUE, but dont @@ -470,13 +497,40 @@ extern NCBI_XCONNECT_EXPORT int/*bool*/ URL_DecodeEx ); -/* URL-encode up to "src_size" symbols(bytes) from buffer "src_buf". + +/* BASE64-encode up to "src_size" symbols(bytes) from buffer "src_buf". * Write the encoded data to buffer "dst_buf", but no more than "dst_size" * bytes. * Assign "*src_read" to the # of bytes successfully encoded from "src_buf". * Assign "*dst_written" to the # of bytes written to buffer "dst_buf". + * Resulting lines will not exceed "*line_len" (or the standard default + * if "line_len" is NULL) bytes; *line_len == 0 disables line breaks. + * To estimate required destination buffer size, you can take into account + * that BASE64 coding converts every 3 bytes of source into 4 bytes on + * destination, not including the line breaks ('\n'). */ -extern NCBI_XCONNECT_EXPORT void URL_Encode +extern NCBI_XCONNECT_EXPORT void BASE64_Encode +(const void* src_buf, /* [in] non-NULL */ + size_t src_size, /* [in] */ + size_t* src_read, /* [out] non-NULL */ + void* dst_buf, /* [in/out] non-NULL */ + size_t dst_size, /* [in] */ + size_t* dst_written,/* [out] non-NULL */ + size_t* line_len /* [in] may be NULL */ + ); + + +/* BASE64-decode up to "src_size" symbols(bytes) from buffer "src_buf". + * Write the decoded data to buffer "dst_buf", but no more than "dst_size" + * bytes. + * Assign "*src_read" to the # of bytes successfully decoded from "src_buf". + * Assign "*dst_written" to the # of bytes written to buffer "dst_buf". + * Return FALSE (0) only if cannot decode anything. + * Destination buffer size, as a worst case, equal to the source size + * will accomodate the entire input. As a rule, each 4 bytes of source + * (line breaks skipped) are converted into 3 bytes on output. + */ +extern NCBI_XCONNECT_EXPORT int/*bool*/ BASE64_Decode (const void* src_buf, /* [in] non-NULL */ size_t src_size, /* [in] */ size_t* src_read, /* [out] non-NULL */ @@ -643,6 +697,24 @@ extern NCBI_XCONNECT_EXPORT size_t HostPortToString /* * -------------------------------------------------------------------------- * $Log: ncbi_connutil.h,v $ + * Revision 6.42 2005/04/20 15:47:24 lavr + * DEF_CONN_REQ_METHOD changed to ANY + * + * Revision 6.41 2005/03/21 17:04:10 lavr + * BASE64_{En|De}code buffer size estimation hints added + * + * Revision 6.40 2005/03/19 02:13:55 lavr + * +BASE64_{En|De}code + * + * Revision 6.39 2005/02/28 17:23:20 lavr + * Fix HTTP_USER_HEADER env.var. name ("HTTP" was missing) + * + * Revision 6.38 2005/02/24 19:51:24 lavr + * Document CONN_HTTP_USER_HEADER environment + * + * Revision 6.37 2005/02/24 19:00:33 lavr + * +CONN_HTTP_USER_HEADER + * * Revision 6.36 2004/09/16 16:19:16 lavr * Mention [in opening comment summary] that EMIME_Type is defined here * diff --git a/connect/ncbi_core.c b/connect/ncbi_core.c index 37011628..b830a288 100644 --- a/connect/ncbi_core.c +++ b/connect/ncbi_core.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_core.c,v 6.14 2003/08/28 18:47:51 ucko Exp $ +/* $Id: ncbi_core.c,v 6.15 2005/04/20 18:13:39 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,6 +31,7 @@ */ #include "ncbi_ansi_ext.h" +#include "ncbi_assert.h" #include <connect/ncbi_core.h> #include <stdlib.h> @@ -461,6 +462,9 @@ extern void REG_Set /* * --------------------------------------------------------------------------- * $Log: ncbi_core.c,v $ + * Revision 6.15 2005/04/20 18:13:39 lavr + * +"ncbi_assert.h" + * * Revision 6.14 2003/08/28 18:47:51 ucko * Revert previous hack (now handled another way) * diff --git a/connect/ncbi_core.h b/connect/ncbi_core.h index faf6d78f..c4fd8c0b 100644 --- a/connect/ncbi_core.h +++ b/connect/ncbi_core.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_CORE__H #define CONNECT___NCBI_CORE__H -/* $Id: ncbi_core.h,v 6.25 2004/03/12 23:26:22 gorelenk Exp $ +/* $Id: ncbi_core.h,v 6.27 2005/04/20 18:10:53 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -65,27 +65,6 @@ #include <connect/ncbi_types.h> -/* Run-time debugging */ -#if defined(verify) -#undef verify -#endif - -#if !defined(NDEBUG) && !defined(_DEBUG) -# define NDEBUG -#endif -#include <assert.h> -#if defined(NDEBUG) -# define verify(expr) (void)(expr) -#else -/* The following 2 headers are actually only required for Codewarrior - * on Mac to prototype printf() and abort() respectively :-/ - */ -# include <stdio.h> -# include <stdlib.h> -# define verify(expr) assert(expr) -#endif - - /** @addtogroup UtilityFunc * * @{ @@ -119,7 +98,8 @@ typedef enum { */ typedef enum { eIO_WritePlain, - eIO_WritePersist + eIO_WritePersist, + eIO_WriteOutOfBand } EIO_WriteMethod; @@ -480,6 +460,12 @@ extern NCBI_XCONNECT_EXPORT void REG_Set * =========================================================================== * * $Log: ncbi_core.h,v $ + * Revision 6.27 2005/04/20 18:10:53 lavr + * verify() moved away into a private header (ncbi_assert.h) + * + * Revision 6.26 2004/12/27 15:30:08 lavr + * +eIO_WriteOutOfBand + * * Revision 6.25 2004/03/12 23:26:22 gorelenk * Added export prefixes. * diff --git a/connect/ncbi_core_c.c b/connect/ncbi_core_c.c index 2e5a1a05..733220f8 100644 --- a/connect/ncbi_core_c.c +++ b/connect/ncbi_core_c.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_core_c.c,v 6.9 2002/10/31 17:53:33 lavr Exp $ +/* $Id: ncbi_core_c.c,v 6.10 2005/04/20 20:38:42 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ */ #include "ncbi_config.h" +#include "ncbi_assert.h" #include <connect/ncbi_ansi_ext.h> #include <connect/ncbi_core_c.h> #include <connect/ncbi_util.h> @@ -231,6 +232,9 @@ extern void CONNECT_Init(const char* conf_file) /* * --------------------------------------------------------------------------- * $Log: ncbi_core_c.c,v $ + * Revision 6.10 2005/04/20 20:38:42 lavr + * +"ncbi_assert.h" + * * Revision 6.9 2002/10/31 17:53:33 lavr * Clear error in case of a trace message * diff --git a/connect/ncbi_dispd.c b/connect/ncbi_dispd.c index 7907798e..a9fd7e37 100644 --- a/connect/ncbi_dispd.c +++ b/connect/ncbi_dispd.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_dispd.c,v 6.62 2004/08/19 15:48:15 lavr Exp $ +/* $Id: ncbi_dispd.c,v 6.65 2005/04/25 18:46:13 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -42,6 +42,10 @@ #include <stdlib.h> #include <time.h> +#if 0/*defined(_DEBUG) && !defined(NDEBUG)*/ +# define SERV_DISPD_DEBUG 1 +#endif /*_DEBUG && !NDEBUG*/ + /* Lower bound of up-to-date/out-of-date ratio */ #define SERV_DISPD_STALE_RATIO_OK 0.8 /* Default rate increase if svc runs locally */ @@ -55,7 +59,7 @@ static FDISP_MessageHook s_MessageHook = 0; #ifdef __cplusplus extern "C" { -#endif +#endif /*__cplusplus*/ static void s_Reset (SERV_ITER); static SSERV_Info* s_GetNextInfo(SERV_ITER, HOST_INFO*); static int/*bool*/ s_Update (SERV_ITER, TNCBI_Time, const char*); @@ -66,7 +70,7 @@ extern "C" { }; #ifdef __cplusplus } /* extern "C" */ -#endif +#endif /*__cplusplus*/ static int s_RandomSeed = 0; @@ -174,9 +178,10 @@ static int/*bool*/ s_Resolve(SERV_ITER iter) if (*net_info->client_host && !strchr(net_info->client_host, '.') && (ip = SOCK_gethostbyname(net_info->client_host)) != 0 && SOCK_ntoa(ip, addr, sizeof(addr)) == 0) { - if ((s= malloc(strlen(net_info->client_host) + strlen(addr) + 3)) != 0) + if ((s = (char*) malloc(strlen(net_info->client_host) + + strlen(addr) + 3)) != 0) { sprintf(s, "%s(%s)", net_info->client_host, addr); - else + } else s = net_info->client_host; } else s = net_info->client_host; @@ -209,7 +214,7 @@ static int/*bool*/ s_Resolve(SERV_ITER iter) " (C++ Toolkit)" #else " (C Toolkit)" -#endif +#endif /*NCBI_CXX_TOOLKIT*/ "\r\n"); data->disp_fail = 0; /* All the rest in the net_info structure is fine with us */ @@ -264,7 +269,7 @@ static int/*bool*/ s_Update(SERV_ITER iter, TNCBI_Time now, const char* text) p++; if (data->net_info->debug_printout) CORE_LOGF(eLOG_Warning, ("[DISPATCHER] %s", p)); -#endif +#endif /*_DEBUG && !NDEBUG*/ data->disp_fail = 1; return 1/*updated*/; } else if (len >= sizeof(HTTP_DISP_MESSAGE) && @@ -334,11 +339,13 @@ static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info) status = info->rate; assert(status != 0.0); - if (info->host == iter->preferred_host) { - if (info->coef <= 0.0 || iter->preference) { + if (iter->preferred_host == info->host || + (!iter->preferred_host && + info->locl && info->coef < 0.0)) { + if (iter->preference || info->coef <= 0.0) { status *= SERV_DISPD_LOCAL_SVC_BONUS; if (access < status && - (iter->preference || info->coef < 0.0)) { + (iter->preference || info->coef < 0.0)) { access = status; point = total + status; /* Latch this local server */ p = -info->coef; @@ -351,19 +358,35 @@ static SSERV_Info* s_GetNextInfo(SERV_ITER iter, HOST_INFO* host_info) data->s_node[i].status = total; } - if (point > 0.0 && iter->preference) { + if (point > 0.0 && iter->preference) { if (total != access) { p = SERV_Preference(iter->preference, access/total, data->n_node); +#ifdef SERV_DISPD_DEBUG + CORE_LOGF(eLOG_Note, ("(P = %lf, A = %lf, T = %lf, N = %d)" + " -> Pref = %lf", iter->preference, + access, total, (int) data->n_node, p)); +#endif /*SERV_DISPD_DEBUG*/ status = total*p; p = total*(1.0 - p)/(total - access); for (i = 0; i < data->n_node; i++) { data->s_node[i].status *= p; - if (p*point <= data->s_node[i].status) + if (p*point <= data->s_node[i].status) data->s_node[i].status += status - p*access; } +#ifdef SERV_DISPD_DEBUG + for (i = 0; i < data->n_node; i++) { + char addr[16]; + SOCK_ntoa(data->s_node[i].info->host, addr, sizeof(addr)); + status = data->s_node[i].status - + (i ? data->s_node[i-1].status : 0.0); + CORE_LOGF(eLOG_Note, ("%s %lf %.2lf%%", addr, + status, status/total*100.0)); + } +#endif /*SERV_DISPD_DEBUG*/ } point = -1.0; } + /* We take pre-chosen local server only if its status is not less than p% of the average remaining status; otherwise, we ignore the server, and apply the generic procedure by seeding a random point. */ @@ -466,6 +489,15 @@ void DISP_SetMessageHook(FDISP_MessageHook hook) /* * -------------------------------------------------------------------------- * $Log: ncbi_dispd.c,v $ + * Revision 6.65 2005/04/25 18:46:13 lavr + * Made parallel with ncbi_lbsmd.c + * + * Revision 6.64 2005/03/16 20:15:25 lavr + * Allow local B services to have a preference + * + * Revision 6.63 2005/01/27 19:00:05 lavr + * Explicit cast of malloc()ed memory + * * Revision 6.62 2004/08/19 15:48:15 lavr * SERV_ITER::type renamed into SERV_ITER::types to reflect its bitmask nature * diff --git a/connect/ncbi_file_connector.c b/connect/ncbi_file_connector.c index c055b536..86f56a3c 100644 --- a/connect/ncbi_file_connector.c +++ b/connect/ncbi_file_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_file_connector.c,v 6.12 2003/05/31 05:14:56 lavr Exp $ +/* $Id: ncbi_file_connector.c,v 6.13 2005/04/20 18:15:59 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,6 +35,7 @@ #include "ncbi_ansi_ext.h" #include <connect/ncbi_file_connector.h> +#include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -324,6 +325,9 @@ extern CONNECTOR FILE_CreateConnectorEx /* * -------------------------------------------------------------------------- * $Log: ncbi_file_connector.c,v $ + * Revision 6.13 2005/04/20 18:15:59 lavr + * +<assert.h> + * * Revision 6.12 2003/05/31 05:14:56 lavr * Add ARGSUSED where args are meant to be unused * diff --git a/connect/ncbi_ftp_connector.c b/connect/ncbi_ftp_connector.c new file mode 100644 index 00000000..20239bbc --- /dev/null +++ b/connect/ncbi_ftp_connector.c @@ -0,0 +1,718 @@ +/* $Id: ncbi_ftp_connector.c,v 1.7 2005/04/20 18:15:59 lavr Exp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * FTP CONNECTOR + * See also: RFCs 959 (STD 9), 1634 (FYI 24), + * and IETF 9-2002 "Extensions to FTP". + * + * See <connect/ncbi_connector.h> for the detailed specification of + * the connector's methods and structures. + * + */ + +#include "ncbi_ansi_ext.h" +#include <connect/ncbi_buffer.h> +#include <connect/ncbi_ftp_connector.h> +#include <connect/ncbi_socket.h> +#include <assert.h> +#include <ctype.h> +#include <stdio.h> +#include <stdlib.h> + + +/*********************************************************************** + * INTERNAL -- Auxiliary types and static functions + ***********************************************************************/ + + +typedef enum { + eFtpFeature_None = 0, + eFtpFeature_MDTM = 1, + eFtpFeature_SIZE = 2 +} EFtpFeature; +typedef unsigned int TFtpFeatures; /* bitwise OR of individual EFtpFeature's */ + + +/* All internal data necessary to perform the (re)connect and i/o + */ +typedef struct { + const char* host; + unsigned short port; + const char* user; + const char* pass; + const char* path; + const char* name; + TFtpFeatures feat; + ESwitch log; + SOCK cntl; /* control connection */ + SOCK data; /* data connection */ + BUF wbuf; /* write buffer */ + EIO_Status r_status; + EIO_Status w_status; +} SFTPConnector; + + +static EIO_Status s_ReadReply(SOCK sock, int* code, + char* line, size_t maxlinelen) +{ + int/*bool*/ first = 1/*true*/; + for (;;) { + int c, m; + size_t n; + char buf[1024]; + EIO_Status status = SOCK_ReadLine(sock, buf, sizeof(buf), &n); + if (status != eIO_Success) + return status; + if (n == sizeof(buf)) + return eIO_Unknown/*line too long*/; + if (first || isdigit((unsigned char) *buf)) { + if (sscanf(buf, "%d%n", &c, &m) < 1) + return eIO_Unknown; + } else + c = 0; + if (first) { + if (m != 3 || code == 0) + return eIO_Unknown; + if (line) + strncpy0(line, &buf[m + 1], maxlinelen); + *code = c; + if (buf[m] != '-') { + if (buf[m] == ' ') + break; + return eIO_Unknown; + } + first = 0/*false*/; + } else if (c == *code && m == 3 && buf[m] == ' ') + break; + } + return eIO_Success; +} + + +static EIO_Status s_FTPReply(SFTPConnector* xxx, int* code, + char* line, size_t maxlinelen) +{ + int c = 0; + EIO_Status status = eIO_Closed; + if (xxx->cntl) { + status = s_ReadReply(xxx->cntl, &c, line, maxlinelen); + if (status == eIO_Success && c == 421) + status = eIO_Closed; + if (status == eIO_Closed || (status == eIO_Success && c == 221)) { + SOCK_Close(xxx->cntl); + xxx->cntl = 0; + if (xxx->data) { + SOCK_Close(xxx->data); + xxx->data = 0; + } + } + } + if (code) + *code = c; + return status; +} + + +static EIO_Status s_WriteCommand(SOCK sock, + const char* cmd, const char* arg) +{ + size_t cmdlen = strlen(cmd); + size_t arglen = arg ? strlen(arg) : 0; + size_t linelen = cmdlen + (arglen ? 1/* */ + arglen : 0) + 2/*\r\n*/; + char* line = (char*) malloc(linelen + 1/*\0*/); + EIO_Status status = eIO_Unknown; + if (line) { + memcpy(line, cmd, cmdlen); + if (arglen) { + line[cmdlen++] = ' '; + memcpy(line + cmdlen, arg, arglen); + cmdlen += arglen; + } + line[cmdlen++] = '\r'; + line[cmdlen++] = '\n'; + line[cmdlen] = '\0'; + status = SOCK_Write(sock, line, linelen, 0, eIO_WritePersist); + free(line); + } + return status; +} + + +static EIO_Status s_FTPCommand(SFTPConnector* xxx, + const char* cmd, const char* arg) +{ + return xxx->cntl ? s_WriteCommand(xxx->cntl, cmd, arg) : eIO_Closed; +} + + +static EIO_Status s_FTPLogin(SFTPConnector* xxx, const STimeout* timeout) +{ + EIO_Status status; + int code; + + assert(xxx->cntl && xxx->user && xxx->pass); + status = SOCK_SetTimeout(xxx->cntl, eIO_ReadWrite, timeout); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code != 220 || !*xxx->user) + return eIO_Unknown; + status = s_FTPCommand(xxx, "USER", xxx->user); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code == 230) + return eIO_Success; + if (code != 331 || !*xxx->pass) + return eIO_Unknown; + status = s_FTPCommand(xxx, "PASS", xxx->pass); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code == 230) + return eIO_Success; + else + return eIO_Unknown; +} + + +static EIO_Status s_FTPChdir(SFTPConnector* xxx, const char* cmd) +{ + if (cmd || xxx->path) { + int code; + EIO_Status status = s_FTPCommand(xxx, + cmd ? cmd : "CWD", + cmd ? 0 : xxx->path); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code != 250) + return eIO_Unknown; + } + return eIO_Success; +} + + +static EIO_Status s_FTPBinary(SFTPConnector* xxx) +{ + int code; + EIO_Status status = s_FTPCommand(xxx, "TYPE", "I"); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code == 200) + return eIO_Success; + else + return eIO_Unknown; +} + + +static EIO_Status s_FTPAbort(SFTPConnector* xxx) +{ + EIO_Status status = eIO_Success; + if (xxx->data) { + int code; + size_t n; + /* Send TELNET IP (Interrupt Process) command */ + status = SOCK_Write(xxx->cntl, "\377\364", 2, &n, eIO_WritePersist); + if (status != eIO_Success) + return status; + if (n != 2) + return eIO_Unknown; + /* Send TELNET DM (Data Mark) command to complete SYNCH, RFC 854 */ + status = SOCK_Write(xxx->cntl, "\377\362", 2, &n, eIO_WriteOutOfBand); + if (status != eIO_Success) + return status; + if (n != 2) + return eIO_Unknown; + status = s_FTPCommand(xxx, "ABOR", 0); + while(SOCK_Read(xxx->data, 0, 1024*1024/*drain up*/, 0, eIO_ReadPlain) + == eIO_Success); + if (status == eIO_Success) + status = s_FTPReply(xxx, &code, 0, 0); + /* Microsoft FTP is known to return 225 (instead of 226) */ + if (status == eIO_Success && (code/100) != 2 && code != 426) + status = eIO_Unknown; + if (status == eIO_Success) + status = SOCK_Close(xxx->data); + else if (xxx->data) { + SOCK_Close(xxx->data); + xxx->data = 0; + } + } + return status; +} + + +static EIO_Status s_FTPPasv(SFTPConnector* xxx) +{ + static STimeout zero; + int code, o[6]; + unsigned int i; + char buf[128], *c; + unsigned int host; + unsigned short port; + + EIO_Status status = s_FTPCommand(xxx, "PASV", 0); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, buf, sizeof(buf) - 1); + if (status != eIO_Success || code != 227) + return eIO_Unknown; + buf[sizeof(buf) - 1] = '\0'; + for (;;) { + /* RFC 1123 4.1.2.6 says that ()'s in PASV reply must not be assumed */ + for (c = buf; *c; c++) { + if (isdigit((unsigned char) *c)) + break; + } + if (!*c) + return eIO_Unknown; + if (sscanf(c, "%d,%d,%d,%d,%d,%d%n", + &o[0], &o[1], &o[2], &o[3], &o[4], &o[5], &code) >= 6) { + break; + } + strcpy(buf, c + code); + } + for (i = 0; i < (unsigned int)(sizeof(o)/sizeof(o[0])); i++) { + if (o[i] < 0 || o[i] > 255) + return eIO_Unknown; + } + i = (((((o[0] << 8) + o[1]) << 8) + o[2]) << 8) + o[3]; + host = SOCK_htonl(i); + i = (o[4] << 8) + o[5]; + port = (unsigned short) i; + if (SOCK_ntoa(host, buf, sizeof(buf)) == 0 && + SOCK_CreateEx(buf, port, &zero, &xxx->data, + 0, 0, xxx->log) == eIO_Success) { + return eIO_Success; + } + s_FTPAbort(xxx); + return eIO_Unknown; +} + + +static EIO_Status s_FTPRetrieve(SFTPConnector* xxx, + const char* cmd) +{ + int code; + EIO_Status status = s_FTPPasv(xxx); + if (status != eIO_Success) + return status; + status = s_FTPCommand(xxx, cmd, 0); + if (status != eIO_Success) + return status; + status = s_FTPReply(xxx, &code, 0, 0); + if (status != eIO_Success) + return status; + if (code == 150) + return eIO_Success; + s_FTPAbort(xxx); + return eIO_Unknown; +} + + +static EIO_Status s_FTPQuit(SFTPConnector* xxx) +{ + EIO_Status status; + int code; + s_FTPAbort(xxx); + status = s_FTPCommand(xxx, "QUIT", 0); + if (status == eIO_Success) + status = s_FTPReply(xxx, &code, 0, 0); + if (status == eIO_Success && code != 221) + status = eIO_Unknown; + if (xxx->cntl) { + if (status == eIO_Success) + status = SOCK_Close(xxx->cntl); + else + SOCK_Close(xxx->cntl); + xxx->cntl = 0; + } + return status; +} + + +static EIO_Status s_FTPExecute(SFTPConnector* xxx, const STimeout* timeout) +{ + EIO_Status status = eIO_Success; + size_t size = BUF_Size(xxx->wbuf); + char* s = (char*) malloc(size + 1); + s_FTPAbort(xxx); + assert(size); + if (s) { + if (BUF_Read(xxx->wbuf, s, size) == size && + SOCK_SetTimeout(xxx->cntl, eIO_ReadWrite, timeout) == eIO_Success){ + char* c; + s[size] = '\0'; + if (!(c = strchr(s, ' '))) + c = s + strlen(s); + size = (size_t)(c - s); + if (strncasecmp(s, "CWD", size) == 0) { + status = s_FTPChdir(xxx, s); + } else if (strncasecmp(s, "LIST", size) == 0 || + strncasecmp(s, "NLST", size) == 0 || + strncasecmp(s, "RETR", size) == 0) { + status = s_FTPRetrieve(xxx, s); + } else if (strncasecmp(s, "REST", size) == 0) { + status = s_FTPCommand(xxx, s, 0); + if (status == eIO_Success) { + int code; + status = s_FTPReply(xxx, &code, 0, 0); + if (status == eIO_Success && code != 350) + status = eIO_Unknown; + } + } else + status = eIO_Unknown; + } else + status = eIO_Unknown; + free(s); + } else + status = eIO_Unknown; + return status; +} + + +/*********************************************************************** + * INTERNAL -- "s_VT_*" functions for the "virt. table" of connector methods + ***********************************************************************/ + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + static const char* s_VT_GetType (CONNECTOR connector); + static EIO_Status s_VT_Open (CONNECTOR connector, + const STimeout* timeout); + static EIO_Status s_VT_Wait (CONNECTOR connector, + EIO_Event event, + const STimeout* timeout); + static EIO_Status s_VT_Write (CONNECTOR connector, + const void* buf, + size_t size, + size_t* n_written, + const STimeout* timeout); + static EIO_Status s_VT_Read (CONNECTOR connector, + void* buf, + size_t size, + size_t* n_read, + const STimeout* timeout); + static EIO_Status s_VT_Flush (CONNECTOR connector, + const STimeout* timeout); + static EIO_Status s_VT_Status (CONNECTOR connector, + EIO_Event dir); + static EIO_Status s_VT_Close (CONNECTOR connector, + const STimeout* timeout); + static void s_Setup (SMetaConnector* meta, + CONNECTOR connector); + static void s_Destroy (CONNECTOR connector); +# ifdef IMPLEMENTED__CONN_WaitAsync + static EIO_Status s_VT_WaitAsync(void* connector, + FConnectorAsyncHandler func, + SConnectorAsyncHandler* data); +# endif +#ifdef __cplusplus +} /* extern "C" */ +#endif /* __cplusplus */ + + +/*ARGSUSED*/ +static const char* s_VT_GetType +(CONNECTOR connector) +{ + return "FTP"; +} + + +static EIO_Status s_VT_Open +(CONNECTOR connector, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + EIO_Status status; + + assert(!xxx->data && !xxx->cntl); + status = SOCK_CreateEx(xxx->host, xxx->port, timeout, &xxx->cntl, + 0, 0, xxx->log); + if (status == eIO_Success) + status = s_FTPLogin(xxx, timeout); + if (status == eIO_Success) + status = s_FTPChdir(xxx, 0); + if (status == eIO_Success) + status = s_FTPBinary(xxx); + if (status != eIO_Success) { + if (xxx->cntl) { + SOCK_Close(xxx->cntl); + xxx->cntl = 0; + } + } + xxx->r_status = status; + xxx->w_status = status; + return status; +} + + +static EIO_Status s_VT_Write +(CONNECTOR connector, + const void* buf, + size_t size, + size_t* n_written, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + EIO_Status status; + const char* c; + size_t s; + + xxx->w_status = eIO_Success; + if ( !size ) + return eIO_Success; + if (!xxx->cntl) + return eIO_Closed; + + if ((c = strchr((const char*) buf, '\n')) != 0) { + if (c[1]) + return eIO_Unknown; + if (c != buf && c[-1] == '\r') + c--; + s = (size_t)(c - (const char*) buf); + } else + s = size; + status = BUF_Write(&xxx->wbuf, buf, s) ? eIO_Success : eIO_Unknown; + if (status == eIO_Success && c) { + xxx->w_status = s_FTPExecute(xxx, timeout); + status = xxx->w_status; + } + *n_written = size; + return status; +} + + +static EIO_Status s_VT_Read +(CONNECTOR connector, + void* buf, + size_t size, + size_t* n_read, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + EIO_Status status = eIO_Closed; + xxx->r_status = eIO_Success; + if (xxx->cntl && xxx->data) { + status = SOCK_SetTimeout(xxx->data, eIO_Read, timeout); + if (status == eIO_Success) { + xxx->r_status = SOCK_Read(xxx->data, + buf, size, n_read, eIO_ReadPlain); + if (xxx->r_status == eIO_Closed) { + int code; + SOCK_Close(xxx->data); + xxx->data = 0; + SOCK_SetTimeout(xxx->cntl, eIO_Read, timeout); + s_FTPReply(xxx, &code, 0, 0); + } + status = xxx->r_status; + } + } + return status; +} + + +static EIO_Status s_VT_Wait +(CONNECTOR connector, + EIO_Event event, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + if (!xxx->cntl) + return eIO_Closed; + if (event & eIO_Write) + return eIO_Success; + if (!xxx->data) { + EIO_Status status; + if (!BUF_Size(xxx->wbuf)) + return eIO_Closed; + if ((status = s_FTPExecute(xxx, timeout)) != eIO_Success) + return status; + if (!xxx->data) + return eIO_Closed; + } + return SOCK_Wait(xxx->data, eIO_Read, timeout); +} + + +static EIO_Status s_VT_Flush +(CONNECTOR connector, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + size_t size = BUF_Size(xxx->wbuf); + EIO_Status status = eIO_Success; + if (size != 0) + status = s_FTPExecute(xxx, timeout); + return status; +} + + +static EIO_Status s_VT_Status +(CONNECTOR connector, + EIO_Event dir) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + + switch (dir) { + case eIO_Read: + return xxx->r_status; + case eIO_Write: + return xxx->w_status; + default: + assert(0); /* should never happen as checked by connection */ + return eIO_InvalidArg; + } +} + + +/*ARGSUSED*/ +static EIO_Status s_VT_Close +(CONNECTOR connector, + const STimeout* timeout) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + if (xxx->cntl) + SOCK_SetTimeout(xxx->cntl, eIO_ReadWrite, timeout); + return s_FTPQuit(xxx); +} + + +static void s_Setup +(SMetaConnector* meta, + CONNECTOR connector) +{ + /* initialize virtual table */ + CONN_SET_METHOD(meta, get_type, s_VT_GetType, connector); + CONN_SET_METHOD(meta, open, s_VT_Open, connector); + CONN_SET_METHOD(meta, wait, s_VT_Wait, connector); + CONN_SET_METHOD(meta, write, s_VT_Write, connector); + CONN_SET_METHOD(meta, flush, s_VT_Flush, connector); + CONN_SET_METHOD(meta, read, s_VT_Read, connector); + CONN_SET_METHOD(meta, status, s_VT_Status, connector); + CONN_SET_METHOD(meta, close, s_VT_Close, connector); +#ifdef IMPLEMENTED__CONN_WaitAsync + CONN_SET_METHOD(meta, wait_async, s_VT_WaitAsync, connector); +#endif + meta->default_timeout = 0/*infinite*/; +} + + +static void s_Destroy +(CONNECTOR connector) +{ + SFTPConnector* xxx = (SFTPConnector*) connector->handle; + free((void*) xxx->host); + free((void*) xxx->user); + free((void*) xxx->pass); + if (xxx->path) + free((void*) xxx->path); + if (xxx->name) + free((void*) xxx->name); + BUF_Destroy(xxx->wbuf); + free(xxx); + connector->handle = 0; + free(connector); +} + + +/*********************************************************************** + * EXTERNAL -- the connector's "constructors" + ***********************************************************************/ + +extern CONNECTOR FTP_CreateDownloadConnector(const char* host, + unsigned short port, + const char* user, + const char* pass, + const char* path, + ESwitch log) +{ + CONNECTOR ccc = (SConnector*) malloc(sizeof(SConnector)); + SFTPConnector* xxx = (SFTPConnector*) malloc(sizeof(*xxx)); + + xxx->data = 0; + xxx->cntl = 0; + xxx->wbuf = 0; + xxx->host = strdup(host); + xxx->port = port ? port : 21; + xxx->user = strdup(user ? user : "ftp"); + xxx->pass = strdup(pass ? pass : "none"); + xxx->path = path && *path ? strdup(path) : 0; + xxx->name = 0; + xxx->log = log; + /* initialize connector data */ + ccc->handle = xxx; + ccc->next = 0; + ccc->meta = 0; + ccc->setup = s_Setup; + ccc->destroy = s_Destroy; + + return ccc; +} + + +/* + * -------------------------------------------------------------------------- + * $Log: ncbi_ftp_connector.c,v $ + * Revision 1.7 2005/04/20 18:15:59 lavr + * +<assert.h> + * + * Revision 1.6 2005/01/27 18:59:52 lavr + * Explicit cast of malloc()ed memory + * + * Revision 1.5 2005/01/05 17:40:13 lavr + * FEAT extensions and fixes for protocol compliance + * + * Revision 1.4 2004/12/27 15:31:27 lavr + * Implement telnet SYNCH and FTP ABORT according to the standard + * + * Revision 1.3 2004/12/08 21:03:26 lavr + * Fixes for default ctor parameters + * + * Revision 1.2 2004/12/07 14:21:55 lavr + * Init wbuf in ctor + * + * Revision 1.1 2004/12/06 17:48:38 lavr + * Initial revision + * + * ========================================================================== + */ diff --git a/connect/ncbi_ftp_connector.h b/connect/ncbi_ftp_connector.h new file mode 100644 index 00000000..d7c6ca44 --- /dev/null +++ b/connect/ncbi_ftp_connector.h @@ -0,0 +1,84 @@ +#ifndef CONNECT___NCBI_FTP_CONNECTOR__H +#define CONNECT___NCBI_FTP_CONNECTOR__H + +/* $Id: ncbi_ftp_connector.h,v 1.1 2004/12/06 17:48:19 lavr Exp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * FTP CONNECTOR + * + * See <connect/ncbi_connector.h> for the detailed specification of + * the connector's methods and structures. + * + */ + +#include <connect/ncbi_buffer.h> +#include <connect/ncbi_connector.h> + + +/** @addtogroup Connectors + * + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Create new CONNECTOR structure to handle ftp download transfer. + * Return NULL on error. + */ +extern NCBI_XCONNECT_EXPORT CONNECTOR FTP_CreateDownloadConnector +(const char* host, /* hostname, required */ + unsigned short port, /* port #, 21 [standard] if 0 passed here */ + const char* user, /* username, "ftp" [==anonymous] by default */ + const char* pass, /* password, "none" by default */ + const char* path, /* initial directory to chdir to on open */ + ESwitch log /* whether to turn on socket debugging [optional] */ +); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +/* @} */ + + +/* + * -------------------------------------------------------------------------- + * $Log: ncbi_ftp_connector.h,v $ + * Revision 1.1 2004/12/06 17:48:19 lavr + * Initial revision + * + * ========================================================================== + */ + +#endif /* CONNECT___NCBI_FTP_CONNECTOR__H */ diff --git a/connect/ncbi_heapmgr.c b/connect/ncbi_heapmgr.c index 7a2767f5..6b9dab8c 100644 --- a/connect/ncbi_heapmgr.c +++ b/connect/ncbi_heapmgr.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_heapmgr.c,v 6.26 2003/10/02 14:52:23 lavr Exp $ +/* $Id: ncbi_heapmgr.c,v 6.27 2005/01/27 19:00:17 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -181,7 +181,7 @@ HEAP HEAP_AttachEx(const void* base, TNCBI_Size size) { HEAP heap; - if (!base || !size || !(heap = malloc(sizeof(*heap)))) + if (!base || !size || !(heap = (HEAP) malloc(sizeof(*heap)))) return 0; if ((void*) HEAP_ALIGN(base) != base) { CORE_LOGF(eLOG_Warning, @@ -573,6 +573,9 @@ int HEAP_Serial(const HEAP heap) /* * -------------------------------------------------------------------------- * $Log: ncbi_heapmgr.c,v $ + * Revision 6.27 2005/01/27 19:00:17 lavr + * Explicit cast of malloc()ed memory + * * Revision 6.26 2003/10/02 14:52:23 lavr * Wrapped long lines in the change log * diff --git a/connect/ncbi_http_connector.c b/connect/ncbi_http_connector.c index 1d57a475..61d508fa 100644 --- a/connect/ncbi_http_connector.c +++ b/connect/ncbi_http_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_http_connector.c,v 6.63 2004/02/12 16:50:02 lavr Exp $ +/* $Id: ncbi_http_connector.c,v 6.65 2005/03/08 16:23:13 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -415,12 +415,11 @@ static EIO_Status s_ReadHeader(SHttpConnector* uuu, char** redirect) /* skip & printout the content, if server error was flagged */ if (server_error && uuu->net_info->debug_printout == eDebugPrintout_Some) { BUF buf = 0; - EIO_Status status; char* body; SOCK_SetTimeout(uuu->sock, eIO_Read, 0); - status = SOCK_StripToPattern(uuu->sock, 0, 0, &buf, 0); - assert(status != eIO_Success); /* because reading until EOF */ + /* because reading until EOF the verify below holds */ + verify(SOCK_StripToPattern(uuu->sock, 0, 0, &buf, 0) != eIO_Success); if (!(size = BUF_Size(buf))) { CORE_LOG(eLOG_Trace, "[HTTP] No body received with this error"); } else if ((body = (char*) malloc(size)) != 0) { @@ -918,7 +917,7 @@ extern CONNECTOR HTTP_CreateConnector net_info = info ? ConnNetInfo_Clone(info) : ConnNetInfo_Create(0); if (user_header) - ConnNetInfo_SetUserHeader(net_info, user_header); + ConnNetInfo_OverrideUserHeader(net_info, user_header); connector = HTTP_CreateConnectorEx(net_info, flags, 0, 0, 0, 0); ConnNetInfo_Destroy(net_info); return connector; @@ -976,6 +975,12 @@ extern CONNECTOR HTTP_CreateConnectorEx /* * -------------------------------------------------------------------------- * $Log: ncbi_http_connector.c,v $ + * Revision 6.65 2005/03/08 16:23:13 lavr + * Replace an assert() with verify() to remove release-mode unused var + * + * Revision 6.64 2005/02/28 17:59:07 lavr + * HTTP_CreateConnector() to "override" addtl. user header instead of "set" + * * Revision 6.63 2004/02/12 16:50:02 lavr * Heed warning about uninited variable use * diff --git a/connect/ncbi_memory_connector.c b/connect/ncbi_memory_connector.c index 260316a2..965fa9cb 100644 --- a/connect/ncbi_memory_connector.c +++ b/connect/ncbi_memory_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_memory_connector.c,v 6.5 2003/05/31 05:15:39 lavr Exp $ +/* $Id: ncbi_memory_connector.c,v 6.8 2005/04/20 18:15:59 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,6 +35,7 @@ #include <connect/ncbi_buffer.h> #include <connect/ncbi_memory_connector.h> +#include <assert.h> #include <stdlib.h> @@ -45,10 +46,11 @@ /* All internal data necessary to perform the (re)connect and i/o */ typedef struct { - BUF buf; - MT_LOCK lock; - EIO_Status r_status; - EIO_Status w_status; + BUF buf; + MT_LOCK lock; + int/*bool*/ own_buf; + EIO_Status r_status; + EIO_Status w_status; } SMemoryConnector; @@ -106,7 +108,6 @@ static EIO_Status s_VT_Open const STimeout* timeout) { SMemoryConnector* xxx = (SMemoryConnector*) connector->handle; - xxx->buf = 0; xxx->r_status = eIO_Success; xxx->w_status = eIO_Success; return eIO_Success; @@ -201,7 +202,7 @@ static EIO_Status s_VT_Close const STimeout* timeout) { SMemoryConnector* xxx = (SMemoryConnector*) connector->handle; - BUF_Destroy(xxx->buf); + BUF_Erase(xxx->buf); return eIO_Success; } @@ -230,7 +231,8 @@ static void s_Destroy (CONNECTOR connector) { SMemoryConnector* xxx = (SMemoryConnector*) connector->handle; - + if (xxx->own_buf) + BUF_Destroy(xxx->buf); free(xxx); connector->handle = 0; free(connector); @@ -243,11 +245,19 @@ static void s_Destroy extern CONNECTOR MEMORY_CreateConnector(MT_LOCK lock) { + return MEMORY_CreateConnectorEx(0, lock); +} + + +extern CONNECTOR MEMORY_CreateConnectorEx(BUF buf, MT_LOCK lock) +{ CONNECTOR ccc = (SConnector*) malloc(sizeof(SConnector)); SMemoryConnector* xxx = (SMemoryConnector*) malloc(sizeof(*xxx)); /* initialize internal data structures */ + xxx->buf = buf; xxx->lock = lock; + xxx->own_buf = buf ? 0/*false*/ : 1/*true*/; /* initialize connector data */ ccc->handle = xxx; @@ -263,6 +273,15 @@ extern CONNECTOR MEMORY_CreateConnector(MT_LOCK lock) /* * -------------------------------------------------------------------------- * $Log: ncbi_memory_connector.c,v $ + * Revision 6.8 2005/04/20 18:15:59 lavr + * +<assert.h> + * + * Revision 6.7 2004/10/27 19:16:33 lavr + * Reuse MEMORY_CreateConnectorEx() in MEMORY_CreateConnector() + * + * Revision 6.6 2004/10/27 18:44:56 lavr + * +MEMORY_CreateConnectorEx() and not-owned buffer management + * * Revision 6.5 2003/05/31 05:15:39 lavr * Add ARGSUSED where args are meant to be unused, remove Flush * diff --git a/connect/ncbi_memory_connector.h b/connect/ncbi_memory_connector.h index 93512514..cd172992 100644 --- a/connect/ncbi_memory_connector.h +++ b/connect/ncbi_memory_connector.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_MEMORY_CONNECTOR__H #define CONNECT___NCBI_MEMORY_CONNECTOR__H -/* $Id: ncbi_memory_connector.h,v 6.4 2003/04/09 19:05:45 siyan Exp $ +/* $Id: ncbi_memory_connector.h,v 6.5 2004/10/27 18:44:14 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -36,6 +36,7 @@ * */ +#include <connect/ncbi_buffer.h> #include <connect/ncbi_connector.h> @@ -57,6 +58,9 @@ extern "C" { extern NCBI_XCONNECT_EXPORT CONNECTOR MEMORY_CreateConnector(MT_LOCK lock); +extern NCBI_XCONNECT_EXPORT CONNECTOR MEMORY_CreateConnectorEx(BUF buf, + MT_LOCK lock); + #ifdef __cplusplus } /* extern "C" */ #endif @@ -68,6 +72,9 @@ extern NCBI_XCONNECT_EXPORT CONNECTOR MEMORY_CreateConnector(MT_LOCK lock); /* * -------------------------------------------------------------------------- * $Log: ncbi_memory_connector.h,v $ + * Revision 6.5 2004/10/27 18:44:14 lavr + * +MEMORY_CreateConnectorEx() + * * Revision 6.4 2003/04/09 19:05:45 siyan * Added doxygen support * diff --git a/connect/ncbi_priv.h b/connect/ncbi_priv.h index 3b3b1e6f..9ea87e46 100644 --- a/connect/ncbi_priv.h +++ b/connect/ncbi_priv.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_PRIV__H #define CONNECT___NCBI_PRIV__H -/* $Id: ncbi_priv.h,v 6.10 2004/03/12 23:25:37 gorelenk Exp $ +/* $Id: ncbi_priv.h,v 6.11 2005/04/20 18:14:10 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,6 +41,7 @@ * */ +#include "ncbi_assert.h" #include <connect/ncbi_util.h> @@ -183,6 +184,9 @@ extern NCBI_XCONNECT_EXPORT char* g_CORE_RegistryGET /* * --------------------------------------------------------------------------- * $Log: ncbi_priv.h,v $ + * Revision 6.11 2005/04/20 18:14:10 lavr + * +"ncbi_assert.h" + * * Revision 6.10 2004/03/12 23:25:37 gorelenk * Added export prefixes. * diff --git a/connect/ncbi_sendmail.c b/connect/ncbi_sendmail.c index bf3c4bc8..a0b85953 100644 --- a/connect/ncbi_sendmail.c +++ b/connect/ncbi_sendmail.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_sendmail.c,v 6.22 2004/01/07 19:51:36 lavr Exp $ +/* $Id: ncbi_sendmail.c,v 6.23 2005/03/18 16:35:39 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -419,8 +419,9 @@ const char* CORE_SendMailEx(const char* to, CORE_LOG(eLOG_Warning,"[SendMail] Subject ignored in as-is messages"); if (!s_SockWrite(sock, "X-Mailer: CORE_SendMail (NCBI " - NCBI_SENDMAIL_TOOLKIT " Toolkit)" MX_CRLF)) + NCBI_SENDMAIL_TOOLKIT " Toolkit)" MX_CRLF)) { SENDMAIL_RETURN("Write error in sending mailer information"); + } assert(sizeof(buffer) > sizeof(MX_CRLF) && sizeof(MX_CRLF) >= 3); @@ -435,7 +436,7 @@ const char* CORE_SendMailEx(const char* to, k += sizeof(MX_CRLF) - 1; newline = 1/*true*/; } else { - if (info->header[n] != '\r' || !newline) + if (info->header[n] != '\r' || info->header[n+1] != '\n') buffer[k++] = info->header[n]; newline = 0/*false*/; } @@ -465,7 +466,7 @@ const char* CORE_SendMailEx(const char* to, k += sizeof(MX_CRLF) - 1; newline = 1/*true*/; } else { - if (body[n] != '\r' || !newline) { + if (body[n] != '\r' || (n+1 < m && body[n+1] != '\n')){ if (body[n] == '.' && (newline || !n)) { buffer[k++] = '.'; buffer[k++] = '.'; @@ -508,6 +509,9 @@ const char* CORE_SendMailEx(const char* to, /* * --------------------------------------------------------------------------- * $Log: ncbi_sendmail.c,v $ + * Revision 6.23 2005/03/18 16:35:39 lavr + * Fix \r\n parse bug in both header and body + * * Revision 6.22 2004/01/07 19:51:36 lavr * Try to obtain user name from USERNAME env.var. on Windows, else fallback * diff --git a/connect/ncbi_sendmail.h b/connect/ncbi_sendmail.h index ef2f3881..6894fe2f 100644 --- a/connect/ncbi_sendmail.h +++ b/connect/ncbi_sendmail.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SENDMAIL__H #define CONNECT___NCBI_SENDMAIL__H -/* $Id: ncbi_sendmail.h,v 6.16 2003/12/09 15:38:02 lavr Exp $ +/* $Id: ncbi_sendmail.h,v 6.17 2005/04/28 14:18:12 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -72,8 +72,8 @@ typedef struct { /* NOTE about recipient lists: * They are not parsed; valid recipient (according to the standard) * can be specified in the form "Name" <address>; recipients should - * be separated by commas. In case of address-only recipients (no "Name" - * part above), angle brackets around the address may be omitted. + * be separated by commas. In case of address-only recipients (with no + * "Name" part above), angle brackets around the address may be omitted. * * NOTE about message body size: * If not specified (0) and by default the message body size is calculated @@ -148,6 +148,9 @@ extern NCBI_XCONNECT_EXPORT const char* CORE_SendMailEx /* * -------------------------------------------------------------------------- * $Log: ncbi_sendmail.h,v $ + * Revision 6.17 2005/04/28 14:18:12 lavr + * A bit of clarification about multiple/single email address formats + * * Revision 6.16 2003/12/09 15:38:02 lavr * +SSendMailInfo::body_size and remarks about its use * diff --git a/connect/ncbi_server_info.c b/connect/ncbi_server_info.c index 090d3311..ed6438fd 100644 --- a/connect/ncbi_server_info.c +++ b/connect/ncbi_server_info.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_server_info.c,v 6.53 2003/09/02 21:21:42 lavr Exp $ +/* $Id: ncbi_server_info.c,v 6.54 2005/04/20 18:15:59 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #include "ncbi_ansi_ext.h" #include "ncbi_server_infop.h" +#include <assert.h> #include <ctype.h> #include <math.h> #include <stdio.h> @@ -838,6 +839,9 @@ static const SSERV_Attr* s_GetAttrByTag(const char* tag) /* * -------------------------------------------------------------------------- * $Log: ncbi_server_info.c,v $ + * Revision 6.54 2005/04/20 18:15:59 lavr + * +<assert.h> + * * Revision 6.53 2003/09/02 21:21:42 lavr * Cleanup included headers * diff --git a/connect/ncbi_service.c b/connect/ncbi_service.c index 4c254c54..0d37c804 100644 --- a/connect/ncbi_service.c +++ b/connect/ncbi_service.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_service.c,v 6.55 2004/08/19 15:48:35 lavr Exp $ +/* $Id: ncbi_service.c,v 6.61 2005/04/25 18:47:29 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -132,7 +132,9 @@ static SERV_ITER s_Open(const char* service, TSERV_Type types, unsigned int preferred_host, double preference, const SConnNetInfo* net_info, const SSERV_Info* const skip[], size_t n_skip, - SSERV_Info** info, HOST_INFO* host_info, int external) + SSERV_Info** info, HOST_INFO* host_info, + int/*bool*/ external, unsigned int origin, + const char* arg, const char* val) { const char* s = s_ServiceName(service, 0); const SSERV_VTable* op; @@ -142,6 +144,7 @@ static SERV_ITER s_Open(const char* service, TSERV_Type types, return 0; iter->service = s; + iter->current = 0; iter->types = types; iter->preferred_host = preferred_host == SERV_LOCALHOST ? SOCK_gethostbyname(0) : preferred_host; @@ -153,6 +156,11 @@ static SERV_ITER s_Open(const char* service, TSERV_Type types, iter->op = 0; iter->data = 0; iter->external = external; + iter->origin = origin; + iter->arg = arg; + iter->arglen = arg ? strlen(arg) : 0; + iter->val = val; + iter->vallen = val ? strlen(val) : 0; if (n_skip) { size_t i; @@ -203,17 +211,20 @@ SERV_ITER SERV_OpenEx(const char* service, const SConnNetInfo* net_info, const SSERV_Info* const skip[], size_t n_skip) { - return s_Open(service, types, preferred_host, 0.0, - net_info, skip, n_skip, 0, 0, 0/*not external*/); + return s_Open(service, types, preferred_host, 0.0/*preference*/, + net_info, skip, n_skip, 0/*info*/, 0/*host_info*/, + 0/*not external*/, 0/*origin*/, 0/*arg*/, 0/*val*/); } SERV_ITER SERV_OpenP(const char* service, TSERV_Type types, unsigned int preferred_host, double preference, - int/*bool*/ external) + int/*bool*/ external, SConnNetInfo* net_info, + unsigned int origin, const char* arg, const char* val) { return s_Open(service, types, preferred_host, preference, - 0, 0, 0, 0, 0, external); + net_info, 0/*skip*/, 0/*n_skip*/, 0/*info*/, 0/*hinfo*/, + external, origin, arg, val); } @@ -221,11 +232,14 @@ static SSERV_Info* s_GetInfo(const char* service, TSERV_Type types, unsigned int preferred_host, double preference, const SConnNetInfo* net_info, const SSERV_Info* const skip[], size_t n_skip, - HOST_INFO* host_info, int/*bool*/ external) + HOST_INFO* host_info, + int/*bool*/ external, unsigned int origin, + const char* arg, const char* val) { SSERV_Info* info = 0; SERV_ITER iter= s_Open(service, types, preferred_host, preference, - net_info, skip, n_skip, &info, host_info, external); + net_info, skip, n_skip, &info, host_info, + external, origin, arg, val); if (iter && !info && iter->op && iter->op->GetNextInfo) info = (*iter->op->GetNextInfo)(iter, host_info); SERV_Close(iter); @@ -239,17 +253,20 @@ SSERV_Info* SERV_GetInfoEx(const char* service, TSERV_Type types, const SSERV_Info* const skip[], size_t n_skip, HOST_INFO* host_info) { - return s_GetInfo(service, types, preferred_host, 0.0, - net_info, skip, n_skip, host_info, 0/*not external*/); + return s_GetInfo(service, types, preferred_host, 0.0/*preference*/, + net_info, skip, n_skip, host_info, + 0/*not external*/, 0/*origin*/, 0/*arg*/, 0/*val*/); } SSERV_Info* SERV_GetInfoP(const char* service, TSERV_Type types, unsigned int preferred_host, double preference, - int/*bool*/ external) + int/*bool*/ external, SConnNetInfo* net_info, + unsigned int origin, const char* arg,const char* val) { return s_GetInfo(service, types, preferred_host, preference, - 0, 0, 0, 0, external); + net_info, 0/*skip*/, 0/*n_skip*/, 0/*host_info*/, + external, origin, arg, val); } @@ -302,10 +319,16 @@ const char* SERV_MapperName(SERV_ITER iter) } +const char* SERV_GetCurrentName(SERV_ITER iter) +{ + return iter->current ? iter->current : iter->service; +} + + int/*bool*/ SERV_Penalize(SERV_ITER iter, double fine) { if (!iter || !iter->op || !iter->op->Penalize || !iter->last) - return 0; + return 0/*false*/; return (*iter->op->Penalize)(iter, fine); } @@ -321,6 +344,10 @@ void SERV_Reset(SERV_ITER iter) size_t i; if (!iter) return; + if (iter->current) { + free((void*) iter->current); + iter->current = 0; + } for (i = 0; i < iter->n_skip; i++) free(iter->skip[i]); iter->n_skip = 0; @@ -393,6 +420,7 @@ char* SERV_PrintEx(SERV_ITER iter, const SConnNetInfo* referrer) static const char referrer_header[] = "Referer: "/*standard misspelling*/; static const char client_revision[] = "Client-Revision: %hu.%hu\r\n"; static const char accepted_types[] = "Accepted-Server-Types:"; + static const char server_count[] = "Server-Count: all\r\n"; char buffer[128], *str; TSERV_Type types, t; size_t buflen, i; @@ -467,6 +495,13 @@ char* SERV_PrintEx(SERV_ITER iter, const SConnNetInfo* referrer) return 0; } } + /* how many for the dispatcher to send to us */ + if (iter->preference) { + if (!BUF_Write(&buf, server_count, sizeof(server_count) - 1)) { + BUF_Destroy(buf); + return 0; + } + } /* Drop any outdated skip entries */ s_SkipSkip(iter); /* Put all the rest into rejection list */ @@ -522,21 +557,41 @@ char* SERV_Print(SERV_ITER iter) */ double SERV_Preference(double pref, double gap, unsigned int n) { + double spread; assert(0.0 <= pref && pref <= 1.0); assert(0.0 < gap && gap <= 1.0); assert(n >= 2); if (gap >= pref) return gap; - else if (gap >= 0.75*(1.0/(double) n)) + spread = 14.0/(n + 12.0); + if (gap >= spread*(1.0/(double) n)) return pref; else - return 2.5*gap*pref; + return 2.0/spread*gap*pref; } /* * -------------------------------------------------------------------------- * $Log: ncbi_service.c,v $ + * Revision 6.61 2005/04/25 18:47:29 lavr + * Private API to accept SConnNetInfo* for network dispatching to work too + * + * Revision 6.60 2005/04/19 16:32:19 lavr + * Cosmetics + * + * Revision 6.59 2005/03/05 21:05:26 lavr + * +SERV_ITER::current; +SERV_GetCurrentName() + * + * Revision 6.58 2005/01/31 17:09:55 lavr + * Argument affinity moved into service iterator + * + * Revision 6.57 2005/01/05 19:15:26 lavr + * Do not use C99-compliant declaration, kills MSVC compilation + * + * Revision 6.56 2005/01/05 17:39:07 lavr + * SERV_Preference() modified to use better load distribution + * * Revision 6.55 2004/08/19 15:48:35 lavr * SERV_ITER::type renamed into SERV_ITER::types to reflect its bitmask nature * diff --git a/connect/ncbi_service.h b/connect/ncbi_service.h index 4e7c81f2..a11db9d0 100644 --- a/connect/ncbi_service.h +++ b/connect/ncbi_service.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVICE__H #define CONNECT___NCBI_SERVICE__H -/* $Id: ncbi_service.h,v 6.34 2004/08/19 15:26:54 lavr Exp $ +/* $Id: ncbi_service.h,v 6.36 2005/03/05 21:04:11 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -62,11 +62,11 @@ typedef struct SSERV_IterTag* SERV_ITER; /* Create an iterator for the iterative server lookup. - * Connection information 'info' can be a NULL pointer, which means - * not to make any network connections (only LBSMD will be consulted). - * If 'info' is not NULL, LBSMD is consulted first (unless 'info->lb_disable' - * is non-zero, meaning to skip LBSMD), and then DISPD is consulted - * (using the information provided) but only if mapping with LBSMD (if any) + * Connection information 'net_info' can be a NULL pointer, which means + * not to make any network connections (only LBSMD will be consulted). If + * 'net_info' is not NULL, LBSMD is consulted first (unless 'net_info->lb_disable' + * is non-zero, meaning to skip LBSMD), and then DISPD is consulted (using + * the information provided) but only if mapping with LBSMD (if any) * has failed. This scheme permits to use any combination of service mappers. * Note that if 'info' is not NULL then non-zero value of 'info->stateless' * forces 'types' to have 'fSERV_StatelessOnly' set. @@ -91,6 +91,8 @@ extern NCBI_XCONNECT_EXPORT SERV_ITER SERV_OpenSimple /* Can be combined in types to get even dead services (not off ones!) */ #define fSERV_Promiscuous 0x80000000 +/* Do reverse DNS translation of the resulting info */ +#define fSERV_ReverseDns 0x40000000 extern NCBI_XCONNECT_EXPORT SERV_ITER SERV_OpenEx @@ -202,6 +204,12 @@ extern NCBI_XCONNECT_EXPORT void DISP_SetMessageHook(FDISP_MessageHook); /* * -------------------------------------------------------------------------- * $Log: ncbi_service.h,v $ + * Revision 6.36 2005/03/05 21:04:11 lavr + * +fSERV_ReverseDns + * + * Revision 6.35 2005/01/31 17:08:35 lavr + * info -> net_info where appropriate for consistency + * * Revision 6.34 2004/08/19 15:26:54 lavr * +fSERV_Promiscuous * diff --git a/connect/ncbi_servicep.h b/connect/ncbi_servicep.h index 44b68738..0552dc6c 100644 --- a/connect/ncbi_servicep.h +++ b/connect/ncbi_servicep.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SERVICEP__H #define CONNECT___NCBI_SERVICEP__H -/* $Id: ncbi_servicep.h,v 6.25 2004/08/19 15:48:04 lavr Exp $ +/* $Id: ncbi_servicep.h,v 6.29 2005/04/25 18:47:29 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,26 +57,38 @@ typedef struct { /* Iterator structure */ struct SSERV_IterTag { - const char* service; /* requested service name */ - TSERV_Type types; /* requested server type(s) */ - unsigned int preferred_host; /* preferred host to select, network b.o. */ - double preference; /* range [0..100] %% */ - SSERV_Info** skip; /* servers to skip */ - size_t n_skip; /* number of servers in the array */ - size_t n_max_skip; /* number of allocated slots in the array */ - SSERV_Info* last; /* last server info taken out */ - - const SSERV_VTable* op; /* table of virtual functions */ - - void* data; /* private data field */ - int/*bool*/ external; /* true for mapping of external requests */ + const char* service; /* requested service name, private storage */ + const char* current; /* current service name, private storage */ + TSERV_Type types; /* requested server type(s) */ + unsigned int preferred_host; /* preferred host to select, network b.o. */ + double preference; /* range [0..100] %% */ + SSERV_Info** skip; /* servers to skip */ + size_t n_skip; /* number of servers in the array */ + size_t n_max_skip; /* number of allocated slots in the array */ + SSERV_Info* last; /* last server info taken out */ + + const SSERV_VTable* op; /* table of virtual functions */ + + void* data; /* private data field */ + int/*bool*/ external; /* whether this is an external request */ + unsigned int origin; /* IP of the origin */ + const char* arg; /* argument to match; original pointer */ + size_t arglen; /* == 0 for NULL pointer above */ + const char* val; /* value to match; original pointer */ + size_t vallen; /* == 0 for NULL pointer above */ }; -/* Modified 'fast track' routine for one-shot obtaining of a service info. +/* Modified 'fast track' routine for obtaining of a service info in one-shot. * Please see <connect/ncbi_service.h> for explanations [SERV_GetInfoEx()]. * For now, this call is to exclusively support MYgethostbyname() replacement - * of standard gethostbyname() libcall in apache Web daemon (see in daemons/). + * of standard gethostbyname() libcall in Apache Web daemon (see in daemons/). + * + * CAUTION: unlike "service" parameter, "arg" and "val" are not copied from, + * but the orignal pointers get stored -- take this into account + * while dealing with dynamically allocated strings in the slow + * "iterator" version of the call below -- the pointers must remain + * valid as long as the iterator stays open (i.e. until SERV_Close()). * * NOTE: Preference 0.0 does not prohibit the preferred_host to be selected; * nor preference 100.0 ultimately opts for the preferred_host; rather, @@ -90,7 +102,11 @@ SSERV_Info* SERV_GetInfoP TSERV_Type types, /* mask of type(s) of servers requested */ unsigned int preferred_host,/* preferred host to use service on, nbo */ double preference, /* [0=min..100=max] preference in %% */ - int/*bool*/ external /* whether mapping is not local to NCBI */ + int/*bool*/ external, /* whether mapping is not local to NCBI */ + SConnNetInfo* net_info, /* for connection to dispatcher, m.b. 0 */ + unsigned int origin, /* origin IP */ + const char* arg, /* environment variable name to search */ + const char* val /* environment variable value to match */ ); /* same as the above but creates an iterator to get services one by one */ @@ -99,10 +115,19 @@ SERV_ITER SERV_OpenP TSERV_Type type, unsigned int preferred_host, double preference, - int/*bool*/ external + int/*bool*/ external, + SConnNetInfo* net_info, + unsigned int origin, + const char* arg, + const char* val ); +/* Return service name the iterator is currently working on. + */ +const char* SERV_GetCurrentName(SERV_ITER iter); + + /* Private interface: update mapper information from the given text * (<CR><LF> separated lines, usually taken from HTTP header). */ @@ -155,6 +180,18 @@ double SERV_Preference(double pref, double gap, unsigned int n); /* * -------------------------------------------------------------------------- * $Log: ncbi_servicep.h,v $ + * Revision 6.29 2005/04/25 18:47:29 lavr + * Private API to accept SConnNetInfo* for network dispatching to work too + * + * Revision 6.28 2005/04/19 16:33:00 lavr + * More comments on how things work (SERV_{GetInfo|Open}P) + * + * Revision 6.27 2005/03/05 21:05:07 lavr + * +SERV_ITER::current; +SERV_GetCurrentName() + * + * Revision 6.26 2005/01/31 17:09:34 lavr + * Argument affinity moved into service iterator + * * Revision 6.25 2004/08/19 15:48:04 lavr * SERV_ITER::type renamed into SERV_ITER::types to reflect its bitmask nature * diff --git a/connect/ncbi_socket.c b/connect/ncbi_socket.c index 16346a81..eae06402 100644 --- a/connect/ncbi_socket.c +++ b/connect/ncbi_socket.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_socket.c,v 6.149 2004/09/08 15:12:43 ucko Exp $ +/* $Id: ncbi_socket.c,v 6.174 2005/04/25 18:48:04 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -37,8 +37,8 @@ */ #include "ncbi_ansi_ext.h" #include "ncbi_priv.h" -/* The next header implicitly includes <connect/ncbi_socket.h> */ #include <connect/ncbi_connutil.h> +#include <connect/ncbi_socket_unix.h> /* OS must be specified in the command-line ("-D....") or in the conf. header */ @@ -46,7 +46,6 @@ # error "Unknown OS, must be one of NCBI_OS_UNIX, NCBI_OS_MSWIN, NCBI_OS_MAC!" #endif /*supported platforms*/ - /* Uncomment these(or specify "-DHAVE_GETADDRINFO -DHAVE_GETNAMEINFO") only if: * 0) you are compiling this outside of the NCBI C or C++ Toolkits * (USE_NCBICONF is not #define'd), and @@ -99,6 +98,9 @@ # include <fcntl.h> # include <sys/socket.h> # include <netinet/in.h> +# ifndef NCBI_COMPILER_METROWERKS +# include <netinet/tcp.h> +# endif # if !defined(NCBI_OS_BEOS) && !defined(NCBI_COMPILER_MW_MSL) # include <arpa/inet.h> # endif /*NCBI_OS_BEOS*/ @@ -106,7 +108,7 @@ # include <sys/un.h> #elif defined(NCBI_OS_MSWIN) -# ifndef COMP_METRO +# ifndef NCBI_COMPILER_METROWERKS # include <winsock2.h> # else # define SD_RECEIVE 0x00 @@ -127,7 +129,6 @@ # error "Unsupported platform, must be one of NCBI_OS_UNIX, NCBI_OS_MSWIN, NCBI_OS_MAC !!!" #endif /* platform-specific headers (for UNIX, MSWIN, MAC) */ - /* Portable standard C headers */ #include <errno.h> @@ -254,6 +255,11 @@ typedef int TSOCK_Handle; #endif /*NCBI_OS_MSWIN, NCBI_OS_UNIX, NCBI_OS_MAC*/ +#ifdef sun +#undef sun +#endif + + #ifdef HAVE_SOCKLEN_T typedef socklen_t SOCK_socklen_t; #else @@ -288,12 +294,12 @@ typedef unsigned EBSockType; /* Listening socket */ -struct LSOCK_tag { +typedef struct LSOCK_tag { TSOCK_Handle sock; /* OS-specific socket handle */ unsigned int id; /* the internal ID (see also "s_ID_Counter") */ unsigned int n_accept; /* total number of accepted clients */ - unsigned short port; /* port on which the socket is listening */ + unsigned short port; /* port on which listening (host byte order) */ /* type, status, EOF, log, read-on-write etc bit-field indicators */ EBSwitch log:2; /* how to log events and data for this socket*/ @@ -304,12 +310,16 @@ struct LSOCK_tag { unsigned/*bool*/ eof:1; /* 0 */ EBIO_Status w_status:3; /* MBZ (NB: eIO_Success) */ unsigned/*bool*/ pending:1; /* 0 */ -}; + +#ifdef NCBI_OS_UNIX + char path[1]; /* must go last */ +#endif /*NCBI_OS_UNIX*/ +} LSOCK_struct; -/* Socket [it must be in one-2-one correspondence with LSOCK above] +/* Socket [it must be in one-2-one binary correspondence with LSOCK above] */ -struct SOCK_tag { +typedef struct SOCK_tag { TSOCK_Handle sock; /* OS-specific socket handle */ unsigned int id; /* the internal ID (see also "s_ID_Counter") */ @@ -350,12 +360,13 @@ struct SOCK_tag { size_t n_in; /* DSOCK: msg #; SOCK: total # of bytes read */ size_t n_out; /* DSOCK: msg #; SOCK: total # of bytes sent */ + unsigned short myport; /* this socket's port number, host byte order*/ + #ifdef NCBI_OS_UNIX - /* filename for UNIX socket */ - char file[1]; /* must go last */ + /* pathname for UNIX socket */ + char path[1]; /* must go last */ #endif /*NCBI_OS_UNIX*/ -}; - +} SOCK_struct; /* @@ -609,8 +620,9 @@ static const char* s_ID(const SOCK sock, char* buf) */ static void s_DoLog (const SOCK sock, EIO_Event event, - const void* data, size_t size, const struct sockaddr* sa) + const void* data, size_t size, const void* ptr) { + const struct sockaddr* sa = (const struct sockaddr*) ptr; char head[128]; char tail[128]; char _id[32]; @@ -669,8 +681,10 @@ static void s_DoLog sprintf(tail + strlen(tail), ", msg# %u", (unsigned)(event == eIO_Read ? sock->n_in : sock->n_out)); } else { - assert(sa == 0); - *tail = 0; + if (sa) + strncpy0(tail, " OUT-OF-BAND", sizeof(tail) - 1); + else + *tail = '\0'; } sprintf(head, "%s%s%s at offset %lu%s%s", s_ID(sock, _id), event == eIO_Read @@ -683,7 +697,8 @@ static void s_DoLog (event == eIO_Read ? " while reading" : " while writing"), (unsigned long) (event == eIO_Read ? sock->n_read : sock->n_written), - sa ? (event == eIO_Read ? " from " : " to ") : "", tail); + sock->type == eSOCK_Datagram && sa + ? (event == eIO_Read ? " from " : " to ") : "", tail); CORE_DATA(data, size, head); break; case eIO_Close: @@ -736,7 +751,7 @@ extern ESwitch SOCK_SetDataLoggingAPI(ESwitch log) extern ESwitch SOCK_SetDataLogging(SOCK sock, ESwitch log) { - ESwitch old = sock->log; + ESwitch old = (ESwitch) sock->log; sock->log = log; return old; } @@ -759,6 +774,14 @@ extern void SOCK_AllowSigPipeAPI(void) #if 0/*defined(_DEBUG) && !defined(NDEBUG)*/ +# ifndef SOCK_HAVE_SHOWDATALAYOUT +# define SOCK_HAVE_SHOWDATALAYOUT 1 +# endif + +#endif /*_DEBUG && !NDEBUG*/ + +#ifdef SOCK_HAVE_SHOWDATALAYOUT + # if !defined(__GNUC__) && !defined(offsetof) # define offsetof(T, F) ((size_t)((char*) &(((T*) 0)->F) - (char*) 0)) # endif @@ -787,9 +810,10 @@ static void s_ShowDataLayout(void) "\tn_read: %u\n" "\tn_written: %u\n" "\tn_in: %u\n" - "\tn_out: %u" + "\tn_out: %u\n" + "\tmyport: %u" # ifdef NCBI_OS_UNIX - "\n\tfile: %u" + "\n\tpath: %u" # endif /*NCBI_OS_UNIX*/ , (unsigned int) sizeof(SOCK_struct), (unsigned int) offsetof(SOCK_struct, sock), @@ -811,14 +835,15 @@ static void s_ShowDataLayout(void) (unsigned int) offsetof(SOCK_struct, n_read), (unsigned int) offsetof(SOCK_struct, n_written), (unsigned int) offsetof(SOCK_struct, n_in), - (unsigned int) offsetof(SOCK_struct, n_out) + (unsigned int) offsetof(SOCK_struct, n_out), + (unsigned int) offsetof(SOCK_struct, myport) # ifdef NCBI_OS_UNIX - , (unsigned int) offsetoff(SOCK_struct, file) + , (unsigned int) offsetof(SOCK_struct, path) # endif /*NCBI_OS_UNIX*/ )); } -#endif +#endif /*SOCK_HAVE_SHOWDATALAYOUT*/ extern EIO_Status SOCK_InitializeAPI(void) @@ -831,9 +856,9 @@ extern EIO_Status SOCK_InitializeAPI(void) return eIO_Success; } -#if 0/*defined(_DEBUG) && !defined(NDEBUG)*/ +#ifdef SOCK_HAVE_SHOWDATALAYOUT s_ShowDataLayout(); -#endif +#endif /*SOCK_HAVE_SHOWDATALAYOUT*/ #if defined(NCBI_OS_MSWIN) {{ @@ -912,6 +937,7 @@ static STimeout *s_tv2to(const struct timeval* tv, STimeout* to) return to; } + static struct timeval* s_to2tv(const STimeout* to, struct timeval* tv) { if ( !to ) @@ -964,9 +990,9 @@ static EIO_Status s_Status(SOCK sock, EIO_Event direction) switch ( direction ) { case eIO_Read: return sock->type != eSOCK_Datagram && sock->eof - ? eIO_Closed : sock->r_status; + ? eIO_Closed : (EIO_Status) sock->r_status; case eIO_Write: - return sock->w_status; + return (EIO_Status) sock->w_status; default: /*should never get here*/ assert(0); @@ -1053,6 +1079,13 @@ static EIO_Status s_Select(size_t n, if (polls[i].event && (EIO_Event)(polls[i].event | eIO_ReadWrite) == eIO_ReadWrite) { TSOCK_Handle fd = polls[i].sock->sock; +#if !defined(NCBI_OS_MSWIN) && defined(FD_SETSIZE) + if (fd >= FD_SETSIZE) { + polls[i].revent = eIO_Close; + ready = 1; + continue; + } +#endif /*!NCBI_MSWIN && FD_SETSIZE*/ if (fd != SOCK_INVALID) { int/*bool*/ ls = IS_LISTENING(polls[i].sock); if (!ls && n != 1 && polls[i].sock->type == eSOCK_Datagram) @@ -1104,6 +1137,14 @@ static EIO_Status s_Select(size_t n, FD_SET(fd, &e_fds); if (n_fds < (int) fd) n_fds = (int) fd; +#ifdef NCBI_OS_MSWIN + /* Check whether FD_SETSIZE has been overcome */ + if (!FD_ISSET(fd, &e_fds)) { + polls[i].revent = eIO_Close; + ready = 1; + continue; + } +#endif } else { polls[i].revent = eIO_Close; ready = 1; @@ -1136,7 +1177,11 @@ static EIO_Status s_Select(size_t n, if ( !tv ) continue; if ( s_Less(s_SelectTimeout, &x_tv) ) { - x_tv.tv_sec -= s_SelectTimeout->tv_sec; + x_tv.tv_sec -= s_SelectTimeout->tv_sec; + if (x_tv.tv_usec < s_SelectTimeout->tv_usec) { + x_tv.tv_sec--; + x_tv.tv_usec += 1000000; + } x_tv.tv_usec -= s_SelectTimeout->tv_usec; continue; } @@ -1172,7 +1217,7 @@ static EIO_Status s_Select(size_t n, if (fd != SOCK_INVALID) { if (!write_only && FD_ISSET(fd, &r_fds)) polls[i].revent = eIO_Read; - if (!read_only && FD_ISSET(fd, &w_fds)) + if (!read_only && FD_ISSET(fd, &w_fds)) polls[i].revent = (EIO_Event)(polls[i].revent | eIO_Write); if (!polls[i].revent && FD_ISSET(fd, &e_fds)) polls[i].revent = eIO_Close; @@ -1196,10 +1241,13 @@ static EIO_Status s_Select(size_t n, extern const STimeout* SOCK_SetSelectInternalRestartTimeout(const STimeout* t) { - static struct timeval s_NewTmo; - static STimeout s_OldTmo; - const STimeout* retval = s_tv2to(s_SelectTimeout, &s_OldTmo); - s_SelectTimeout = s_to2tv(t, &s_NewTmo); + static struct timeval s_NewTmo; + static STimeout s_OldTmo; + const STimeout* retval; + CORE_LOCK_WRITE; + retval = s_tv2to(s_SelectTimeout, &s_OldTmo); + s_SelectTimeout = s_to2tv(t, &s_NewTmo); + CORE_UNLOCK; return retval; } @@ -1209,31 +1257,42 @@ extern const STimeout* SOCK_SetSelectInternalRestartTimeout(const STimeout* t) * LISTENING SOCKET */ -extern EIO_Status LSOCK_Create(unsigned short port, - unsigned short backlog, - LSOCK* lsock) +static EIO_Status s_CreateListening(const char* path, + unsigned short port, + unsigned short backlog, + LSOCK* lsock, + TLSCE_Flags flags) { - return LSOCK_CreateEx(port, backlog, lsock, fLSCE_LogDefault); -} - + ESwitch log = (ESwitch)(flags & 0xF); + unsigned int x_id = ++s_ID_Counter; + TSOCK_Handle x_lsock; + SOCK_socklen_t addrlen; + union { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef NCBI_OS_UNIX + struct sockaddr_un sun; +#endif /*NCBI_OS_UNIX*/ + } addr; + char s[80]; + const char* c; -extern EIO_Status LSOCK_CreateEx(unsigned short port, - unsigned short backlog, - LSOCK* lsock, - TLSCE_Flags flags) -{ - ESwitch log = (ESwitch)(flags & 0xF); - unsigned int x_id = ++s_ID_Counter; - TSOCK_Handle x_lsock; - struct sockaddr_in addr; - unsigned int ip; *lsock = 0; - /* initialize internals */ verify(s_Initialized || SOCK_InitializeAPI() == eIO_Success); + assert(!!path ^ !!port); + + if (path) { +#ifdef NCBI_OS_UNIX + addr.sa.sa_family = AF_UNIX; +#else + return eIO_NotSupported; +#endif + } else + addr.sa.sa_family = AF_INET; /* create new(listening) socket */ - if ((x_lsock = socket(AF_INET, SOCK_STREAM, 0)) == SOCK_INVALID) { + if ((x_lsock = socket(addr.sa.sa_family, SOCK_STREAM, 0)) == SOCK_INVALID){ int x_errno = SOCK_ERRNO; CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("LSOCK#%u[?]: [LSOCK::Create] " @@ -1241,39 +1300,53 @@ extern EIO_Status LSOCK_CreateEx(unsigned short port, return eIO_Unknown; } - /* - * It was confirmed(?) that at least under Solaris 2.5 this precaution: - * 1) makes the address released immediately after the process - * termination; - * 2) still issue EADDINUSE error on the attempt to bind() to the - * same address being in-use by a living process (if SOCK_STREAM). - */ - if ( !s_SetReuseAddress(x_lsock, 1/*true*/) ) { - int x_errno = SOCK_ERRNO; - CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), - ("LSOCK#%u[%u]: [LSOCK::Create] " - " Failed setsockopt(REUSEADDR)", - x_id, (unsigned int) x_lsock)); - SOCK_CLOSE(x_lsock); - return eIO_Unknown; + if ( port ) { + /* + * It was confirmed(?) that at least under Solaris 2.5 this precaution: + * 1) makes the address released immediately after the process + * termination; + * 2) still issue EADDRINUSE error on the attempt to bind() to the + * same address being in-use by a living process (if SOCK_STREAM). + */ + if ( !s_SetReuseAddress(x_lsock, 1/*true*/) ) { + int x_errno = SOCK_ERRNO; + CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), + ("LSOCK#%u[%u]: [LSOCK::Create] " + " Failed setsockopt(REUSEADDR)", + x_id, (unsigned int) x_lsock)); + SOCK_CLOSE(x_lsock); + return eIO_Unknown; + } } /* bind */ - ip = flags & fLSCE_BindLocal ? INADDR_LOOPBACK : INADDR_ANY; memset(&addr, 0, sizeof(addr)); - addr.sin_family = AF_INET; - addr.sin_addr.s_addr = htonl(ip); - addr.sin_port = htons(port); +#ifdef NCBI_OS_UNIX + if ( path ) { + addrlen = sizeof(addr.sun); + addr.sun.sun_family = AF_UNIX; + strncpy0(addr.sun.sun_path, path, sizeof(addr.sun.sun_path) - 1); + c = path; + } else +#endif /*NCBI_OS_UNIX*/ + { + unsigned int ip = + flags & fLSCE_BindLocal ? INADDR_LOOPBACK : INADDR_ANY; + addrlen = sizeof(addr.sin); + addr.sin.sin_family = AF_INET; + addr.sin.sin_addr.s_addr = htonl(ip); + addr.sin.sin_port = htons(port); #ifdef HAVE_SIN_LEN - addr.sin_len = sizeof(addr); + addr.sin.sin_len = addrlen; #endif /*HAVE_SIN_LEN*/ - if (bind(x_lsock, (struct sockaddr*) &addr, sizeof(addr)) != 0) { + c = HostPortToString(htonl(ip), port, s, sizeof(s)) ? s : "?:?"; + } + if (bind(x_lsock, &addr.sa, addrlen) != 0) { int x_errno = SOCK_ERRNO; CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("LSOCK#%u[%u]: [LSOCK::Create] " - " Failed bind(%s:%hu)", x_id, - (unsigned int) x_lsock, - ip == INADDR_LOOPBACK ? "127.0.0.1" : "", port)); + " Failed bind(%s)", x_id, + (unsigned int) x_lsock, c)); SOCK_CLOSE(x_lsock); return x_errno == SOCK_EADDRINUSE ? eIO_Closed : eIO_Unknown; } @@ -1282,8 +1355,9 @@ extern EIO_Status LSOCK_CreateEx(unsigned short port, if (listen(x_lsock, backlog) != 0) { int x_errno = SOCK_ERRNO; CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), - ("LSOCK#%u[%u]: [LSOCK::Create] Failed listen(%hu)" - , x_id, (unsigned int) x_lsock, backlog)); + ("LSOCK#%u[%u]: [LSOCK::Create] Failed " + "listen(%hu) at %s", x_id, (unsigned int) x_lsock, + backlog, s)); SOCK_CLOSE(x_lsock); return eIO_Unknown; } @@ -1298,32 +1372,70 @@ extern EIO_Status LSOCK_CreateEx(unsigned short port, } /* allocate memory for the internal socket structure */ - if ( !(*lsock = (LSOCK) calloc(1, sizeof(**lsock))) ) + if (!(*lsock = (LSOCK)calloc(1, sizeof(**lsock) + (path?strlen(path):0)))){ return eIO_Unknown; + } (*lsock)->sock = x_lsock; + (*lsock)->port = port; (*lsock)->id = x_id; (*lsock)->log = log; (*lsock)->i_on_sig = eDefault; +#ifdef NCBI_OS_UNIX + if ( path ) + strcpy((*lsock)->path, path); +#endif /*NCBI_OS_UNIX*/ SET_LISTENING(*lsock); /* statistics & logging */ if (log == eOn || (log == eDefault && s_Log == eOn)) { - CORE_LOGF(eLOG_Trace,("LSOCK#%u[%u]: Listening at %s:%hu", - x_id, (unsigned int) x_lsock, - ip == INADDR_LOOPBACK ? "127.0.0.1" : "", port)); + CORE_LOGF(eLOG_Trace,("LSOCK#%u[%u]: Listening on %s", + x_id, (unsigned int) x_lsock, c)); } return eIO_Success; } +extern EIO_Status LSOCK_Create(unsigned short port, + unsigned short backlog, + LSOCK* lsock) +{ + return s_CreateListening(0, port, backlog, lsock, fLSCE_LogDefault); +} + + +extern EIO_Status LSOCK_CreateEx(unsigned short port, + unsigned short backlog, + LSOCK* lsock, + TLSCE_Flags flags) +{ + return s_CreateListening(0, port, backlog, lsock, flags); +} + + +extern EIO_Status LSOCK_CreateUNIX(const char* path, + unsigned short backlog, + LSOCK* lsock, + ESwitch log) +{ + return s_CreateListening(path, 0, backlog, lsock, log); +} + + extern EIO_Status LSOCK_Accept(LSOCK lsock, const STimeout* timeout, SOCK* sock) { - struct sockaddr_in addr; - unsigned int x_id; - TSOCK_Handle x_sock; + union { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef NCBI_OS_UNIX + struct sockaddr_un sun; +#endif /*NCBI_OS_UNIX*/ + } addr; + unsigned int x_id; + TSOCK_Handle x_sock; + SOCK_socklen_t addrlen; if (lsock->sock == SOCK_INVALID) { CORE_LOGF(eLOG_Error, ("LSOCK#%u[?]: [LSOCK::Accept] " @@ -1348,52 +1460,74 @@ extern EIO_Status LSOCK_Accept(LSOCK lsock, }} x_id = (lsock->id * 1000 + ++s_ID_Counter) * 1000; - {{ /* accept next connection */ - SOCK_socklen_t addrlen = (SOCK_socklen_t) sizeof(addr); - memset(&addr, 0, sizeof(addr)); + + /* accept next connection */ + memset(&addr, 0, sizeof(addr)); +#ifdef NCBI_OS_UNIX + if ( lsock->path[0] ) { + addrlen = sizeof(addr.sun); + } else +#endif /*NCBI_OS_UNIX*/ + { + addrlen = sizeof(addr.sin); #ifdef HAVE_SIN_LEN - addr.sin_len = sizeof(addr); -#endif - if ((x_sock = accept(lsock->sock, (struct sockaddr*) &addr, &addrlen)) - == SOCK_INVALID) { - int x_errno = SOCK_ERRNO; - CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), - ("LSOCK#%u[%u]: [LSOCK::Accept] " - " Failed accept()", lsock->id, - (unsigned int) lsock->sock)); - return eIO_Unknown; - } - lsock->n_accept++; - assert(addr.sin_family == AF_INET); - /* man accept(2) notes that non-blocking state may not be inherited */ - if ( !s_SetNonblock(x_sock, 1/*true*/) ) { - CORE_LOGF(eLOG_Error, ("SOCK#%u[%u]: [LSOCK::Accept] Cannot" - " set accepted socket to non-blocking mode", - x_id, (unsigned int) x_sock)); - SOCK_CLOSE(x_sock); - return eIO_Unknown; + addr.sin.sin_len = sizeof(addr); +#endif /*HAVE_SIN_LEN*/ } + if ((x_sock = accept(lsock->sock, &addr.sa, &addrlen)) == SOCK_INVALID) { + int x_errno = SOCK_ERRNO; + CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), + ("LSOCK#%u[%u]: [LSOCK::Accept] " + " Failed accept()", lsock->id, + (unsigned int) lsock->sock)); + return eIO_Unknown; + } + lsock->n_accept++; + /* man accept(2) notes that non-blocking state may not be inherited */ + if ( !s_SetNonblock(x_sock, 1/*true*/) ) { + CORE_LOGF(eLOG_Error, ("SOCK#%u[%u]: [LSOCK::Accept] Cannot" + " set accepted socket to non-blocking mode", + x_id, (unsigned int) x_sock)); + SOCK_CLOSE(x_sock); + return eIO_Unknown; + } - if (s_ReuseAddress && !s_SetReuseAddress(x_sock, 1/*true*/)) { - int x_errno = SOCK_ERRNO; - CORE_LOGF_ERRNO_EX(eLOG_Warning, x_errno, SOCK_STRERROR(x_errno), - ("SOCK#%u[%u]: [LSOCK::Accept] " - " Failed setsockopt(REUSEADDR)", - x_id, (unsigned int) x_sock)); - } - }} + if (s_ReuseAddress && +#ifdef NCBI_OS_UNIX + !lsock->path[0] && +#endif /*NCBI_OS_UNIX*/ + !s_SetReuseAddress(x_sock, 1/*true*/)) { + int x_errno = SOCK_ERRNO; + CORE_LOGF_ERRNO_EX(eLOG_Warning, x_errno, SOCK_STRERROR(x_errno), + ("SOCK#%u[%u]: [LSOCK::Accept] " + " Failed setsockopt(REUSEADDR)", + x_id, (unsigned int) x_sock)); + } /* create new SOCK structure */ - if ( !(*sock = (SOCK) calloc(1, sizeof(**sock))) ) { +#ifdef NCBI_OS_UNIX + if ( lsock->path[0] ) + addrlen = strlen(lsock->path); + else +#endif /*NCBI_OS_UNIX*/ + addrlen = 0; + if ( !(*sock = (SOCK) calloc(1, sizeof(**sock) + addrlen)) ) { SOCK_CLOSE(x_sock); return eIO_Unknown; } /* success */ +#ifdef NCBI_OS_UNIX + if ( lsock->path[0] ) { + strcpy((*sock)->path, lsock->path); + } else +#endif /*NCBI_OS_UNIX*/ + { + (*sock)->host = addr.sin.sin_addr.s_addr; + (*sock)->port = addr.sin.sin_port; + } (*sock)->sock = x_sock; (*sock)->id = x_id; - (*sock)->host = addr.sin_addr.s_addr; - (*sock)->port = addr.sin_port; (*sock)->log = lsock->log; (*sock)->type = eSOCK_ServerSide; (*sock)->r_on_w = eDefault; @@ -1408,7 +1542,7 @@ extern EIO_Status LSOCK_Accept(LSOCK lsock, /* statistics & logging */ if (lsock->log == eOn || (lsock->log == eDefault && s_Log == eOn)) - s_DoLog(*sock, eIO_Open, 0, 0, (struct sockaddr*) &addr); + s_DoLog(*sock, eIO_Open, 0, 0, &addr.sa); return eIO_Success; } @@ -1417,6 +1551,8 @@ extern EIO_Status LSOCK_Accept(LSOCK lsock, extern EIO_Status LSOCK_Close(LSOCK lsock) { EIO_Status status; + const char* c; + char s[80]; if (lsock->sock == SOCK_INVALID) { CORE_LOGF(eLOG_Error, ("LSOCK#%u[?]: [LSOCK::Close] " @@ -1432,11 +1568,20 @@ extern EIO_Status LSOCK_Close(LSOCK lsock) lsock->id, (unsigned int) lsock->sock)); } +#ifdef NCBI_OS_UNIX + if ( lsock->path[0] ) { + c = lsock->path; + } else +#endif /*NCBI_OS_UNIX*/ + { + c = HostPortToString(0, lsock->port, s, sizeof(s)) ? s : ":?"; + } + /* statistics & logging */ if (lsock->log == eOn || (lsock->log == eDefault && s_Log == eOn)) { - CORE_LOGF(eLOG_Trace, ("LSOCK#%u[%u]: Closing at port :%hu " + CORE_LOGF(eLOG_Trace, ("LSOCK#%u[%u]: Closing at %s " "(%u accept%s total)", lsock->id, - (unsigned int) lsock->sock, lsock->port, + (unsigned int) lsock->sock, c, lsock->n_accept, lsock->n_accept == 1? "":"s")); } @@ -1459,6 +1604,11 @@ extern EIO_Status LSOCK_Close(LSOCK lsock) /* cleanup & return */ lsock->sock = SOCK_INVALID; +#ifdef NCBI_OS_UNIX + if ( lsock->path[0] ) + remove(lsock->path); +#endif + free(lsock); return status; } @@ -1523,6 +1673,26 @@ static EIO_Status s_IsConnected(SOCK sock, status = eIO_Unknown; } #endif /*NCBI_OS_UNIX || NCBI_OS_MSWIN*/ +#if defined(_DEBUG) && !defined(NDEBUG) + if (status == eIO_Success) { +# ifdef NCBI_OS_UNIX + if (!sock->path[0]) +# endif /*NCBI_OS_UNIX*/ + { + struct sockaddr_in addr; + SOCK_socklen_t addrlen = sizeof(addr); + memset(&addr, 0, addrlen); +# ifdef HAVE_SIN_LEN + addr.sin_len = addrlen; +# endif /*HAVE_SIN_LEN*/ + if (getsockname(sock->sock, + (struct sockaddr*) &addr, &addrlen) == 0) { + assert(addr.sin_family == AF_INET); + sock->myport = ntohs(addr.sin_port); + } + } + } +#endif /*_DEBUG && !_NDEBUG*/ if (status != eIO_Success || poll.revent != eIO_Write) { if ( !*x_errno ) *x_errno = SOCK_ERRNO; @@ -1530,7 +1700,11 @@ static EIO_Status s_IsConnected(SOCK sock, sock->r_status = sock->w_status = status = eIO_Closed; else if (status == eIO_Success) status = eIO_Unknown; - } else if (s_ReuseAddress && !s_SetReuseAddress(sock->sock, 1/*true*/)) { + } else if (s_ReuseAddress && +#ifdef NCBI_OS_UNIX + !sock->path[0] && +#endif /*NCBI_OS_UNIX*/ + !s_SetReuseAddress(sock->sock, 1/*true*/)) { int x_errno = SOCK_ERRNO; char _id[32]; CORE_LOGF_ERRNO_EX(eLOG_Warning, x_errno, SOCK_STRERROR(x_errno), @@ -1541,7 +1715,7 @@ static EIO_Status s_IsConnected(SOCK sock, } -/* Connect the (pre-allocated) socket to the specified "host:port" peer. +/* Connect the (pre-allocated) socket to the specified "host:port"/"file" peer. * HINT: if "host" is NULL then assume(!) that the "sock" already exists, * and connect to the same host; the same is for zero "port". * NOTE: Client-side stream sockets only. @@ -1554,33 +1728,59 @@ static EIO_Status s_Connect(SOCK sock, char _id[32]; int x_errno; TSOCK_Handle x_sock; - unsigned int x_host; - unsigned short x_port; - struct sockaddr_in peer; + union { + struct sockaddr sa; + struct sockaddr_in sin; +#ifdef NCBI_OS_UNIX + struct sockaddr_un sun; +#endif /*NCBI_OS_UNIX*/ + } addr; + SOCK_socklen_t addrlen; int n; + const char* c; + char s[80]; assert(sock->type == eSOCK_ClientSide); -#ifdef NCBI_OS_UNIX - assert(!sock->file[0]); -#endif /*NCBI_OS_UNIX*/ /* initialize internals */ verify(s_Initialized || SOCK_InitializeAPI() == eIO_Success); - /* get address of the remote host (assume the same host if it is NULL) */ - x_host = host && *host ? SOCK_gethostbyname(host) : sock->host; - if ( !x_host ) { - CORE_LOGF(eLOG_Error, ("%s[SOCK::s_Connect] Failed " - "SOCK_gethostbyname(\"%.64s\")", - s_ID(sock, _id), host)); - return eIO_Unknown; - } - - /* set the port to connect to (assume the same port if "port" is zero) */ - x_port = (unsigned short) (port ? htons(port) : sock->port); + memset(&addr, 0, sizeof(addr)); +#ifdef NCBI_OS_UNIX + if (sock->path[0]) { + addrlen = sizeof(addr.sun); + addr.sun.sun_family = AF_UNIX; + strncpy0(addr.sun.sun_path, sock->path, sizeof(addr.sun.sun_path)-1); + c = sock->path; + } else +#endif /*NCBI_OS_UNIX*/ + { + unsigned int x_host; + unsigned short x_port; + addrlen = sizeof(addr.sin); + addr.sin.sin_family = AF_INET; + /* get address of the remote host (assume the same host if NULL) */ + x_host = host && *host ? SOCK_gethostbyname(host) : sock->host; + if ( !x_host ) { + CORE_LOGF(eLOG_Error, ("%s[SOCK::s_Connect] Failed " + "SOCK_gethostbyname(\"%.64s\")", + s_ID(sock, _id), host)); + return eIO_Unknown; + } + addr.sin.sin_addr.s_addr = x_host; + /* set the port to connect to (same port if "port" is zero) */ + x_port = (unsigned short) (port ? htons(port) : sock->port); + addr.sin.sin_port = x_port; +#ifdef HAVE_SIN_LEN + addr.sin.sin_len = sizeof(addr.sin); +#endif /*HAVE_SIN_LEN*/ + sock->host = x_host; + sock->port = x_port; + c = HostPortToString(x_host,ntohs(x_port),s,sizeof(s)) ? s : "???"; + } - /* create new socket */ - if ((x_sock = socket(AF_INET, SOCK_STREAM, 0)) == SOCK_INVALID) { + /* check the new socket */ + if ((x_sock = socket(addr.sa.sa_family, SOCK_STREAM, 0)) == SOCK_INVALID) { int x_errno = SOCK_ERRNO; CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("%s[SOCK::s_Connect] Cannot create socket", @@ -1598,18 +1798,8 @@ static EIO_Status s_Connect(SOCK sock, return eIO_Unknown; } - /* fill in the server "addr" to connect to */ - memset(&peer, 0, sizeof(peer)); - peer.sin_family = AF_INET; - peer.sin_addr.s_addr = x_host; - peer.sin_port = x_port; -#ifdef HAVE_SIN_LEN - peer.sin_len = sizeof(peer); -#endif /*HAVE_SIN_LEN*/ - - /* statistics & logging */ if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn)) - s_DoLog(sock, eIO_Open, 0, 0, (struct sockaddr*) &peer); + s_DoLog(sock, eIO_Open, 0, 0, &addr.sa); /* establish connection to the peer */ sock->r_status = eIO_Success; @@ -1617,11 +1807,10 @@ static EIO_Status s_Connect(SOCK sock, sock->w_status = eIO_Success; assert(sock->w_len == 0); for (n = 0; ; n = 1) { - if (connect(x_sock, (struct sockaddr*) &peer, sizeof(peer)) == 0) { + if (connect(x_sock, &addr.sa, addrlen) == 0) { x_errno = 0; break; } - x_errno = SOCK_ERRNO; if (x_errno != SOCK_EINTR || sock->i_on_sig == eOn || (sock->i_on_sig == eDefault && s_InterruptOnSignal)) @@ -1632,11 +1821,9 @@ static EIO_Status s_Connect(SOCK sock, (n == 0 || x_errno != SOCK_EALREADY) && x_errno != SOCK_EWOULDBLOCK) { if (x_errno != SOCK_EINTR) { - char addr[80]; - HostPortToString(x_host, ntohs(x_port), addr, sizeof(addr)); CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("%s[SOCK::s_Connect] Failed connect() " - "to %s", s_ID(sock, _id), addr)); + "to %s", s_ID(sock, _id), c)); } sock->sock = SOCK_INVALID; SOCK_CLOSE(x_sock); @@ -1650,12 +1837,10 @@ static EIO_Status s_Connect(SOCK sock, status = s_IsConnected(sock, s_to2tv(timeout, &tv), &x_errno, 0); if (status != eIO_Success) { - char addr[80]; - HostPortToString(x_host, ntohs(x_port), addr, sizeof(addr)); CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("%s[SOCK::s_Connect] Failed pending " - "connect() to %s (%s)", s_ID(sock, _id), - addr, IO_StatusStr(status))); + "connect() to %s (%s)", + s_ID(sock, _id), c, IO_StatusStr(status))); sock->sock = SOCK_INVALID; SOCK_CLOSE(x_sock); return status; @@ -1667,8 +1852,6 @@ static EIO_Status s_Connect(SOCK sock, sock->pending = 0/*connected*/; /* success: do not change any timeouts */ - sock->host = x_host; - sock->port = x_port; sock->w_len = BUF_Size(sock->w_buf); return eIO_Success; } @@ -1783,7 +1966,7 @@ static int s_Recv(SOCK sock, } -static EIO_Status s_WritePending(SOCK, const struct timeval*, int); +static EIO_Status s_WritePending(SOCK, const struct timeval*, int, int); /* s_Select() with stall protection: try pull incoming data from sockets. * This method returns array of polls, "revent"s of which are always @@ -1830,7 +2013,7 @@ static EIO_Status s_SelectStallsafe(size_t n, if (polls[i].event == eIO_Read && polls[i].revent == eIO_Write) { assert(n != 1); assert(polls[i].sock->pending || polls[i].sock->w_len); - status = s_WritePending(polls[i].sock, tv, 1/*writeable*/); + status = s_WritePending(polls[i].sock, tv, 1/*writeable*/, 0); if (status != eIO_Success && status != eIO_Timeout) { polls[i].revent = eIO_Close; break; @@ -1919,6 +2102,19 @@ static EIO_Status s_WipeWBuf(SOCK sock) } +#ifdef NCBI_OS_MSWIN +static void s_Add(struct timeval* tv, int ms_addend) +{ + tv->tv_usec += (ms_addend % 1000) * 1000; + tv->tv_sec += ms_addend / 1000; + if (tv->tv_usec >= 10000000) { + tv->tv_sec += tv->tv_usec / 10000000; + tv->tv_usec %= 10000000; + } +} +#endif /*NCBI_OS_MSWIN*/ + + /* Write data to the socket "as is" (as many bytes at once as possible). * Return eIO_Success if at least some bytes were written successfully. * Otherwise (no bytes written) return an error code to indicate the problem. @@ -1927,22 +2123,27 @@ static EIO_Status s_WipeWBuf(SOCK sock) static EIO_Status s_Send(SOCK sock, const void* buf, size_t size, - size_t* n_written) + size_t* n_written, + int/*bool*/ oob) { char _id[32]; +#ifdef NCBI_OS_MSWIN + int no_buffer_wait = 0; + struct timeval timeout; + memset(&timeout, 0, sizeof(timeout)); +#endif /*NCBI_OS_MSWIN*/ assert(size > 0 && sock->type != eSOCK_Datagram && *n_written == 0); for (;;) { /* optionally retry if interrupted by a signal */ /* try to write */ - int x_written = send(sock->sock, (void*) buf, size, 0); + int x_written = send(sock->sock, (void*) buf, size, oob ? MSG_OOB : 0); int x_errno; if (x_written > 0) { /* statistics & logging */ if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn)) - s_DoLog(sock, eIO_Write, buf, (size_t) x_written, 0); + s_DoLog(sock, eIO_Write, buf, (size_t) x_written, oob? "" : 0); sock->n_written += x_written; - *n_written = x_written; sock->w_status = eIO_Success; break/*done*/; @@ -1950,13 +2151,35 @@ static EIO_Status s_Send(SOCK sock, x_errno = SOCK_ERRNO; /* don't want to handle all possible errors... let them be "unknown" */ sock->w_status = eIO_Unknown; + if (oob) + break; /* blocked -- retry if unblocked before the timeout expires */ /* (use stall protection if specified) */ - if (x_errno == SOCK_EWOULDBLOCK || x_errno == SOCK_EAGAIN) { + if (x_errno == SOCK_EWOULDBLOCK || x_errno == SOCK_EAGAIN +#ifdef NCBI_OS_MSWIN + || x_errno == WSAENOBUFS +#endif /*NCBI_OS_MSWIN*/ + ) { EIO_Status status; SSOCK_Poll poll; +#ifdef NCBI_OS_MSWIN + if (x_errno == WSAENOBUFS) { + s_Add(&timeout, no_buffer_wait); + if (!s_Less(&timeout, sock->w_timeout)) + return eIO_Timeout; + if (no_buffer_wait) + Sleep(no_buffer_wait); + if (no_buffer_wait == 0) + no_buffer_wait = 10; + else if (no_buffer_wait < 160) + no_buffer_wait *= 2; + } else { + no_buffer_wait = 0; + memset(&timeout, 0, sizeof(timeout)); + } +#endif /*NCBI_OS_MSWIN*/ poll.sock = sock; poll.event = eIO_Write; poll.revent = eIO_Open; @@ -1995,7 +2218,7 @@ static EIO_Status s_Send(SOCK sock, } } - return sock->w_status; + return (EIO_Status) sock->w_status; } @@ -2008,7 +2231,8 @@ static EIO_Status s_Send(SOCK sock, static EIO_Status s_WriteSliced(SOCK sock, const void* buf, size_t size, - size_t* n_written) + size_t* n_written, + int/*bool*/ oob) { /* split output buffer by slices (of size <= SOCK_WRITE_SLICE) * before writing to the socket @@ -2019,7 +2243,7 @@ static EIO_Status s_WriteSliced(SOCK sock, do { size_t n_io = size > SOCK_WRITE_SLICE ? SOCK_WRITE_SLICE : size; size_t n_io_done = 0; - status = s_Send(sock, (char*) buf + *n_written, n_io, &n_io_done); + status = s_Send(sock, (char*) buf + *n_written, n_io, &n_io_done, oob); if (status != eIO_Success) break; *n_written += n_io_done; @@ -2037,7 +2261,8 @@ static EIO_Status s_WriteSliced(SOCK sock, static EIO_Status s_WritePending(SOCK sock, const struct timeval* tv, - int/*bool*/ writeable) + int/*bool*/ writeable, + int/*bool*/ oob) { const struct timeval* x_tv; EIO_Status status; @@ -2052,12 +2277,12 @@ static EIO_Status s_WritePending(SOCK sock, char addr[80]; char _id[32]; #ifdef NCBI_OS_UNIX - if ( sock->file[0] ) { - size_t len = strlen(sock->file); + if ( sock->path[0] ) { + size_t len = strlen(sock->path); int/*bool*/ trunc = len > sizeof(addr) - 3 ? 1 : 0; sprintf(addr, "\"%s%.*s\"", trunc ? "..." : "", (int)(trunc ? sizeof(addr) - 6 : len), - &sock->file[trunc ? len - sizeof(addr) + 6 : 0]); + &sock->path[trunc ? len - sizeof(addr) + 6 : 0]); } else #endif /*NCBI_OS_UNIX*/ HostPortToString(sock->host, ntohs(sock->port), @@ -2071,7 +2296,7 @@ static EIO_Status s_WritePending(SOCK sock, } sock->pending = 0/*connected*/; } - if (sock->w_len == 0 || sock->w_status == eIO_Closed) + if (oob || sock->w_len == 0 || sock->w_status == eIO_Closed) return eIO_Success; x_tv = sock->w_timeout; @@ -2081,7 +2306,7 @@ static EIO_Status s_WritePending(SOCK sock, char buf[4096]; size_t n_written = 0; size_t n_write = BUF_PeekAt(sock->w_buf, off, buf, sizeof(buf)); - status = s_WriteSliced(sock, buf, n_write, &n_written); + status = s_WriteSliced(sock, buf, n_write, &n_written, 0); if (status != eIO_Success) break; sock->w_len -= n_written; @@ -2109,15 +2334,15 @@ static EIO_Status s_Read(SOCK sock, *n_read = 0; if (sock->type == eSOCK_Datagram) { - *n_read = peek ? - BUF_Peek(sock->r_buf, buf, size) : - BUF_Read(sock->r_buf, buf, size); + *n_read = peek + ? BUF_Peek(sock->r_buf, buf, size) + : BUF_Read(sock->r_buf, buf, size); sock->r_status = *n_read || !size ? eIO_Success : eIO_Closed; - return sock->r_status; + return (EIO_Status) sock->r_status; } - status = s_WritePending(sock, sock->r_timeout, 0); - if (sock->pending || !size) + status = s_WritePending(sock, sock->r_timeout, 0, 0); + if (sock->pending || !size) return sock->pending ? status : s_Status(sock, eIO_Read); for (;;) { /* retry if either blocked or interrupted (optional) */ @@ -2184,7 +2409,8 @@ static EIO_Status s_Read(SOCK sock, static EIO_Status s_Write(SOCK sock, const void* buf, size_t size, - size_t* n_written) + size_t* n_written, + int/*bool*/ oob) { EIO_Status status; @@ -2198,7 +2424,7 @@ static EIO_Status s_Write(SOCK sock, *n_written = size; } else sock->w_status = eIO_Unknown; - return sock->w_status; + return (EIO_Status) sock->w_status; } if (sock->w_status == eIO_Closed) { @@ -2211,14 +2437,15 @@ static EIO_Status s_Write(SOCK sock, return eIO_Closed; } - if ((status = s_WritePending(sock, sock->w_timeout, 0)) != eIO_Success) { + status = s_WritePending(sock, sock->w_timeout, 0, oob); + if (status != eIO_Success) { if (status == eIO_Timeout || status == eIO_Closed) return status; return size ? status : eIO_Success; } assert(sock->w_len == 0); - return size ? s_WriteSliced(sock, buf, size, n_written) : eIO_Success; + return size ? s_WriteSliced(sock, buf, size, n_written, oob) : eIO_Success; } @@ -2254,7 +2481,7 @@ static EIO_Status s_Shutdown(SOCK sock, case eIO_Write: if (sock->w_status == eIO_Closed) return eIO_Success; /* has been shut down already */ - if ((status = s_WritePending(sock, tv, 0)) != eIO_Success + if ((status = s_WritePending(sock, tv, 0, 0)) != eIO_Success && (!tv || tv->tv_sec || tv->tv_usec)) { CORE_LOGF(eLOG_Warning, ("%s[SOCK::s_Shutdown] Shutting down for " "write with some output pending (%s)", @@ -2273,7 +2500,7 @@ static EIO_Status s_Shutdown(SOCK sock, if (sock->r_status == eIO_Closed && sock->w_status == eIO_Closed) return eIO_Success; if (sock->w_status != eIO_Closed && - (status = s_WritePending(sock, tv, 0)) != eIO_Success + (status = s_WritePending(sock, tv, 0, 0)) != eIO_Success && (!tv || tv->tv_sec || tv->tv_usec)) { CORE_LOGF(eLOG_Warning, ("%s[SOCK::s_Shutdown] Shutting down for " "R/W with some output pending (%s)", @@ -2365,7 +2592,7 @@ static EIO_Status s_Close(SOCK sock) "back to blocking mode", s_ID(sock, _id))); } } else { - status = s_WritePending(sock, sock->c_timeout, 0); + status = s_WritePending(sock, sock->c_timeout, 0, 0); if (status != eIO_Success) { CORE_LOGF(eLOG_Warning, ("%s[SOCK::s_Close] Leaving with some " "output data pending (%s)", @@ -2406,35 +2633,31 @@ static EIO_Status s_Close(SOCK sock) } - -extern EIO_Status SOCK_Create(const char* host, - unsigned short port, - const STimeout* timeout, - SOCK* sock) -{ - return SOCK_CreateEx(host, port, timeout, sock, 0, 0, eDefault); -} - - -extern EIO_Status SOCK_CreateEx(const char* host, - unsigned short port, - const STimeout* timeout, - SOCK* sock, - const void* data, - size_t datalen, - ESwitch log) +static EIO_Status s_Create(const char* host, + unsigned short port, + const STimeout* timeout, + SOCK* sock, + const void* data, + size_t datalen, + ESwitch log) { unsigned int x_id = ++s_ID_Counter * 1000; + size_t x_n = port ? 0 : strlen(host); SOCK x_sock; *sock = 0; /* allocate memory for the internal socket structure */ - if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock)))) + if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock) + x_n))) return eIO_Unknown; x_sock->sock = SOCK_INVALID; x_sock->id = x_id; x_sock->log = log; x_sock->type = eSOCK_ClientSide; +#ifdef NCBI_OS_UNIX + if (!port) { + strcpy(x_sock->path, host); + } +#endif /*NCBI_OS_UNIX*/ /* setup the I/O data buffer properties */ BUF_SetChunkSize(&x_sock->r_buf, SOCK_BUF_CHUNK_SIZE); @@ -2467,6 +2690,48 @@ extern EIO_Status SOCK_CreateEx(const char* host, } +extern EIO_Status SOCK_Create(const char* host, + unsigned short port, + const STimeout* timeout, + SOCK* sock) +{ + if (!host || !port) + return eIO_InvalidArg; + return s_Create(host, port, timeout, sock, 0, 0, eDefault); +} + + +extern EIO_Status SOCK_CreateEx(const char* host, + unsigned short port, + const STimeout* timeout, + SOCK* sock, + const void* data, + size_t datalen, + ESwitch log) +{ + if (!host || !port) + return eIO_InvalidArg; + return s_Create(host, port, timeout, sock, data, datalen, log); +} + + +extern EIO_Status SOCK_CreateUNIX(const char* path, + const STimeout* timeout, + SOCK* sock, + const void* data, + size_t datalen, + ESwitch log) +{ + if (!path || !*path) + return eIO_InvalidArg; +#ifdef NCBI_OS_UNIX + return s_Create(path, 0, timeout, sock, data, datalen, log); +#else + return eIO_NotSupported; +#endif /*NCBI_OS_UNIX*/ +} + + extern EIO_Status SOCK_CreateOnTop(const void* handle, size_t handle_size, SOCK* sock) @@ -2587,7 +2852,7 @@ extern EIO_Status SOCK_CreateOnTopEx(const void* handle, x_sock->host = peer.in.sin_addr.s_addr; x_sock->port = peer.in.sin_port; } else - strcpy(x_sock->file, peer.un.sun_path); + strcpy(x_sock->path, peer.un.sun_path); #else x_sock->host = peer.in.sin_addr.s_addr; x_sock->port = peer.in.sin_port; @@ -2627,35 +2892,18 @@ extern EIO_Status SOCK_CreateOnTopEx(const void* handle, } -extern EIO_Status SOCK_Reconnect(SOCK sock, - const char* host, - unsigned short port, - const STimeout* timeout) +static EIO_Status s_Reconnect(SOCK sock, + const char* host, + unsigned short port, + const STimeout* timeout) { - char _id[32]; - - if (sock->sock == eSOCK_Datagram) { - CORE_LOGF(eLOG_Error, ("%s[SOCK::Reconnect] " - " Datagram socket", s_ID(sock, _id))); - assert(0); - return eIO_InvalidArg; - } - -#ifdef NCBI_OS_UNIX - if (sock->file[0]) { - CORE_LOGF(eLOG_Error, ("%s[SOCK::Reconnect] UNIX socket \"%s\"", - s_ID(sock, _id), sock->file)); - assert(0); - return eIO_InvalidArg; - } -#endif /*NCBI_OS_UNIX*/ - /* close the socket if necessary */ if (sock->sock != SOCK_INVALID) s_Close(sock); /* special treatment for server-side socket */ if (sock->type & eSOCK_ServerSide) { + char _id[32]; if (!host || !*host || !port) { CORE_LOGF(eLOG_Error, ("%s[SOCK::Reconnect] Attempt to reconnect " "server-side socket as the client one to " @@ -2673,6 +2921,35 @@ extern EIO_Status SOCK_Reconnect(SOCK sock, } +extern EIO_Status SOCK_Reconnect(SOCK sock, + const char* host, + unsigned short port, + const STimeout* timeout) +{ + char _id[32]; + + if (sock->sock == eSOCK_Datagram) { + CORE_LOGF(eLOG_Error, ("%s[SOCK::Reconnect] " + " Datagram socket", s_ID(sock, _id))); + assert(0); + return eIO_InvalidArg; + } + if (host && !*host) + host = 0; + +#ifdef NCBI_OS_UNIX + if (sock->path[0] && (host || port)) { + CORE_LOGF(eLOG_Error, ("%s[SOCK::Reconnect] " + " Cannot reconnect UNIX socket \"%s\" as INET", + s_ID(sock, _id), sock->path)); + assert(0); + return eIO_InvalidArg; + } +#endif /*NCBI_OS_UNIX*/ + return s_Reconnect(sock, host, port, timeout); +} + + extern EIO_Status SOCK_Shutdown(SOCK sock, EIO_Event how) { @@ -2793,7 +3070,7 @@ extern EIO_Status SOCK_Wait(SOCK sock, EIO_Status status; const struct timeval* x_tv = s_to2tv(timeout, &tv); - if ((status = s_WritePending(sock, x_tv, 0)) != eIO_Success) { + if ((status = s_WritePending(sock, x_tv, 0, 0)) != eIO_Success) { if (event == eIO_Write || sock->pending) return status; } @@ -2863,7 +3140,7 @@ extern EIO_Status POLLABLE_Poll(size_t n, const STimeout* timeout, size_t* n_ready) { - return SOCK_Poll(n, (SSOCK_Poll *const) polls, timeout, n_ready); + return SOCK_Poll(n, (SSOCK_Poll*) polls, timeout, n_ready); } @@ -2974,24 +3251,22 @@ extern EIO_Status SOCK_Read(SOCK sock, if (sock->sock != SOCK_INVALID) { switch ( how ) { case eIO_ReadPlain: - status = s_Read(sock, buf, size, &x_read, 0/*false, read*/); + status = s_Read(sock, buf, size, &x_read, 0/*read*/); break; case eIO_ReadPeek: - status = s_Read(sock, buf, size, &x_read, 1/*true, peek*/); + status = s_Read(sock, buf, size, &x_read, 1/*peek*/); break; case eIO_ReadPersist: x_read = 0; do { size_t xx_read; - status = SOCK_Read(sock, (char*) buf + (buf? x_read : 0), size, - &xx_read, eIO_ReadPlain); - if (status != eIO_Success) - break; + status = s_Read(sock, (char*)buf + (buf ? x_read : 0), + size, &xx_read, 0/*read*/); x_read += xx_read; size -= xx_read; - } while ( size ); + } while (size && status == eIO_Success); break; default: @@ -3015,6 +3290,75 @@ extern EIO_Status SOCK_Read(SOCK sock, } +extern EIO_Status SOCK_ReadLine(SOCK sock, + char* line, + size_t size, + size_t* n_read) +{ + EIO_Status status = eIO_Success; + int/*bool*/ cr_seen = 0/*false*/; + int/*bool*/ done = 0/*false*/; + size_t len = 0; + + do { + size_t i; + char w[1024], c; + size_t x_size = BUF_Size(sock->r_buf); + char* x_buf = size - len < sizeof(w) - cr_seen ? w : line + len; + if (x_size == 0 || x_size > sizeof(w) - cr_seen) + x_size = sizeof(w) - cr_seen; + status = s_Read(sock, x_buf + cr_seen, + size ? x_size : size, &x_size, 0/*read*/); + if ( !x_size ) + done = 1/*true*/; + else if ( cr_seen ) + x_size++; + for (i = cr_seen; i < x_size; i++) { + char c = x_buf[i]; + if (c == '\0' || c == '\n') { + cr_seen = 0/*false*/; + done = 1/*true*/; + i++; + break; + } + if (c == '\r') { + if ( !cr_seen ) { + cr_seen = 1/*true*/; + continue; + } + } + if ( cr_seen ) + line[len++] = '\r'; + if (c != '\r') + cr_seen = 0/*false*/; + if (len >= size) + break; + if (x_buf == w) + line[len] = c; + if (++len >= size) + break; + } + if (len >= size) + done = 1/*true*/; + if (done && cr_seen) { + c = '\r'; + if (SOCK_PushBack(sock, &c, 1) != eIO_Success) + status = eIO_Unknown; + } + if (i < x_size + && SOCK_PushBack(sock, &x_buf[i], x_size - i) != eIO_Success) { + status = eIO_Unknown; + } + } while (!done && status == eIO_Success); + if (len < size) + line[len] = '\0'; + if ( n_read ) + *n_read = len; + + return status; +} + + extern EIO_Status SOCK_PushBack(SOCK sock, const void* buf, size_t size) @@ -3042,21 +3386,31 @@ extern EIO_Status SOCK_Write(SOCK sock, if (sock->sock != SOCK_INVALID) { switch ( how ) { + case eIO_WriteOutOfBand: + if (sock->type == eSOCK_Datagram) { + CORE_LOGF(eLOG_Error, ("%s[SOCK::Write] " + " OOB not supported for datagrams", + s_ID(sock, _id))); + status = eIO_NotSupported; + x_written = 0; + break; + } + /*FALLTHRU*/ + case eIO_WritePlain: - status = s_Write(sock, buf, size, &x_written); + status = s_Write(sock, buf, size, &x_written, + how == eIO_WriteOutOfBand ? 1 : 0); break; case eIO_WritePersist: x_written = 0; do { size_t xx_written; - status = SOCK_Write(sock, (char*) buf + x_written, size, - &xx_written, eIO_WritePlain); - if (status != eIO_Success) - break; + status = s_Write(sock, (char*) buf + x_written, + size, &xx_written, 0); x_written += xx_written; size -= xx_written; - } while ( size ); + } while (size && status == eIO_Success); break; default: @@ -3151,8 +3505,8 @@ extern char* SOCK_GetPeerAddressString(SOCK sock, if (!buf || !buflen) return 0; #ifdef NCBI_OS_UNIX - if (sock->file[0]) - strncpy0(buf, sock->file, buflen - 1); + if (sock->path[0]) + strncpy0(buf, sock->path, buflen - 1); else #endif /*NCBI_OS_UNIX*/ HostPortToString(sock->host, ntohs(sock->port), buf, buflen); @@ -3191,7 +3545,7 @@ extern ESwitch SOCK_SetReadOnWriteAPI(ESwitch on_off) extern ESwitch SOCK_SetReadOnWrite(SOCK sock, ESwitch on_off) { if (sock->type != eSOCK_Datagram) { - ESwitch old = sock->r_on_w; + ESwitch old = (ESwitch) sock->r_on_w; sock->r_on_w = on_off; return old; } @@ -3211,7 +3565,7 @@ extern ESwitch SOCK_SetInterruptOnSignalAPI(ESwitch on_off) extern ESwitch SOCK_SetInterruptOnSignal(SOCK sock, ESwitch on_off) { - ESwitch old = sock->i_on_sig; + ESwitch old = (ESwitch) sock->i_on_sig; sock->i_on_sig = on_off; return old; } @@ -3238,6 +3592,24 @@ extern void SOCK_SetReuseAddress(SOCK sock, int/*bool*/ on_off) } +extern void SOCK_DisableOSSendDelay(SOCK sock, int/*bool*/ on_off) +{ +#ifdef TCP_NODELAY + if (sock->sock != SOCK_INVALID) { + int n = (int) on_off; + if (setsockopt(sock->sock, IPPROTO_TCP, TCP_NODELAY, (void*)&n, sizeof(n))) { + int x_errno = SOCK_ERRNO; + char _id[32]; + CORE_LOGF_ERRNO_EX(eLOG_Warning, x_errno, SOCK_STRERROR(x_errno), + ("%s[SOCK::DisableOSSendDelay] " + " Failed setsockopt(%sTCP_NODELAY)", + s_ID(sock, _id), on_off ? "" : "!")); + } + } +#endif /*TCP_NODELAY*/ +} + + extern EIO_Status DSOCK_Create(SOCK* sock) { return DSOCK_CreateEx(sock, eDefault); @@ -3323,7 +3695,7 @@ extern EIO_Status DSOCK_Bind(SOCK sock, unsigned short port) #ifdef HAVE_SIN_LEN addr.sin_len = sizeof(addr); #endif /*HAVE_SIN_LEN*/ - if (bind(sock->sock, (struct sockaddr*) &addr, sizeof(addr)) !=0 ) { + if (bind(sock->sock, (struct sockaddr*) &addr, sizeof(addr)) != 0) { int x_errno = SOCK_ERRNO; CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("%s[DSOCK::Bind] Failed bind()", s_ID(sock,_id))); @@ -3388,7 +3760,7 @@ extern EIO_Status DSOCK_Connect(SOCK sock, if (connect(sock->sock, (struct sockaddr*) &peer, sizeof(peer)) != 0) { char addr[80]; int x_errno = SOCK_ERRNO; - HostPortToString(sock->host, sock->port, addr, sizeof(addr)); + HostPortToString(sock->host, ntohs(sock->port), addr, sizeof(addr)); CORE_LOGF_ERRNO_EX(eLOG_Error, x_errno, SOCK_STRERROR(x_errno), ("%s[DSOCK::Connect] Failed connect() to %s", s_ID(sock, _id), addr)); @@ -3429,7 +3801,7 @@ extern EIO_Status DSOCK_SendMsg(SOCK sock, } if ( datalen ) { - s_Write(sock, data, datalen, &x_msgsize); + s_Write(sock, data, datalen, &x_msgsize, 0); verify(x_msgsize == datalen); } sock->eof = 1/*true - finalized message*/; @@ -3791,6 +4163,16 @@ extern int/*bool*/ SOCK_IsServerSide(SOCK sock) } +extern int/*bool*/ SOCK_IsUNIX(SOCK sock) +{ +#ifdef NCBI_OS_UNIX + return sock->sock != SOCK_INVALID && sock->path[0]; +#else + return 0/*false*/; +#endif /*NCBI_OS_UNIX*/ +} + + extern int SOCK_gethostname(char* name, size_t namelen) { @@ -3894,7 +4276,7 @@ extern unsigned int SOCK_gethostbyname(const char* hostname) } #else /* use some variant of gethostbyname */ struct hostent* he; -# if defined(HAVE_GETHOSTBYNAME_R) +# ifdef HAVE_GETHOSTBYNAME_R static const char suffix[] = "_r"; struct hostent x_he; char x_buf[1024]; @@ -3931,7 +4313,7 @@ extern unsigned int SOCK_gethostbyname(const char* hostname) x_errno = EINVAL; } -# if !defined(HAVE_GETHOSTBYNAME_R) +# ifndef HAVE_GETHOSTBYNAME_R CORE_UNLOCK; # endif /*HAVE_GETHOSTBYNAME_R*/ @@ -4066,9 +4448,85 @@ extern char* SOCK_gethostbyaddr(unsigned int host, /* * =========================================================================== * $Log: ncbi_socket.c,v $ + * Revision 6.174 2005/04/25 18:48:04 lavr + * Touch up for preprocessor (#if def) usage consistency + * + * Revision 6.173 2005/04/19 18:14:23 lavr + * Fix MSWIN compilation errors (s_Send) + * + * Revision 6.172 2005/04/19 16:33:54 lavr + * Introduce write-wait timeouts for Windows (no buffer space situations) + * + * Revision 6.171 2005/04/06 19:37:53 lavr + * Use adaptive wait-off in case of MS-Win's WSAENOBUFS error on send() + * + * Revision 6.170 2005/03/11 20:01:55 lavr + * Document SOCK::myport byte order + * + * Revision 6.169 2005/03/11 19:59:26 lavr + * Introduce SOCK::myport, solely for interactive debugging purposes + * + * Revision 6.168 2005/03/08 16:46:20 lavr + * Fix 32/64 int/ptr discrepancy + * + * Revision 6.167 2005/03/08 16:17:26 lavr + * Remove an extra const qualifier + * + * Revision 6.166 2005/02/11 18:46:47 lavr + * Fix some network/host byte order issues with port numbers + * + * Revision 6.165 2005/01/05 17:38:25 lavr + * Fix assert() in s_CreateListening() + * + * Revision 6.164 2004/12/27 15:30:35 lavr + * Implement OOB write + * + * Revision 6.163 2004/11/15 19:34:23 lavr + * Speed-up/fix SOCK_Read(), SOCK_Write() and improve SOCK_ReadLine() + * + * Revision 6.162 2004/11/15 16:11:32 lavr + * Yet again half-fix in SOCK_ReadLine() + * + * Revision 6.161 2004/11/15 15:39:35 lavr + * Fix SOCK_ReadLine() + * + * Revision 6.160 2004/11/09 21:27:01 lavr + * SOCK_ReadLine(): cleaned-up a little + * + * Revision 6.159 2004/11/09 21:13:28 lavr + * +SOCK_ReadLine() + * + * Revision 6.158 2004/10/26 20:27:10 ucko + * Ensure that "sun" isn't defined as a macro. + * + * Revision 6.157 2004/10/26 17:47:51 lavr + * Store socket's host:port when connecting (fallen out during UNIX mods) + * + * Revision 6.156 2004/10/26 16:17:07 lavr + * Fix SOCK_IsUNIX() (preprocessor macro check reversed) + * + * Revision 6.155 2004/10/26 14:48:13 lavr + * Implement UNIX socket extensions to the socket API + * + * Revision 6.154 2004/10/19 23:48:54 vakatov + * [MSWIN] Do not check filedes against FD_SETSIZE + * + * Revision 6.153 2004/10/19 19:12:52 kans + * netinet/tcp.h only included if not COMP_METRO - + * already includes headers in library project + * + * Revision 6.152 2004/10/19 18:50:16 lavr + * Heed setsockopt() type mismatch for CodeWarrior + * + * Revision 6.151 2004/10/19 18:12:15 lavr + * Fix compilation problems with previous commit + * + * Revision 6.150 2004/10/19 18:05:44 lavr + * +SOCK_DisableOSSendDelay; few other minor patches + * * Revision 6.149 2004/09/08 15:12:43 ucko - * SOCK_gethostbyaddr: use getnameinfo only if EAI_SYSTEM is defined. - * (OSF headers provide it conditionally.) + * SOCK_gethostbyaddr: use getnameinfo only if EAI_SYSTEM is defined + * (OSF headers provide it conditionally) * * Revision 6.148 2004/08/20 21:24:29 lavr * Fix CORE_LOGF_ERRNO_EX() in conditional branches we never compiled :-) diff --git a/connect/ncbi_socket.h b/connect/ncbi_socket.h index 6e558095..cf3ff53d 100644 --- a/connect/ncbi_socket.h +++ b/connect/ncbi_socket.h @@ -1,7 +1,7 @@ #ifndef CONNECT___NCBI_SOCKET__H #define CONNECT___NCBI_SOCKET__H -/* $Id: ncbi_socket.h,v 6.50 2004/07/23 19:04:38 lavr Exp $ +/* $Id: ncbi_socket.h,v 6.54 2005/01/05 17:37:20 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -64,6 +64,7 @@ * SOCK_GetReadTimeout * SOCK_GetWriteTimeout * SOCK_Read (including "peek" and "persistent read") + * SOCK_ReadLine * SOCK_PushBack * SOCK_Status * SOCK_Write @@ -77,6 +78,7 @@ * SOCK_SetInterruptOnSignal * SOCK_SetReuseAddressAPI * SOCK_SetReuseAddress + * SOCK_DisableOSSendDelay * * Datagram Socket: * @@ -94,6 +96,7 @@ * SOCK_IsDatagram * SOCK_IsClientSide * SOCK_IsServerSide + * SOCK_IsUNIX * * Data logging: * @@ -425,6 +428,8 @@ extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_CreateOnTopEx * NOTE2: the call is applicable to stream [not datagram] sockets only. * NOTE3: "timeout"==NULL is infinite; "timeout"=={0,0} causes no wait for * connection to be established and to return immediately. + * NOTE4: UNIX sockets can only be reconnected to the same file thus both + * host and port have to be passed as 0s. */ extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_Reconnect (SOCK sock, /* [in] handle of the socket to reconnect */ @@ -624,6 +629,29 @@ extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_Read ); +/* + * Read a line from SOCK. A line is terminated by either '\n' or '\0' + * with optional preceding '\r'. Returned result is always '\0'- + * terminated with preceding '\r' (if any) stripped. *n_read (if 'n_read' + * passed non-NULL) contains the numbed of characters written into + * 'buf' (not counting the terminating '\0'). If 'buf', whose size is + * specified via 'size' parameter, is not big enough to contain the + * line, all 'size' bytes will be filled, with *n_read == size upon + * return. Note that there will be no terminating '\0' in this + * (and the only) case, which the caller can easily distinguish. + * Return code eIO_Success upon successful completion, other - upon + * an error. Note that *n_read must be analyzed prior to return code, + * because the buffer could have received some contents before + * the indicated error occurred (especially when connection closed). + */ +extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_ReadLine +(SOCK sock, + char* buf, /* [out] data buffer to read to */ + size_t size, /* [in] max # of bytes to read to "buf" */ + size_t* n_read /* [out] # of bytes read (can be NULL) */ + ); + + /* Push the specified data back to the socket input queue (in the socket's * internal read buffer). These can be any data, not necessarily the data * previously read from the socket. @@ -755,6 +783,21 @@ extern NCBI_XCONNECT_EXPORT ESwitch SOCK_SetReadOnWrite ); +/* Control OS-defined send strategy by disabling/enabling TCP + * Nagle algorithm that packs multiple requests into a single + * frame and thus transferring data in fewer transactions, + * miminizing the network traffic and bursting the throughput. + * Some applications, however, may find it useful to disable this + * default behavior for the sake of their performance increase + * (like in case of short transactions otherwise held by the system + * to be possibly coalesced into larger chunks). + */ +extern NCBI_XCONNECT_EXPORT void SOCK_DisableOSSendDelay +(SOCK sock, + int/*bool*/ on_off /* NB: use true to disable; false to enable */ + ); + + /****************************************************************************** * Connectionless (datagram) sockets @@ -885,6 +928,12 @@ extern NCBI_XCONNECT_EXPORT int/*bool*/ SOCK_IsClientSide(SOCK sock); extern NCBI_XCONNECT_EXPORT int/*bool*/ SOCK_IsServerSide(SOCK sock); +/* Return non-zero value if socket "sock" was created by LSOCK_Accept(). + * Return zero otherwise. + */ +extern NCBI_XCONNECT_EXPORT int/*bool*/ SOCK_IsUNIX(SOCK sock); + + /****************************************************************************** * AUXILIARY network-specific functions (added for the portability reasons) @@ -966,6 +1015,18 @@ extern NCBI_XCONNECT_EXPORT char* SOCK_gethostbyaddr /* * --------------------------------------------------------------------------- * $Log: ncbi_socket.h,v $ + * Revision 6.54 2005/01/05 17:37:20 lavr + * SOCK_ReadLine() documented in details + * + * Revision 6.53 2004/11/09 21:13:00 lavr + * +ReadLine + * + * Revision 6.52 2004/10/26 14:46:06 lavr + * <ncbi_socket.h> -> <ncbi_socket_unix.h> + * + * Revision 6.51 2004/10/19 18:05:07 lavr + * +SOCK_DisableOSSendDelay + * * Revision 6.50 2004/07/23 19:04:38 lavr * LSOCK_CreateEx(): last parameter to become flags (bitmask) * diff --git a/connect/ncbi_socket_connector.c b/connect/ncbi_socket_connector.c index c0365fb4..f78a4649 100644 --- a/connect/ncbi_socket_connector.c +++ b/connect/ncbi_socket_connector.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_socket_connector.c,v 6.19 2003/08/25 14:42:14 lavr Exp $ +/* $Id: ncbi_socket_connector.c,v 6.20 2005/04/20 18:15:59 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -35,6 +35,7 @@ #include "ncbi_ansi_ext.h" #include <connect/ncbi_socket_connector.h> +#include <assert.h> #include <stdio.h> #include <stdlib.h> @@ -373,6 +374,9 @@ extern CONNECTOR SOCK_CreateConnectorOnTopEx /* * -------------------------------------------------------------------------- * $Log: ncbi_socket_connector.c,v $ + * Revision 6.20 2005/04/20 18:15:59 lavr + * +<assert.h> + * * Revision 6.19 2003/08/25 14:42:14 lavr * Employ new k..Timeout constants -- log modification only * diff --git a/connect/ncbi_socket_unix.h b/connect/ncbi_socket_unix.h new file mode 100644 index 00000000..f73d86c8 --- /dev/null +++ b/connect/ncbi_socket_unix.h @@ -0,0 +1,85 @@ +#ifndef CONNECT___NCBI_SOCKET_UNIX__H +#define CONNECT___NCBI_SOCKET_UNIX__H + +/* $Id: ncbi_socket_unix.h,v 1.1 2004/10/26 14:44:44 lavr Exp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * TCP/IP socket API extension for UNIX + * + */ + +#include <connect/ncbi_socket.h> + + +/** @addtogroup Sockets + * + * @{ + */ + + +#ifdef __cplusplus +extern "C" { +#endif + + +extern NCBI_XCONNECT_EXPORT EIO_Status LSOCK_CreateUNIX +(const char* path, /* [in] filename of the named socket to create */ + unsigned short backlog, /* [in] maximal # of pending connections */ + LSOCK* lsock, /* [out] handle of the created listening socket */ + ESwitch log /* [in] whether to do logging on this socket */ + ); + + +extern NCBI_XCONNECT_EXPORT EIO_Status SOCK_CreateUNIX +(const char* file, /* [in] filename of the UNIX socket to connect to*/ + const STimeout* timeout, /* [in] connection timeout (infinite if NULL) */ + SOCK* sock, /* [out] handle of the created socket */ + const void* init_data,/* [in] initial output data segment (may be NULL)*/ + size_t init_size,/* [in] size of initial data segment (may be 0) */ + ESwitch log /* [in] whether to do logging on this socket */ + ); + + +#ifdef __cplusplus +} /* extern "C" */ +#endif + + +/* @} */ + + +/* + * --------------------------------------------------------------------------- + * $Log: ncbi_socket_unix.h,v $ + * Revision 1.1 2004/10/26 14:44:44 lavr + * Initial revision + * + * =========================================================================== + */ + +#endif /* CONNECT___NCBI_SOCKET_UNIX__H */ diff --git a/connect/ncbi_util.c b/connect/ncbi_util.c index c52964d2..010bd7ec 100644 --- a/connect/ncbi_util.c +++ b/connect/ncbi_util.c @@ -1,4 +1,4 @@ -/* $Id: ncbi_util.c,v 6.31 2003/11/14 13:04:38 lavr Exp $ +/* $Id: ncbi_util.c,v 6.32 2005/04/20 18:15:42 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -30,7 +30,6 @@ * */ -#include "ncbi_config.h" #include "ncbi_priv.h" #ifndef NCBI_CXX_TOOLKIT # include <ncbistd.h> @@ -500,6 +499,9 @@ extern const char* CORE_GetPlatform(void) /* * --------------------------------------------------------------------------- * $Log: ncbi_util.c,v $ + * Revision 6.32 2005/04/20 18:15:42 lavr + * -"ncbi_config.h" + * * Revision 6.31 2003/11/14 13:04:38 lavr * Little changes in comments [no code changes] * diff --git a/connect/ncbibuf.c b/connect/ncbibuf.c deleted file mode 100644 index e3f101c6..00000000 --- a/connect/ncbibuf.c +++ /dev/null @@ -1,128 +0,0 @@ -/* $Id: ncbibuf.c,v 6.8 2003/01/08 15:09:07 lavr Exp $ - * ========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * ========================================================================== - * - * Author: Denis Vakatov - * - * File Description: - * Memory-resident FIFO storage area (to be used e.g. in I/O buffering) - * - * This is just a back-compatibility interface("Nlm_*") to the real - * BUF API located in "ncbi_buffer.[ch]". - * Unlike the "real" BUF API, this API uses: - * a) "Nlm_" name prefix for structures, types and functions; - * b) "Nlm_*" fixed size integer types like "Nlm_Uint4"; - * c) "Nlm_Boolean" rather than a native "int" for the boolean type; - * d) [MSWIN] "NLM_EXTERN" rather than just "extern" to ease the compilation - * for MSWIN DLL. - * - * -------------------------------------------------------------------------- - * $Log: ncbibuf.c,v $ - * Revision 6.8 2003/01/08 15:09:07 lavr - * Fix Nlm_BUF_Destroy() to use BUF_Destroy() w/o return value - * - * Revision 6.7 2000/02/25 16:45:54 vakatov - * Redesigned to really share "ncbi_*.[ch]" etc. between the C and - * the C++ toolkits, and even to use them in a "standalone" fashion - * - * Revision 6.6 1999/10/12 16:40:26 vakatov - * Deleted all test code as there is one in "test/test_ncbi_buffer.c" now - * - * Revision 6.5 1999/08/17 22:30:21 vakatov - * Use "Nlm_BUF" to avoid name clash with "BUF" in "ncbi_buffer.h" when - * compiling with MipsPro IRIX compiler - * - * Revision 6.4 1999/08/17 19:47:24 vakatov - * Moved all real code from NCBIBUF to NCBI_BUFFER; the code has been cleaned - * from the NCBI C toolkit specific types and API calls. - * NCBIBUF module still exists for the backward compatibility -- it - * provides old NCBI-wise interface. - * ========================================================================== - */ - - -#include <ncbibuf.h> - -/* ...and undefine "Nlm_BUF_*" to allow to access <ncbi_buffer.h> API */ -#undef BUF -#undef BUF_SetChunkSize -#undef BUF_Size -#undef BUF_Write -#undef BUF_Peek -#undef BUF_Read -#undef BUF_PushBack -#undef BUF_Destroy - -/* this is the only place where both <ncbibuf.h> and <ncbi_buffer.h> can - * be #include'd in one source module! */ -#undef NCBIBUF__H - -#include <connect/ncbi_buffer.h> - - -NLM_EXTERN Nlm_Uint4 Nlm_BUF_SetChunkSize -(BUF* pBuf, Nlm_Uint4 chunk_size) -{ - return (Nlm_Uint4) BUF_SetChunkSize(pBuf, chunk_size); -} - -NLM_EXTERN Nlm_Uint4 Nlm_BUF_Size -(BUF buf) -{ - return (Nlm_Uint4) BUF_Size(buf); -} - -NLM_EXTERN Nlm_Boolean Nlm_BUF_Write -(BUF* pBuf, const void* data, Nlm_Uint4 size) -{ - return (Nlm_Boolean) BUF_Write(pBuf, data, size); -} - -NLM_EXTERN Nlm_Boolean Nlm_BUF_PushBack -(BUF* pBuf, const void* data, Nlm_Uint4 size) -{ - return (Nlm_Boolean) BUF_PushBack(pBuf, data, size); -} - - -NLM_EXTERN Nlm_Uint4 Nlm_BUF_Peek -(BUF buf, void* data, Nlm_Uint4 size) -{ - return (Nlm_Uint4) BUF_Peek(buf, data, size); -} - - -NLM_EXTERN Nlm_Uint4 Nlm_BUF_Read -(BUF buf, void* data, Nlm_Uint4 size) -{ - return (Nlm_Uint4) BUF_Read(buf, data, size); -} - - -NLM_EXTERN BUF Nlm_BUF_Destroy -(BUF buf) -{ - BUF_Destroy(buf); - return 0; -} diff --git a/connect/ncbibuf.h b/connect/ncbibuf.h deleted file mode 100644 index 50684517..00000000 --- a/connect/ncbibuf.h +++ /dev/null @@ -1,149 +0,0 @@ -#ifndef NCBIBUF__H -#define NCBIBUF__H - -/* $Id: ncbibuf.h,v 6.5 1999/08/17 22:30:22 vakatov Exp $ - * ========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * ========================================================================== - * - * Author: Denis Vakatov - * - * File Description: - * Memory-resident FIFO storage area (to be used e.g. in I/O buffering) - * - * This is just a back-compatibility interface("Nlm_*") to the real - * BUF API located in "ncbi_buffer.[ch]". - * Unlike the "real" BUF API, this API uses: - * a) "Nlm_" name prefix for structures, types and functions; - * b) "Nlm_*" fixed size integer types like "Nlm_Uint4"; - * c) "Nlm_Boolean" rather than a native "int" for the boolean type; - * d) [MSWIN] "NLM_EXTERN" rather than just "extern" to ease the compilation - * for MSWIN DLL. - * - * -------------------------------------------------------------------------- - * $Log: ncbibuf.h,v $ - * Revision 6.5 1999/08/17 22:30:22 vakatov - * Use "Nlm_BUF" to avoid name clash with "BUF" in "ncbi_buffer.h" when - * compiling with MipsPro IRIX compiler - * - * Revision 6.4 1999/08/17 19:47:25 vakatov - * Moved all real code from NCBIBUF to NCBI_BUFFER; the code has been cleaned - * from the NCBI C toolkit specific types and API calls. - * NCBIBUF module still exists for the backward compatibility -- it - * provides old NCBI-wise interface. - * - * ========================================================================== - */ - -#include <ncbilcl.h> -#include <ncbistd.h> - - -#undef NLM_EXTERN -#ifdef NLM_IMPORT -#define NLM_EXTERN NLM_IMPORT -#else -#define NLM_EXTERN extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - -#define BUF Nlm_BUF -#define BUF_SetChunkSize Nlm_BUF_SetChunkSize -#define BUF_Size Nlm_BUF_Size -#define BUF_Write Nlm_BUF_Write -#define BUF_Peek Nlm_BUF_Peek -#define BUF_Read Nlm_BUF_Read -#define BUF_PushBack Nlm_BUF_PushBack -#define BUF_Destroy Nlm_BUF_Destroy - - -/* handle of a buffer (see "ncbi_buffer.[ch]") */ -struct BUF_tag; -typedef struct BUF_tag* BUF; - - -/* Set minimal size of the buffer memory chunk. - * Return the actually set chunk size on success; zero on error - * NOTE: if "*pBuf" == NULL then create it - * if "chunk_size" is passed 0 then set it to BUF_DEF_CHUNK_SIZE - */ -NLM_EXTERN Nlm_Uint4 BUF_SetChunkSize(BUF* pBuf, Nlm_Uint4 chunk_size); - - -/* Return the number of bytes stored in "buf". - * NOTE: return 0 if "buf" == NULL - */ -NLM_EXTERN Nlm_Uint4 BUF_Size(BUF buf); - - -/* Add new data to the end of "*pBuf" (to be read last). - * NOTE: if "*pBuf" == NULL then create it - */ -NLM_EXTERN Nlm_Boolean BUF_Write(BUF* pBuf, const void* data, Nlm_Uint4 size); - - -/* Write the data to the very beginning of "*pBuf" (to be read first). - * NOTE: if "*pBuf" == NULL then create it - */ -NLM_EXTERN Nlm_Boolean BUF_PushBack(BUF* pBuf, - const void* data, Nlm_Uint4 size); - - -/* Copy up to "size" bytes stored in "buf" to "data". - * Return the # of copied bytes(can be less than "size"). - * NOTE: "buf" and "data" can be NULL; in both cases, do nothing - * and return 0. - */ -NLM_EXTERN Nlm_Uint4 BUF_Peek(BUF buf, void* data, Nlm_Uint4 size); - - -/* Copy up to "size" bytes stored in "buf" to "data" and remove - * copied data from the "buf". - * Return the # of copied-and/or-removed bytes(can be less than "size") - * NOTE: if "buf" == NULL then do nothing and return 0 - * if "data" == NULL then do not copy data anywhere(still, remove it) - */ -NLM_EXTERN Nlm_Uint4 BUF_Read(BUF buf, void* data, Nlm_Uint4 size); - - -/* Destroy all internal data; return NULL - * NOTE: do nothing if "buf" == NULL - */ -NLM_EXTERN BUF BUF_Destroy(BUF buf); - - -#ifdef __cplusplus -} -#endif - -#undef NLM_EXTERN -#ifdef NLM_EXPORT -#define NLM_EXTERN NLM_EXPORT -#else -#define NLM_EXTERN -#endif - -#endif /* NCBIBUF__H */ diff --git a/connect/ncbisock.c b/connect/ncbisock.c deleted file mode 100644 index 954d7f00..00000000 --- a/connect/ncbisock.c +++ /dev/null @@ -1,535 +0,0 @@ -/* $Id: ncbisock.c,v 6.11 2002/09/13 19:17:36 lavr Exp $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Author: Denis Vakatov - * - * File Description: - * Plain portable TCP/IP socket API for: UNIX, MS-Win, MacOS - * - * This is just a back-compatibility interface("Nlm_*") to the real - * SOCK API located in "ncbi_socket.[ch]". - * Unlike the "real" SOCK API, this API uses: - * a) "Nlm_" name prefix for structures, types and functions; - * b) "Nlm_*" fixed size integer types like "Nlm_Uint4"; - * c) "Nlm_Boolean" rather than a native "int" for the boolean type; - * d) [MSWIN] "NLM_EXTERN" rather than just "extern" to ease the compilation - * for MSWIN DLL. - * - * --------------------------------------------------------------------------- - * $Log: ncbisock.c,v $ - * Revision 6.11 2002/09/13 19:17:36 lavr - * Fix incomplete S2E() mapping - * - * Revision 6.10 2002/08/27 20:26:23 lavr - * Fixed reference: SOCK_htonl() -> SOCK_HostToNetLong() - * - * Revision 6.9 2002/08/12 20:01:30 lavr - * Fix SOCK_Write() call (misplaced argument) - * - * Revision 6.8 2002/08/12 19:55:46 lavr - * Use write_mode in SOCK_Write() - * - * Revision 6.7 2002/08/07 18:45:17 lavr - * Change from deprecated to current EIO_ReadMethod enums - * - * Revision 6.6 2002/08/07 18:34:21 lavr - * SOCK_GetAddress() -> SOCK_GetPeerAddress() - * - * Revision 6.5 2001/04/03 22:17:05 juran - * Backout previous change. - * - * Revision 6.3 2000/12/07 19:16:59 vakatov - * Use new NCBI_SOCKET API imported from the C++ Toolkit - * - * Revision 6.2 2000/02/25 16:45:54 vakatov - * Redesigned to really share "ncbi_*.[ch]" etc. between the C and - * the C++ toolkits, and even to use them in a "standalone" fashion - * - * Revision 6.3 2000/02/18 23:50:41 vakatov - * REDESIGN - * - * Revision 6.2 2000/02/17 21:51:15 vakatov - * REDESIGN:: - * - * Revision 6.1 1999/10/18 15:39:05 vakatov - * Initial revision - * This is actually just an interface for the back compatibility with the - * former "ncbisock.[ch]"; the real code is in "ncbi_socket.[ch]" - * =========================================================================== - */ - -#include <ncbithr.h> -#include <ncbisock.h> -#include <ncbierr.h> - - -/* Undefine some "Nlm_SOCK_*" to clear the access to <ncbi_socket.h> API - */ -#undef LSOCK -#undef SOCK - -#undef LSOCK_Create -#undef LSOCK_Accept -#undef LSOCK_Close -#undef LSOCK_GetOSHandle - -#undef SOCK_Create -#undef SOCK_SetTimeout -#undef SOCK_Read -#undef SOCK_ReadPersist -#undef SOCK_Peek -#undef SOCK_PushBack -#undef SOCK_Eof -#undef SOCK_Write -#undef SOCK_Reconnect -#undef SOCK_Close -#undef SOCK_GetOSHandle - - -/* This is the only place where both <ncbibuf.h> and <ncbi_buffer.h> are - * allowed to be #include'd in the same source module! - */ -#undef NCBISOCK__H - -#include <connect/ncbi_socket.h> -#include <connect/ncbi_util.h> - - -/* EIO_Status <--> ESOCK_ErrCode - */ -static ESOCK_ErrCode s_ESOCK_ErrCode[eIO_Unknown + 1] = { - eSOCK_ESuccess, - eSOCK_ETimeout, - eSOCK_EClosed, - eSOCK_EUnknown, - eSOCK_EUnknown, - eSOCK_EUnknown, - eSOCK_EUnknown -}; -#define S2E(status) s_ESOCK_ErrCode[(int) status] - -static EIO_Status s_EIO_Status[eSOCK_EUnknown + 1] = { - eIO_Success, - eIO_Timeout, - eIO_Closed, - eIO_Unknown -}; -#define E2S(err_code) s_EIO_Status[(int) err_code] - - -/* ESOCK_Mode -> EIO_Event - */ -static EIO_Event s_EIO_Event[3] = { - eIO_Read, - eIO_Write, - eIO_ReadWrite -}; -#define M2E(mode) s_EIO_Event[(int) mode] - - -/*********************************************************************** - * INITIALIZATION -- to provide MT-safety and error posting - */ - -#if defined(__cplusplus) -extern "C" { - static int/*bool*/ s_MT_LOCK_Handler(void* user_data, EMT_Lock how); - static void s_MT_LOCK_Cleanup(void* user_data); - static void s_LOG_Handler(void* user_data, SLOG_Handler* call_data); -} -#endif /* __cplusplus */ - - -static int/*bool*/ s_MT_LOCK_Handler(void* user_data, EMT_Lock how) -{ - TNlmRWlock rw_lock = (TNlmRWlock) user_data; - Int4 ret_code; - switch ( how ) { - case eMT_Lock: - ret_code = NlmRWwrlock(rw_lock); - break; - case eMT_LockRead: - ret_code = NlmRWrdlock(rw_lock); - break; - case eMT_Unlock: - ret_code = NlmRWunlock(rw_lock); - break; - default: - ASSERT(0); - ret_code = 1/*bad*/; - } - - return (ret_code == 0); -} - -static void s_MT_LOCK_Cleanup(void* user_data) -{ - NlmRWdestroy((TNlmRWlock) user_data); -} - - -static void s_LOG_Handler(void* user_data, SLOG_Handler* call_data) -{ - static ErrSev s_Lev2Sev[eLOG_Fatal + 1] = { - SEV_INFO, - SEV_INFO, - SEV_WARNING, - SEV_ERROR, - SEV_REJECT, - SEV_FATAL - }; - - if (Nlm_ErrSetContext(call_data->module, call_data->file, call_data->line, - 0, 0, 0, 0) == 0) { - ErrSev sev = s_Lev2Sev[(int) call_data->level]; - Nlm_ErrPostStr(sev, SOCK_ERRCODE, 0, call_data->message); - } -} - - -static int/*bool*/ s_Initialized = 0/*false*/; -static TNlmMutex s_InitMutex; - -static int/*fake*/ s_Initialize(void) -{ - NlmMutexLockEx(&s_InitMutex); - if ( !s_Initialized ) { - /* MT safety */ - if ( NlmThreadsAvailable() ) { - TNlmRWlock rw_lock = NlmRWinit(); - if ( !rw_lock ) { - ASSERT(0); - } else { - MT_LOCK lk = - MT_LOCK_Create(rw_lock, s_MT_LOCK_Handler, s_MT_LOCK_Cleanup); - ASSERT(lk); - CORE_SetLOCK(lk); - } - } - - /* Error posting */ - CORE_SetLOG( LOG_Create(0, s_LOG_Handler, 0, 0) ); - - /* API initialization */ - {{ - if (SOCK_InitializeAPI() == eIO_Success) - s_Initialized = 1/*true*/; - else - ASSERT(0); - }} - } - NlmMutexUnlock(s_InitMutex); - return 1; -} - -#define INITIALIZE (void)(s_Initialized ? 1 : s_Initialize()) - - - -/****************************************************************************** - * SHUTDOWN - */ - -NLM_EXTERN ESOCK_ErrCode SOCK_Destroy -(void) -{ - ESOCK_ErrCode err_code; - TNlmMutex x_InitMutex; - - NlmMutexLockEx(&s_InitMutex); - - if ( s_Initialized ) { - err_code = S2E( SOCK_ShutdownAPI() ); - s_Initialized = 0/*false*/; - } else { - err_code = eSOCK_ESuccess; - } - - x_InitMutex = s_InitMutex; - s_InitMutex = 0; - NlmMutexUnlock(x_InitMutex); - NlmMutexDestroy(x_InitMutex); - - return err_code; -} - - - -/*********************************************************************** - * MISC - */ - -NLM_EXTERN const char* SOCK_ErrCodeStr -(ESOCK_ErrCode err_code) -{ - return IO_StatusStr( E2S(err_code) ); -} - - - -/*********************************************************************** - * LSOCK - */ - -NLM_EXTERN ESOCK_ErrCode Nlm_LSOCK_Create -(Nlm_Uint2 port, - Nlm_Uint2 n_listen, - LSOCK* lsock) -{ - INITIALIZE; - return S2E( LSOCK_Create(port, n_listen, lsock) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_LSOCK_Accept -(LSOCK lsock, - const STimeout* timeout, - SOCK* sock) -{ - return S2E( LSOCK_Accept(lsock, timeout, sock) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_LSOCK_Close -(LSOCK lsock) -{ - return S2E( LSOCK_Close(lsock) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_LSOCK_GetOSHandle -(LSOCK lsock, - void* handle_buf, - Nlm_Uint4 handle_size) -{ - return S2E( LSOCK_GetOSHandle(lsock, handle_buf, (size_t) handle_size) ); -} - - - -/*********************************************************************** - * SOCK - */ - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Create -(const char* host, - Nlm_Uint2 port, - const STimeout* timeout, - SOCK* sock) -{ - INITIALIZE; - return S2E( SOCK_Create(host, port, timeout, sock) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Reconnect -(SOCK sock, - const char* host, - Nlm_Uint2 port, - const STimeout* timeout) -{ - return S2E( SOCK_Reconnect(sock, host, port, timeout) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Close -(SOCK sock) -{ - return S2E( SOCK_Close(sock) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Select -(SOCK sock, - Nlm_ESOCK_Mode mode, - const STimeout* timeout) -{ - return S2E( SOCK_Wait(sock, M2E(mode), timeout) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_SetTimeout -(SOCK sock, - Nlm_ESOCK_Mode mode, - const STimeout* new_timeout, - STimeout* r_timeout, - STimeout* w_timeout) -{ - /* retrieve R and/or W timeouts, if requested */ - static const STimeout s_Infinite = { 99999999, 999999 }; - if ( r_timeout ) { - const STimeout* x_timeout = SOCK_GetTimeout(sock, eIO_Read); - *r_timeout = x_timeout ? *x_timeout : s_Infinite; - } - if ( w_timeout ) { - const STimeout* x_timeout = SOCK_GetTimeout(sock, eIO_Write); - *w_timeout = x_timeout ? *x_timeout : s_Infinite; - } - - /* special case -- do not change the timeout(s) */ - if (new_timeout == SOCK_GET_TIMEOUT) - return Nlm_eSOCK_Success; - - /* change C(close) timeout when W timeout is changed */ - if (mode == eSOCK_OnWrite || mode == eSOCK_OnReadWrite) { - VERIFY(SOCK_SetTimeout(sock, eIO_Close, new_timeout) == eIO_Success); - } - - /* change R and/or W timeouts */ - return S2E( SOCK_SetTimeout(sock, M2E(mode), new_timeout) ); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Read -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read) -{ - size_t x_read; - ESOCK_ErrCode err_code = - S2E( SOCK_Read(sock, buf, (size_t) size, &x_read, eIO_ReadPlain) ); - *n_read = (Nlm_Uint4) x_read; - return err_code; -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_ReadPersist -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read) -{ - size_t x_read; - ESOCK_ErrCode err_code = - S2E( SOCK_Read(sock, buf, (size_t) size, &x_read, eIO_ReadPersist) ); - *n_read = (Nlm_Uint4) x_read; - return err_code; -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Peek -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read) -{ - size_t x_read; - ESOCK_ErrCode err_code = - S2E( SOCK_Read(sock, buf, (size_t) size, &x_read, eIO_ReadPeek) ); - *n_read = (Nlm_Uint4) x_read; - return err_code; -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_PushBack -(SOCK sock, - const void* buf, - Nlm_Uint4 size) -{ - return S2E( SOCK_PushBack(sock, buf, (size_t) size) ); -} - - -NLM_EXTERN Nlm_Boolean Nlm_SOCK_Eof(SOCK sock) -{ - return (SOCK_Status(sock, eIO_Read) == eIO_Closed); -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_Write -(SOCK sock, - const void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_written) -{ - size_t x_written; - ESOCK_ErrCode err_code = - S2E( SOCK_Write(sock, buf, (size_t) size, &x_written, eIO_WritePersist) ); - if ( n_written ) - *n_written = (Nlm_Uint4) x_written; - return err_code; -} - - -NLM_EXTERN void Nlm_SOCK_Address -(SOCK sock, - Nlm_Uint4* host, - Nlm_Uint2* port, - Nlm_Boolean network_byte_order) -{ - if ( host ) { - unsigned int x_host; - SOCK_GetPeerAddress(sock, &x_host, 0, network_byte_order - ? eNH_NetworkByteOrder : eNH_HostByteOrder); - *host = x_host; - } - if ( port ) { - unsigned short x_port; - SOCK_GetPeerAddress(sock, 0, &x_port, network_byte_order - ? eNH_NetworkByteOrder : eNH_HostByteOrder); - *port = x_port; - } -} - - -NLM_EXTERN ESOCK_ErrCode Nlm_SOCK_GetOSHandle -(SOCK sock, - void* handle_buf, - Nlm_Uint4 handle_size) -{ - return S2E( SOCK_GetOSHandle(sock, handle_buf, (size_t) handle_size) ); -} - - - -/*********************************************************************** - * AUXILIARY - */ - -NLM_EXTERN Nlm_Boolean Nlm_GetHostName -(char* name, - Nlm_Uint4 namelen) -{ - INITIALIZE; - return SOCK_gethostname(name, (size_t) namelen) ? FALSE : TRUE; -} - - -NLM_EXTERN Nlm_Boolean Nlm_Uint4toInaddr -(Nlm_Uint4 ui4_addr, - char* buf, - Nlm_Uint4 buf_len) -{ - INITIALIZE; - return SOCK_ntoa((unsigned int) ui4_addr, buf, (size_t) buf_len) ? - FALSE : TRUE; -} - - -NLM_EXTERN Nlm_Uint4 Nlm_htonl(Nlm_Uint4 value) -{ - return (Nlm_Uint4) SOCK_HostToNetLong((Nlm_Uint4) value); -} diff --git a/connect/ncbisock.h b/connect/ncbisock.h deleted file mode 100644 index 68091266..00000000 --- a/connect/ncbisock.h +++ /dev/null @@ -1,412 +0,0 @@ -#ifndef NCBISOCK__H -#define NCBISOCK__H - -/* $Id: ncbisock.h,v 6.3 2004/04/01 13:43:06 lavr Exp $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Author: Denis Vakatov - * - * File Description: - * Plain portable TCP/IP socket API for: UNIX, MS-Win, MacOS - * - * This is just a back-compatibility interface("Nlm_*") to the real - * SOCK API located in "ncbi_socket.[ch]". - * Unlike the "real" SOCK API, this API uses: - * a) "Nlm_" name prefix for structures, types and functions; - * b) "Nlm_*" fixed size integer types like "Nlm_Uint4"; - * c) "Nlm_Boolean" rather than a native "int" for the boolean type; - * d) [MSWIN] "NLM_EXTERN" rather than just "extern" to ease the compilation - * for MSWIN DLL. - * - * --------------------------------------------------------------------------- - * $Log: ncbisock.h,v $ - * Revision 6.3 2004/04/01 13:43:06 lavr - * Spell "occurred", "occurrence", and "occurring" - * - * Revision 6.2 2000/02/25 16:45:55 vakatov - * Redesigned to really share "ncbi_*.[ch]" etc. between the C and - * the C++ toolkits, and even to use them in a "standalone" fashion - * - * Revision 6.3 2000/02/17 21:51:34 vakatov - * REDESIGN:: - * - * Revision 6.2 2000/02/17 19:37:42 vakatov - * REDESIGN:: - * - * Revision 6.1 1999/10/18 15:39:05 vakatov - * Initial revision - * This is actually just an interface for the back compatibility with the - * former "ncbisock.[ch]"; the real code is in "ncbi_socket.[ch]" - * =========================================================================== - */ - -#include <ncbistd.h> - - -#define LSOCK Nlm_LSOCK -#define SOCK Nlm_SOCK - -#define ESOCK_ErrCode Nlm_ESOCK_ErrCode -#define eSOCK_ESuccess Nlm_eSOCK_Success -#define eSOCK_ETimeout Nlm_eSOCK_Timeout -#define eSOCK_EClosed Nlm_eSOCK_Closed -#define eSOCK_EUnknown Nlm_eSOCK_Unknown - -#define ESOCK_Mode Nlm_ESOCK_Mode -#define eSOCK_OnRead Nlm_eSOCK_OnRead -#define eSOCK_OnWrite Nlm_eSOCK_OnWrite -#define eSOCK_OnReadWrite Nlm_eSOCK_OnReadWrite - -#define SOCK_ErrCodeStr Nlm_SOCK_ErrCodeStr - -#define SOCK_Initialize Nlm_SOCK_Initialize -#define SOCK_Destroy Nlm_SOCK_Destroy - -#define LSOCK_Create Nlm_LSOCK_Create -#define LSOCK_Accept Nlm_LSOCK_Accept -#define LSOCK_Close Nlm_LSOCK_Close -#define LSOCK_GetOSHandle Nlm_LSOCK_GetOSHandle - -#define SOCK_Create Nlm_SOCK_Create -#define SOCK_SetTimeout Nlm_SOCK_SetTimeout -#define SOCK_Select Nlm_SOCK_Select -#define SOCK_Read Nlm_SOCK_Read -#define SOCK_ReadPersist Nlm_SOCK_ReadPersist -#define SOCK_Peek Nlm_SOCK_Peek -#define SOCK_PushBack Nlm_SOCK_PushBack -#define SOCK_Eof Nlm_SOCK_Eof -#define SOCK_Write Nlm_SOCK_Write -#define SOCK_Address Nlm_SOCK_Address -#define SOCK_Reconnect Nlm_SOCK_Reconnect -#define SOCK_Close Nlm_SOCK_Close -#define SOCK_GetOSHandle Nlm_SOCK_GetOSHandle - -#define GetHostName Nlm_GetHostName -#define Uint4toInaddr Nlm_Uint4toInaddr - -/* for ErrPost */ -#define SOCK_ERRCODE 777 - - -#undef NLM_EXTERN -#ifdef NLM_IMPORT -#define NLM_EXTERN NLM_IMPORT -#else -#define NLM_EXTERN extern -#endif - -#ifdef __cplusplus -extern "C" { -#endif - - -/* Handle of a socket (see "ncbi_socket.[ch]") - */ -struct LSOCK_tag; /* listening socket: internal storage */ -typedef struct LSOCK_tag* LSOCK; /* listening socket: handle */ - -struct SOCK_tag; /* socket: internal storage */ -typedef struct SOCK_tag* SOCK; /* socket: handle */ - - -/* Error code - */ -typedef enum -{ - eSOCK_ESuccess = 0, /* everything is fine, no errors occurred */ - eSOCK_ETimeout, /* timeout expired before the data could be i/o'd */ - eSOCK_EClosed, /* peer has closed the connection */ - - eSOCK_EUnknown /* unknown(most probably -- fatal) error */ -} ESOCK_ErrCode; - - -/* I/O direction - */ -typedef enum { - eSOCK_OnRead, - eSOCK_OnWrite, - eSOCK_OnReadWrite -} ESOCK_Mode; - - -/* Return (const) verbal description for the passed error code - */ -NLM_EXTERN const char* SOCK_ErrCodeStr -(ESOCK_ErrCode err_code - ); - - - -/****************************************************************************** - * LISTENING SOCKET - */ - - -/* [SERVER-side] Create and initialize the server-side(listening) socket - * (socket() + bind() + listen()) - */ -NLM_EXTERN ESOCK_ErrCode LSOCK_Create -(Nlm_Uint2 port, /* [in] the port to listen at */ - Nlm_Uint2 n_listen, /* [in] maximal # of pending connections */ - LSOCK* lsock /* [out] handle of the created listening socket */ - ); - - -/* [SERVER-side] Accept connection from a client - * NOTE: the "*timeout" is for this accept() only; to set i/o timeout, - * use SOCK_Timeout(); (by default -- infinite) - */ -NLM_EXTERN ESOCK_ErrCode LSOCK_Accept -(LSOCK lsock, /* [in] handle of a listening socket */ - const STimeout* timeout, /* [in] timeout(infinite if NULL) */ - SOCK* sock /* [out] handle of the created socket */ - ); - - -/* [SERVER-side] Close the listening socket, destroy relevant internal data - */ -NLM_EXTERN ESOCK_ErrCode LSOCK_Close -(LSOCK lsock - ); - - -/* Get an OS-dependent native socket handle to use by platform-specific API. - * FYI: on MS-Windows it will be "SOCKET", on other platforms -- "int". - */ -NLM_EXTERN ESOCK_ErrCode LSOCK_GetOSHandle -(LSOCK lsock, - void* handle_buf, /* pointer to a memory area to put the OS handle at */ - Nlm_Uint4 handle_size /* exact(!) size of the expected OS handle */ - ); - - - -/****************************************************************************** - * SOCKET - */ - - -/* [CLIENT-side] Connect client to another(server-side, listening) socket - * (socket() + connect() [+ select()]) - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Create -(const char* host, /* [in] server host */ - Nlm_Uint2 port, /* [in] server port */ - const STimeout* timeout, /* [in] the connect timeout */ - SOCK* sock /* [out] handle of the created socket */ -); - - -/* [CLIENT-side] Close the socket referred by "sock" and then connect - * it to another "host:port"; fail if it takes more than "timeout". - * (close() + connect() [+ select()]) - * - * HINT: if "host" is NULL then connect to the same host address as before - * if "port" is zero then connect to the same port # as before - * NOTE: "new" socket inherits the i/o timeouts, - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Reconnect -(SOCK sock, /* handle of the socket to reconnect */ - const char* host, /* [in] server host */ - Nlm_Uint2 port, /* [in] server port */ - const STimeout* timeout /* [in] the connect timeout */ - ); - - -/* [CLIENT-side] Close the connection, destroy relevant internal data - * NOTE: if write timeout is specified then it is lingering until either all - * unsent data are sent or until the timeout expires - * NOTE: whatever error code is returned, this function cannot be - * called more than once for the same socket - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Close -(SOCK sock - ); - - -/* Block on the socket until either read/write(dep. on "mode") is - * available or timeout expires(if "timeout" is NULL then assume it infinite) - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Select -(SOCK sock, - ESOCK_Mode mode, - const STimeout* timeout - ); - - -/* Specify timeout for the connection i/o (see SOCK_[Read|Write|Close] funcs). - * NOTE: set the timeout to the maximum if "new_timeout" is NULL - * NOTE: the default timeout is the maximum possible(wait "ad infinitum") - */ -#define SOCK_GET_TIMEOUT ((const STimeout*)~0) -NLM_EXTERN ESOCK_ErrCode SOCK_SetTimeout -(SOCK sock, - ESOCK_Mode mode, - const STimeout* new_timeout, /* (dont set if equal to SOCK_GET_TIMEOUT) */ - STimeout* r_timeout, /* if non-NULL, return previous read */ - STimeout* w_timeout /* and(or) write timeout values */ - ); - - -/* Read up to "size" bytes from "sock" to the mem.buffer pointed by "buf". - * In "*n_read", return the number of succesfully read bytes. - * If there is no data available to read and the timeout(see - * SOCK_Timeout()) is expired then return eSOCK_ETimeout. - * NOTE: Theoretically, eSOCK_Closed may indicate an empty message - * rather than a real closure of the connection... - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Read -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read - ); - - -/* Operate just like SOCK_Read() but it persistently tries to read *exactly* - * "size" bytes, and it reads again and again -- until timeout expiration or - * error - */ -NLM_EXTERN ESOCK_ErrCode SOCK_ReadPersist -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read - ); - - -/* Operate just like SOCK_Read() but dont remove the read data from the - * input queue. - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Peek -(SOCK sock, - void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_read - ); - - -/* Push the specified data back to the socket input queue(to the socket's - * internal read buffer). These can be any data, not necessarily the data - * previously read from the socket. - */ -NLM_EXTERN ESOCK_ErrCode SOCK_PushBack -(SOCK sock, - const void* buf, - Nlm_Uint4 size - ); - - -/* If the last input operation (Read, ReadPersist or Peek) hit EOF. - * NOTE: the input operations does not return SOCK_eClosed unless there - * is no more data to read/peek; thus, in the case of Peek, this is - * the only "non-destructive" way to check whether it already hit - * the EOF or we can still expect more data to come. - */ -NLM_EXTERN Nlm_Boolean SOCK_Eof -(SOCK sock - ); - - -/* Write "size" bytes from the mem.buffer "buf" to "sock". - * In "*n_written", return the number of successfully written bytes. - * If cannot write all data and the timeout(see SOCK_Timeout()) is expired - * then return eSOCK_ETimeout. - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Write -(SOCK sock, - const void* buf, - Nlm_Uint4 size, - Nlm_Uint4* n_written - ); - - -/* Get host address and port of the socket peer - * If "network_byte_order" is true then return them in the network byte order - * NOTE: "host" or "port" can be NULL - */ -NLM_EXTERN void SOCK_Address -(SOCK sock, - Nlm_Uint4* host, - Nlm_Uint2* port, - Nlm_Boolean network_byte_order - ); - - -/* Get an OS-dependent native socket handle to use by platform-specific API. - * FYI: on MS-Windows it will be "SOCKET", on other platforms -- "int". - */ -NLM_EXTERN ESOCK_ErrCode SOCK_GetOSHandle -(SOCK sock, - void* handle_buf, /* pointer to a memory area to put the OS handle at */ - Nlm_Uint4 handle_size /* exact(!) size of the expected OS handle */ - ); - - - -/****************************************************************************** - * SHUTDOWN - */ - -/* Destroy internal data used by this module - * NOTE: no function from this API can be used after the call to SOCK_Destroy - */ -NLM_EXTERN ESOCK_ErrCode SOCK_Destroy(void); - - - -/****************************************************************************** - * AUXILIARY network-specific functions (added for the portability reasons) - */ - - -NLM_EXTERN Nlm_Boolean GetHostName -(char* name, - Nlm_Uint4 namelen - ); - -NLM_EXTERN Nlm_Boolean Uint4toInaddr -(Nlm_Uint4 ui4_addr, /* NOTE: must be in the network byte-order */ - char* buf, /* to be filled by smth. like "123.45.67.89\0" */ - Nlm_Uint4 buf_len - ); - -/* Total KLUDGE (dont use this beast, please) */ -NLM_EXTERN Nlm_Uint4 Nlm_htonl(Nlm_Uint4 value); - - -#ifdef __cplusplus -} -#endif - -#undef NLM_EXTERN -#ifdef NLM_EXPORT -#define NLM_EXTERN NLM_EXPORT -#else -#define NLM_EXTERN -#endif - -#endif /* NCBISOCK__H */ diff --git a/connect/test/http_connector_hit.c b/connect/test/http_connector_hit.c index 713809d8..b4625f80 100644 --- a/connect/test/http_connector_hit.c +++ b/connect/test/http_connector_hit.c @@ -1,4 +1,4 @@ -/* $Id: http_connector_hit.c,v 6.13 2004/04/01 14:14:02 lavr Exp $ +/* $Id: http_connector_hit.c,v 6.16 2005/04/20 18:23:11 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,6 +31,7 @@ */ #include "../ncbi_ansi_ext.h" +#include "../ncbi_assert.h" #include <connect/ncbi_http_connector.h> #include <connect/ncbi_util.h> /* This header must go last */ @@ -130,8 +131,8 @@ int main(int argc, const char* argv[]) if (argc < 4) { fprintf(stderr, "Usage: %s host port path [args] [inp_file] [user_header]\n" - "Example: %s yar.ncbi.nlm.nih.gov 6224 " - "/tools/vakatov/con_url.cgi 'arg1+arg2+arg3'\n", + "Example: %s www.ncbi.nlm.nih.gov 80 " + "/Service/bounce.cgi 'arg1+arg2+arg3'\n", argv[0], argv[0]); fprintf(stderr, "Too few arguments.\n"); return 1; @@ -199,6 +200,15 @@ int main(int argc, const char* argv[]) /* * -------------------------------------------------------------------------- * $Log: http_connector_hit.c,v $ + * Revision 6.16 2005/04/20 18:23:11 lavr + * +"../ncbi_assert.h" + * + * Revision 6.15 2004/11/23 15:04:26 lavr + * Use public bounce.cgi from "www" + * + * Revision 6.14 2004/11/22 20:24:53 lavr + * "yar" replaced with "graceland" + * * Revision 6.13 2004/04/01 14:14:02 lavr * Spell "occurred", "occurrence", and "occurring" * diff --git a/connect/test/socket_io_bouncer.c b/connect/test/socket_io_bouncer.c index 8ba1edb0..9139fe85 100644 --- a/connect/test/socket_io_bouncer.c +++ b/connect/test/socket_io_bouncer.c @@ -1,4 +1,4 @@ -/* $Id: socket_io_bouncer.c,v 6.7 2002/12/04 19:50:31 lavr Exp $ +/* $Id: socket_io_bouncer.c,v 6.8 2005/04/20 18:23:11 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ */ #include "../ncbi_ansi_ext.h" +#include "../ncbi_assert.h" #include <connect/ncbi_socket.h> #include <stdio.h> #include <stdlib.h> @@ -157,6 +158,9 @@ int main(int argc, const char* argv[]) /* * -------------------------------------------------------------------------- * $Log: socket_io_bouncer.c,v $ + * Revision 6.8 2005/04/20 18:23:11 lavr + * +"../ncbi_assert.h" + * * Revision 6.7 2002/12/04 19:50:31 lavr * #include "../ncbi_ansi_ext.h" instead of <string.h> to define strcasecmp() * diff --git a/connect/test/test_assert.h b/connect/test/test_assert.h index 926f0a7c..8fc5f0bb 100644 --- a/connect/test/test_assert.h +++ b/connect/test/test_assert.h @@ -1,7 +1,7 @@ #ifndef TEST_ASSERT__H #define TEST_ASSERT__H -/* $Id: test_assert.h,v 6.22 2004/06/10 19:20:27 ivanov Exp $ +/* $Id: test_assert.h,v 6.25 2005/04/07 16:27:30 ivanov Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,24 +57,36 @@ * and in debug libraries, as well as all General Protection Fault messages. * Environment variable DIAG_SILENT_ABORT must be set to "Y" or "y". */ + +/* Handler for "Unhandled" exceptions */ +static LONG CALLBACK _SEH_Handler(EXCEPTION_POINTERS* ep) +{ + /* Always terminate a program */ + return EXCEPTION_EXECUTE_HANDLER; +} + static int _SuppressDiagPopupMessages(void) { /* Check environment variable for silent abort app at error */ const char* value = getenv("DIAG_SILENT_ABORT"); if (value && (*value == 'Y' || *value == 'y')) { /* Windows GPF errors */ - SetErrorMode(SEM_NOGPFAULTERRORBOX); + SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | + SEM_NOOPENFILEERRORBOX); /* Runtime library */ _set_error_mode(_OUT_TO_STDERR); /* Debug library */ - _CrtSetReportFile(_CRT_WARN, stderr); + _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ERROR, stderr); + _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE); - _CrtSetReportFile(_CRT_ASSERT, stderr); + _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR); _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE); + + /* Exceptions */ + SetUnhandledExceptionFilter(_SEH_Handler); } return 0; } @@ -130,6 +142,15 @@ static int (*_SDPM)(void) = _SuppressDiagPopupMessages; /* * -------------------------------------------------------------------------- * $Log: test_assert.h,v $ + * Revision 6.25 2005/04/07 16:27:30 ivanov + * _SuppressDiagPopupMessages(): added handling of "Unhandled" exceptions + * + * Revision 6.24 2005/02/22 19:49:55 ivanov + * Added more suppress modes for SetErrorMode() + * + * Revision 6.23 2004/12/21 03:44:42 lavr + * Fix CRT report file destination, _CRTDBG_FILE_STDERR not stderr! + * * Revision 6.22 2004/06/10 19:20:27 ivanov * _SuppressDiagPopupMessages() returns 'int' to avoid runtime errors on MSVC7 * diff --git a/connect/test/test_ncbi_connutil_misc.c b/connect/test/test_ncbi_connutil_misc.c index a26809f6..732ceee0 100644 --- a/connect/test/test_ncbi_connutil_misc.c +++ b/connect/test/test_ncbi_connutil_misc.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_connutil_misc.c,v 6.14 2004/04/01 14:14:02 lavr Exp $ +/* $Id: test_ncbi_connutil_misc.c,v 6.18 2005/04/20 18:23:26 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ #include <connect/ncbi_connutil.h> #include <connect/ncbi_util.h> +#include <stdlib.h> #include <string.h> /* This header must go last */ #include "test_assert.h" @@ -141,6 +142,51 @@ static void TEST_URL_Encoding(void) } +/*********************************************************************** + * TEST: BASE64_Encode(), BAS64_Decode() + */ + +static void TEST_BASE64_Encoding(void) +{ + const char test_string[] = "Quick brown fox jumps over the lazy dog"; + char buf1[1024], buf2[1024], buf3[1024]; + size_t read, written, len = 16, i, j; + + BASE64_Encode(test_string, strlen(test_string) + 1, &read, + buf1, sizeof(buf1), &written, &len); + assert(read == strlen(test_string) + 1); + assert(written < sizeof(buf1)); + assert(buf1[written] == '\0'); + + assert(BASE64_Decode(buf1, written, &read, + buf2, sizeof(buf2), &written)); + assert(strlen(buf1) == read); + assert(written == strlen(test_string) + 1); + assert(buf2[written - 1] == '\0'); + assert(strcmp(buf2, test_string) == 0); + + for (i = 0; i < 100; i++) { + len = rand() % 250; + memset(buf1, '\0', sizeof(buf1)); + memset(buf2, '=', sizeof(buf2)); + memset(buf3, '\0', sizeof(buf3)); + for (j = 0; j < len; j++) { + buf1[j] = rand() & 0xFF; + } + + j = rand() % 100; + BASE64_Encode(buf1, len, &read, buf2, sizeof(buf2), &written, &j); + assert(len == read); + assert (written < sizeof(buf2)); + assert(buf2[written] == '\0'); + + buf2[written] = '='; + BASE64_Decode(buf2, written, &read, buf3, sizeof(buf3), &written); + assert(len == written); + assert(memcmp(buf1, buf3, len) == 0); + } +} + /*********************************************************************** * TEST: Miscellaneous @@ -291,6 +337,7 @@ int main(void) CORE_SetLOGFILE(stderr, 0/*false*/); TEST_URL_Encoding(); + TEST_BASE64_Encoding(); TEST_MIME(); TEST_ConnNetInfo(); @@ -302,6 +349,18 @@ int main(void) /* * --------------------------------------------------------------------------- * $Log: test_ncbi_connutil_misc.c,v $ + * Revision 6.18 2005/04/20 18:23:26 lavr + * +<stdlib.h> + * + * Revision 6.17 2005/03/21 17:04:51 lavr + * BASE64_{En|De}code tests extended + * + * Revision 6.16 2005/03/19 02:17:08 lavr + * Fix change log entry + * + * Revision 6.15 2005/03/19 02:14:10 lavr + * +Test for BASE64_{En|De}code + * * Revision 6.14 2004/04/01 14:14:02 lavr * Spell "occurred", "occurrence", and "occurring" * diff --git a/connect/test/test_ncbi_core.c b/connect/test/test_ncbi_core.c index 02160ef4..62d11888 100644 --- a/connect/test/test_ncbi_core.c +++ b/connect/test/test_ncbi_core.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_core.c,v 6.9 2002/08/14 03:35:26 lavr Exp $ +/* $Id: test_ncbi_core.c,v 6.10 2005/04/20 18:23:11 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -32,6 +32,7 @@ * */ +#include "../ncbi_assert.h" #include <connect/ncbi_util.h> #include <stdlib.h> #include <errno.h> @@ -362,6 +363,9 @@ int main(void) /* * --------------------------------------------------------------------------- * $Log: test_ncbi_core.c,v $ + * Revision 6.10 2005/04/20 18:23:11 lavr + * +"../ncbi_assert.h" + * * Revision 6.9 2002/08/14 03:35:26 lavr * Fix ELOG_Level test; add eIO_Interrupt to EIO_Status test * diff --git a/connect/test/test_ncbi_dsock.c b/connect/test/test_ncbi_dsock.c index 1fa884bb..d535c7b9 100644 --- a/connect/test/test_ncbi_dsock.c +++ b/connect/test/test_ncbi_dsock.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_dsock.c,v 6.14 2003/12/11 15:34:29 lavr Exp $ +/* $Id: test_ncbi_dsock.c,v 6.15 2005/01/05 21:33:58 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -57,13 +57,20 @@ /* This is the maximal datagram size defined by the UDP standard */ # define MAX_DGRAM_SIZE 65535 #endif +/* NOTE: x86_64 (AMD) kernel does not allow dgrams bigger than MTU minus + * small overhead; for these we use the script and pass the MTU via argv. + */ #define DEFAULT_PORT 55555 +static unsigned short s_MTU = MAX_DGRAM_SIZE; + + static int s_Usage(const char* prog) { - CORE_LOGF(eLOG_Error, ("Usage:\n%s {client|server} [port [seed]]", prog)); + CORE_LOGF(eLOG_Error, ("Usage:\n%s {client|server} [port [mtu [seed]]]", + prog)); return 1; } @@ -220,7 +227,7 @@ static int s_Client(int x_port, unsigned int max_try) return 1; } - msglen = (size_t)(((double)rand()/(double)RAND_MAX)*(MAX_DGRAM_SIZE - 10)); + msglen = (size_t)(((double)rand()/(double)RAND_MAX)*(s_MTU - 10)); if (msglen < sizeof(time_t)) msglen = sizeof(time_t); @@ -336,17 +343,17 @@ int main(int argc, const char* argv[]) fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); - if (argc < 2 || argc > 4) + if (argc < 2 || argc > 5) return s_Usage(argv[0]); - if (argc <= 3) { + if (argc <= 4) { #ifdef NCBI_OS_UNIX seed = (unsigned long) time(0) + (unsigned long) getpid(); #else seed = (unsigned long) time(0); #endif /*NCBI_OS_UNIX*/ } else - sscanf(argv[3], "%lu", &seed); + sscanf(argv[4], "%lu", &seed); CORE_LOGF(eLOG_Note, ("Random SEED = %lu", seed)); srand(seed); @@ -358,6 +365,12 @@ int main(int argc, const char* argv[]) SOCK_SetDataLoggingAPI(eOn); } + if (argc > 3) { + int mtu = atoi(argv[3]); + if (mtu > 32 && mtu < (int) s_MTU) + s_MTU = mtu - 32/*small protocol (IP/UDP) overhead*/; + } + if (!(env = getenv("CONN_MAX_TRY")) || !(max_try = atoi(env))) max_try = DEF_CONN_MAX_TRY; @@ -374,6 +387,9 @@ int main(int argc, const char* argv[]) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_dsock.c,v $ + * Revision 6.15 2005/01/05 21:33:58 lavr + * Introduce MTU and use it on AMD-64 buggy kernels + * * Revision 6.14 2003/12/11 15:34:29 lavr * Lower maximal datagram size for Linux - 65535 didn't seem to work everywhere * diff --git a/connect/test/test_ncbi_file_connector.c b/connect/test/test_ncbi_file_connector.c index ac464ce2..9588ec19 100644 --- a/connect/test/test_ncbi_file_connector.c +++ b/connect/test/test_ncbi_file_connector.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_file_connector.c,v 6.5 2004/02/23 15:23:43 lavr Exp $ +/* $Id: test_ncbi_file_connector.c,v 6.6 2005/04/20 18:23:11 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -30,6 +30,7 @@ * */ +#include "../ncbi_assert.h" #include <connect/ncbi_connection.h> #include <connect/ncbi_file_connector.h> #include <connect/ncbi_util.h> @@ -120,6 +121,9 @@ int main(int argc, const char* argv[]) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_file_connector.c,v $ + * Revision 6.6 2005/04/20 18:23:11 lavr + * +"../ncbi_assert.h" + * * Revision 6.5 2004/02/23 15:23:43 lavr * New (last) parameter "how" added in CONN_Write() API call * diff --git a/connect/test/test_ncbi_ftp_connector.c b/connect/test/test_ncbi_ftp_connector.c new file mode 100644 index 00000000..0155115e --- /dev/null +++ b/connect/test/test_ncbi_ftp_connector.c @@ -0,0 +1,159 @@ +/* $Id: test_ncbi_ftp_connector.c,v 1.3 2004/12/27 15:32:10 lavr Exp $ + * =========================================================================== + * + * PUBLIC DOMAIN NOTICE + * National Center for Biotechnology Information + * + * This software/database is a "United States Government Work" under the + * terms of the United States Copyright Act. It was written as part of + * the author's official duties as a United States Government employee and + * thus cannot be copyrighted. This software/database is freely available + * to the public for use. The National Library of Medicine and the U.S. + * Government have not placed any restriction on its use or reproduction. + * + * Although all reasonable efforts have been taken to ensure the accuracy + * and reliability of the software and data, the NLM and the U.S. + * Government do not and cannot warrant the performance or results that + * may be obtained by using this software or data. The NLM and the U.S. + * Government disclaim all warranties, express or implied, including + * warranties of performance, merchantability or fitness for any particular + * purpose. + * + * Please cite the author in any work or product based on this material. + * + * =========================================================================== + * + * Author: Anton Lavrentiev + * + * File Description: + * Test case for FTP-based CONNECTOR + * + */ + +#include "../ncbi_ansi_ext.h" +#include "../ncbi_priv.h" +#include <connect/ncbi_connection.h> +#include <connect/ncbi_ftp_connector.h> +#include <stdlib.h> +/* This header must go last */ +#include "test_assert.h" + + +#define TEST_HOST "ftp.ncbi.nlm.nih.gov" +#define TEST_PORT 0 +#define TEST_USER "ftp" +#define TEST_PASS "none" +#define TEST_PATH "/" + + +int main(int argc, char* argv[]) +{ + static const char chdir[] = "CWD /toolbox/ncbi_tools\n"; + static const char file[] = "RETR CURRENT/ncbi.tar.gz"; + const char* env = getenv("CONN_DEBUG_PRINTOUT"); + int/*bool*/ aborting = 0; + STimeout timeout; + CONNECTOR connector; + FILE* data_file; + CONN conn; + ESwitch log = eDefault; + size_t n; + char buf[1024]; + EIO_Status status; + + /* Log and data-log streams */ + CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | + fLOG_OmitNoteLevel | fLOG_DateTime); + CORE_SetLOGFILE(stderr, 0/*false*/); + data_file = fopen("test_ncbi_ftp_connector.log", "wb"); + assert(data_file); + + timeout.sec = 3; + timeout.usec = 0; + + if (env && (strcasecmp(env, "1") == 0 || + strcasecmp(env, "TRUE") == 0 || + strcasecmp(env, "SOME") == 0 || + strcasecmp(env, "DATA") == 0)) { + log = eOn; + } + if (env && (strcasecmp(env, "0") == 0 || + strcasecmp(env, "NONE") == 0 || + strcasecmp(env, "FALSE") == 0)) { + log = eOff; + } + + /* Run the tests */ + connector = FTP_CreateDownloadConnector(TEST_HOST, TEST_PORT, + TEST_USER, TEST_PASS, + TEST_PATH, log); + + if (CONN_Create(connector, &conn) != eIO_Success) + CORE_LOG(eLOG_Fatal, "Cannot create FTP download connection"); + + if (CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain) != eIO_Closed) + CORE_LOG(eLOG_Fatal, "Test failed in empty READ"); + + if (CONN_Write(conn, "aaa", 3, &n, eIO_WritePlain) != eIO_Success) + CORE_LOG(eLOG_Fatal, "Cannot write FTP command"); + + if (CONN_Wait(conn, eIO_Read, &timeout) != eIO_Unknown) + CORE_LOG(eLOG_Fatal, "Test failed in waiting on READ"); + + if (CONN_Write(conn, "LIST", 4, &n, eIO_WritePlain) != eIO_Success) + CORE_LOG(eLOG_Fatal, "Cannot write LIST command"); + + do { + status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain); + if (n != 0) + printf("%.*s", (int) n, buf); + } while (status == eIO_Success); + + if (CONN_Write(conn, chdir, sizeof(chdir) - 1, &n, eIO_WritePlain) + != eIO_Success) { + CORE_LOGF(eLOG_Fatal, ("Cannot execute %.*s", + (int)sizeof(chdir) - 2, chdir)); + } + + if (CONN_Write(conn, file, sizeof(file) - 1, &n, eIO_WritePersist) + != eIO_Success) { + CORE_LOGF(eLOG_Fatal, ("Cannot write %s", file)); + } + + do { + status = CONN_Read(conn, buf, sizeof(buf), &n, eIO_ReadPlain); + if (n != 0) + fwrite(buf, n, 1, data_file); + if (argc > 1 && rand() % 100 == 0) { + aborting = 1; + break; + } + } while (status == eIO_Success); + + if (CONN_Close(conn) != eIO_Success) + CORE_LOGF(eLOG_Fatal, ("Error %s FTP connection", + aborting ? "aborting" : "closing")); + + /* Cleanup and Exit */ + fclose(data_file); + if (aborting) + remove("test_ncbi_ftp_connector.log"); + CORE_SetLOG(0); + return 0; +} + + +/* + * -------------------------------------------------------------------------- + * $Log: test_ncbi_ftp_connector.c,v $ + * Revision 1.3 2004/12/27 15:32:10 lavr + * Randomly test ABORTs (if there is an argument for main()) + * + * Revision 1.2 2004/12/06 22:02:51 ucko + * +<stdlib.h> for getenv() + * + * Revision 1.1 2004/12/06 17:49:00 lavr + * Initial revision + * + * ========================================================================== + */ diff --git a/connect/test/test_ncbi_http_connector.c b/connect/test/test_ncbi_http_connector.c index ab4adefb..7c8f9f5c 100644 --- a/connect/test/test_ncbi_http_connector.c +++ b/connect/test/test_ncbi_http_connector.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_http_connector.c,v 6.15 2004/04/01 14:14:02 lavr Exp $ +/* $Id: test_ncbi_http_connector.c,v 6.18 2004/11/23 15:04:39 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -41,9 +41,9 @@ /* Hard-coded pseudo-registry getter */ -#define TEST_HOST "yar.ncbi.nlm.nih.gov" -#define TEST_PORT "6224" -#define TEST_PATH "/tools/vakatov/con_url.cgi" +#define TEST_HOST "www.ncbi.nlm.nih.gov" +#define TEST_PORT "80" +#define TEST_PATH "/Service/bounce.cgi" #define TEST_ARGS "arg1+arg2+arg3" #define TEST_DEBUG_PRINTOUT "yes" #define TEST_REQ_METHOD "any" @@ -142,6 +142,15 @@ int main(void) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_http_connector.c,v $ + * Revision 6.18 2004/11/23 15:04:39 lavr + * Use public bounce.cgi from "www" + * + * Revision 6.17 2004/11/22 20:27:32 lavr + * Weird 5.123456 timeout restored to the form it used to be + * + * Revision 6.16 2004/11/22 20:25:27 lavr + * "yar" replaced with "graceland" + * * Revision 6.15 2004/04/01 14:14:02 lavr * Spell "occurred", "occurrence", and "occurring" * diff --git a/connect/test/test_ncbi_http_get.c b/connect/test/test_ncbi_http_get.c index bd1dfff2..7876f201 100644 --- a/connect/test/test_ncbi_http_get.c +++ b/connect/test/test_ncbi_http_get.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_http_get.c,v 6.12 2003/09/30 20:59:39 lavr Exp $ +/* $Id: test_ncbi_http_get.c,v 6.14 2005/04/20 15:51:19 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -34,6 +34,7 @@ #include "../ncbi_priv.h" #include <connect/ncbi_http_connector.h> #include <connect/ncbi_util.h> +#include <errno.h> #include <stdlib.h> #include <time.h> #ifdef NCBI_OS_UNIX @@ -48,8 +49,11 @@ int main(int argc, char* argv[]) static const STimeout s_ZeroTmo = {0, 0}; CONNECTOR connector; SConnNetInfo* net_info; + char blk[512]; + EIO_Status status; THCC_Flags flags; CONN conn; + FILE* fp; time_t t; size_t n; char* s; @@ -58,15 +62,22 @@ int main(int argc, char* argv[]) fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); - if (argc != 2 || !*argv[1]) { - CORE_LOG(eLOG_Error, "URL has to be supplied on the command line"); - exit(1); - } + if (argc < 2 || !*argv[1]) + CORE_LOG(eLOG_Fatal, "URL has to be supplied on the command line"); + if (argc > 3) + CORE_LOG(eLOG_Fatal, "Command cannot take more than 2 arguments"); + if (argc == 3) { + fp = strcmp(argv[2], "-") == 0 ? stdin : fopen(argv[2], "rb"); + if (!fp) { + CORE_LOGF_ERRNO(eLOG_Error, errno, ("Cannot open \"%s\"", + argv[2] ? argv[2] : "")); + } + } else + fp = 0; CORE_LOG(eLOG_Note, "Creating network info structure"); if (!(net_info = ConnNetInfo_Create(0))) CORE_LOG(eLOG_Fatal, "Cannot create network info structure"); - net_info->req_method = eReqMethod_Get; if ((s = getenv("CONN_TIMEOUT")) && strcmp(s, "0") == 0) { memcpy(&net_info->tmo, &s_ZeroTmo, sizeof(s_ZeroTmo)); net_info->timeout = &net_info->tmo; @@ -93,12 +104,19 @@ int main(int argc, char* argv[]) CORE_LOG(eLOG_Fatal, "Cannot create connection"); CONN_SetTimeout(conn, eIO_Open, net_info->timeout); CONN_SetTimeout(conn, eIO_ReadWrite, net_info->timeout); + while (fp && !feof(fp)) { + n = fread(blk, 1, sizeof(blk), fp); + status = CONN_Write(conn, blk, n, &n, eIO_WritePersist); + if (status != eIO_Success) { + CORE_LOGF(eLOG_Fatal, ("Write error: %s", IO_StatusStr(status))); + } + } + if (fp) + fclose(fp); t = time(0); for (;;) { - char blk[512]; - EIO_Status status = CONN_Wait(conn, eIO_Read, net_info->timeout); - + status = CONN_Wait(conn, eIO_Read, net_info->timeout); if (status != eIO_Success) { if (status == eIO_Closed) break; @@ -135,6 +153,12 @@ int main(int argc, char* argv[]) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_http_get.c,v $ + * Revision 6.14 2005/04/20 15:51:19 lavr + * Allow addtl file argument to attach as a body ('-' for stdin) + * + * Revision 6.13 2005/04/19 16:37:52 lavr + * Allow HTTP method to be overridden from the environment + * * Revision 6.12 2003/09/30 20:59:39 lavr * Fix typo in previous log message * diff --git a/connect/test/test_ncbi_mac_mit_socket.c b/connect/test/test_ncbi_mac_mit_socket.c deleted file mode 100755 index 9fb65309..00000000 --- a/connect/test/test_ncbi_mac_mit_socket.c +++ /dev/null @@ -1,301 +0,0 @@ -/* testmain.c - * - * Simple test routines for the DNR and socket interfaces that are - * linked from Sequin. A friendlier user interface would be nice... - * - * 02/27/00 pjc - * Added utility printing function and tests for 6 more functions - * - * 02/26/00 pjc - * gethostbyname and gethostbyaddr: first working - * - * Created 1/15/00 by pchurchill - */ - -#include <stdio.h> -#include <stdlib.h> -#include <time.h> -#include <s_socket.h> -#include <OpenTptInternet.h> // for TCP/IP -#include <netdb.h> -#include <neti_in.h> -#include <a_inet.h> - -/* printIP - * - * Utility function for printing out IP addresses during - * debugging - */ -int printIP( char** theAddr) -{ - int i = 0; - unsigned char *b; - unsigned long **x = (unsigned long **) theAddr; - - while( (theAddr[i] != 0) && (i < kMaxHostAddrs)){ - b = (unsigned char *) theAddr[i]; - printf( "IP address for 0x%lx \t", *x[i]); - printf( "is %d.%d.%d.%d\n",b[0],b[1],b[2],b[3]); - i++; - } - printf("\n"); - return 0; -} - -/* printHNames - * - * Utility function to print out the fully qualified hostname - * along with any aliases that were identified - */ -void printHNames( struct hostent* info) -{ - int i = 0; - - printf("Fully qualified hostname: %s\n", info->h_name); - printf("Also reported the aliases: "); - while( info->h_aliases[i] != NULL){ - printf("%s, ", info->h_aliases[i]); - i++; - } - printf("\n"); - return; -} - - -void testGetHostByName( const char* hostname) -{ - struct hostent *ans = NULL; - - printf("Calling gethostbyname() for '%s'\n", hostname); - ans = gethostbyname(hostname); - if( ans != NULL){ - printIP( &ans->h_addr_list[0]); - printHNames( ans); - } - else{ - printf("gethostbyname returned 'NULL'.\n\terrno reads as %d\n",ncbi_GetErrno()); - } - printf("\n"); - return; -} - -void testGetHostByAddr( InetHost theAddr) -{ - struct hostent *ans = NULL; - - printf("Calling gethostbyaddr() for '%8lx'\n", theAddr); - ans = gethostbyaddr( &theAddr, 4, AF_INET); - if( ans != NULL){ - printIP( &ans->h_addr_list[0]); - printHNames( ans); - } - else{ - printf("Hmm, gethostbyaddr returned 'NULL'. Need to implement errno\n"); - } - printf("\n"); - return; -} - -void testGetHostID( void) -{ - unsigned char *b; - InetHost hostid; - - printf("About to call gethostid()\n"); - hostid = gethostid(); - if( hostid == 0){ - printf("gethostid returned 0. Need to implement errno\n"); - } - else{ - b = (unsigned char *) &hostid; - printf("gethostid() returned 0x%8x, %d.%d.%d.%d\n\n", hostid, - b[0],b[1],b[2],b[3]); - } - return; -} - -void testGetHostName( void) -{ - char myname[255]; - int ans = 0; - - printf("About to call gethostname()\n"); - ans = gethostname( myname, 255); - if( ans != 0){ - printf("gethostname returned 0. Need to implement errno\n"); - } - else{ - printf("gethostname() returned %s\n\n", myname); - } - return; -} - -/* testInet_ntoa - * - * test the address utility that converts IP addresses from network - * to host byte ordering (this is trivial on a Mac, they are both - * in the same order) - */ -void testInet_ntoa( InetHost x) -{ - char* ans; - struct in_addr addr; - - addr.s_addr = x; - printf("About to call inet_ntoa for 0x%8x\n", x); - ans = inet_ntoa( addr); - if( ans != NULL){ - printf("inet_ntoa returned: %s\n\n", ans); - } - else{ - printf("inet_ntoa returned NULL, Need to implement errno\n"); - } - return; -} - -/* testInet_aton - * - * tests utility that converts from dotted decimal notation (string) - * to internet host address (hex). Both input and output are through - * parameters passed to the function. - */ -void testInet_aton( const char* string) -{ - int error; - struct in_addr addr; - - printf("About to call inet_aton for %s\n", string); - error = inet_aton( string, &addr); - if( error == INET_SUCCESS){ - printf("inet_aton returned: 0x%8x\n\n", addr.s_addr); - } - else{ - printf("inet_ntoa returned %d\n\n", error); - } - return; -} - - -/* testInet_addr - * - * tests utility that converts from dotted decimal notation (string) - * to internet host address (hex) - */ -void testInet_addr( const char* string) -{ - InetHost addr; - - printf("About to call inet_addr for %s\n", string); - addr = inet_addr( string); - printf("inet_addr returned: 0x%8x\n\n", addr); - return; -} - -/* testGetServByName - * - */ -void testGetServByName( void) -{ - struct servent *ans; - char *proto[] = {"udp","tcp"}; - char *serv[] = {"ftp","http","gopher","nfs","\0"}; - int i; - - for( i = 0; serv[i] != "\0"; i++){ - printf("\nCalling getservbyname for %s, %s\n", serv[i], proto[1]); - ans = getservbyname( serv[i], proto[1]); - if( ans != NULL){ - printf(" getservbyname: returned %s, %s, %d\n", - ans->s_name, ans->s_proto, ans->s_port); - } else{ - printf(" getservbyname: Returned NULL, maybe it doesn't exist?\n"); - } - } - return; -} - - -/* testGetServByPort - * - */ -void testGetServByPort( void) -{ - struct servent *udpAns, *tcpAns; - char ans1[32], ans2[32]; - int i; - - printf("Testing getservbyport, by scanning the first 255 ports\n\n"); - printf("Port #: udp service tcp service\n"); - for( i=0; i<=255; i++){ - udpAns = getservbyport( i, "udp"); - if( udpAns){ - strncpy( ans1, udpAns->s_name, 30); - } - tcpAns = getservbyport( i, "tcp"); - if( tcpAns){ - strncpy( ans2, tcpAns->s_name, 30); - } - if( (udpAns == NULL) && (tcpAns == NULL)){ - continue; - } - printf(" %3d: ", i); - if( udpAns){ - printf("%12s", ans1); - } - if( tcpAns){ - printf("%14s", ans2); - } - printf("\n"); - } - return; -} - - -/* main - * - */ - -int main( void) -{ - // for now, just call the functions. don't do anything real ;-) - - printf("Hello, this is Phil's OT dnr tester\n\n"); - - // first, test functions that don't require network - testInet_ntoa( 0x80082680); - testInet_aton( "128.8.38.128"); - testInet_addr( "38.128.8.128"); - testGetServByName(); - // This test takes quite a while to run... - // testGetServByPort(); - - // next get info about our local machine - testGetHostID(); - testGetHostName(); - - // then lookup a few others to see if they work... - testGetHostByAddr( 0x80082680); - testGetHostByName( "www.apple.com"); - testGetHostByName( "www.churchillandassociates.com"); - testGetHostByName( "mail"); - // one that should fail... - testGetHostByName( "foo.dev.com"); - -// s_socket(); // create the socket -// s_close(); // close it (free the resources) -// s_connect(); // connect using udp or tcp -// s_send(); // just send # bytes -// s_write(); // similar, but datagram oriented -// s_recv(); // just get the next n bytes -// s_read(); // similar, but datagram oriented -// s_setsockopt(); -// s_accept(); -// s_listen(); -// s_bind(); -// s_fcntl(); -/* - bzero(); // unchanged from ncsalib - */ - return 0; -} - diff --git a/connect/test/test_ncbi_sendmail.c b/connect/test/test_ncbi_sendmail.c index 47f884f6..c3ea3d8a 100644 --- a/connect/test/test_ncbi_sendmail.c +++ b/connect/test/test_ncbi_sendmail.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_sendmail.c,v 6.11 2003/12/09 15:39:30 lavr Exp $ +/* $Id: test_ncbi_sendmail.c,v 6.13 2005/03/21 17:30:28 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -31,7 +31,9 @@ */ #include "../ncbi_priv.h" /* CORE logging facilities */ +#include "../ncbi_ansi_ext.h" #include <connect/ncbi_sendmail.h> +#include <connect/ncbi_socket.h> #include <stdlib.h> #include <string.h> #include <time.h> @@ -58,6 +60,7 @@ int main(void) ".\n", "", "a\nb\nc\nd\n.", + "a\r\n\rb\r\nc\r\nd\r\n.", ".\na" }; const char* subject[] = { @@ -70,19 +73,27 @@ int main(void) "lavr@pavo", " \"Anton Lavrentiev\" <lavr@pavo> , lavr, <lavr> ", }; + const char* mx_host, *p; size_t i, j, k, n, m; - const char* mx_host; SSendMailInfo info; const char* retval; STimeout mx_tmo; char* huge_body; short mx_port; - FILE *fp; + FILE* fp; CORE_SetLOGFormatFlags(fLOG_None | fLOG_Level | fLOG_OmitNoteLevel | fLOG_DateTime); CORE_SetLOGFILE(stderr, 0/*false*/); srand(time(0)); + if ((p = getenv("CONN_DEBUG_PRINTOUT")) != 0) { + if (strncasecmp(p, "1", 1) == 0 || + strncasecmp(p, "YES", 3) == 0 || + strncasecmp(p, "SOME", 4) == 0 || + strncasecmp(p, "DATA", 4) == 0) { + SOCK_SetDataLoggingAPI(eOn); + } + } CORE_LOG(eLOG_Note, "Phase 1 of 2: Testing CORE_SendMail"); @@ -246,6 +257,12 @@ int main(void) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_sendmail.c,v $ + * Revision 6.13 2005/03/21 17:30:28 lavr + * Include "../ncbi_ansi_ext.h" (essential for Windows) + * + * Revision 6.12 2005/03/18 16:36:10 lavr + * Additional test for \r\n in body; debug output provision + * * Revision 6.11 2003/12/09 15:39:30 lavr * Added new test of custom-sized message body * diff --git a/connect/test/test_ncbi_service_connector.c b/connect/test/test_ncbi_service_connector.c index 5b474241..81d70005 100644 --- a/connect/test/test_ncbi_service_connector.c +++ b/connect/test/test_ncbi_service_connector.c @@ -1,4 +1,4 @@ -/* $Id: test_ncbi_service_connector.c,v 6.29 2004/02/23 15:23:43 lavr Exp $ +/* $Id: test_ncbi_service_connector.c,v 6.31 2005/01/28 17:44:48 lavr Exp $ * =========================================================================== * * PUBLIC DOMAIN NOTICE @@ -43,9 +43,10 @@ int main(int argc, const char* argv[]) static char obuf[8192 + 2] = "UUUUUZZZZZZUUUUUUZUZUZZUZUZUZUZUZ\n"; const char* service = argc > 1 && *argv[1] ? argv[1] : "bounce"; const char* host = argc > 2 && *argv[2] ? argv[2] : "www.ncbi.nlm.nih.gov"; - SConnNetInfo *net_info; + SConnNetInfo* net_info; CONNECTOR connector; EIO_Status status; + STimeout* timeout; char ibuf[1024]; CONN conn; size_t n; @@ -61,9 +62,9 @@ int main(int argc, const char* argv[]) obuf[++n] = 0; } strcpy(net_info->args, "testarg=testval&service=none"); + timeout = net_info->timeout; connector = SERVICE_CreateConnectorEx(service, fSERV_Any, net_info, 0); - ConnNetInfo_Destroy(net_info); if (!connector) CORE_LOG(eLOG_Fatal, "Failed to create service connector"); @@ -99,10 +100,7 @@ int main(int argc, const char* argv[]) #endif for (;;) { - STimeout timeout; - timeout.sec = 5; - timeout.usec = 12345; - if (CONN_Wait(conn, eIO_Read, &timeout) != eIO_Success) { + if (CONN_Wait(conn, eIO_Read, timeout) != eIO_Success) { CONN_Close(conn); CORE_LOG(eLOG_Fatal, "Error waiting for reading"); } @@ -150,6 +148,8 @@ int main(int argc, const char* argv[]) CORE_LOG(eLOG_Fatal, "Error reading from service ID1"); } + + ConnNetInfo_Destroy(net_info); CORE_LOGF(eLOG_Note, ("%d bytes read from service ID1", n)); CONN_Close(conn); #endif @@ -162,6 +162,12 @@ int main(int argc, const char* argv[]) /* * -------------------------------------------------------------------------- * $Log: test_ncbi_service_connector.c,v $ + * Revision 6.31 2005/01/28 17:44:48 lavr + * Fix: forgotten to merge status variable relocation + * + * Revision 6.30 2005/01/28 17:41:22 lavr + * Allow CONN_TIMEOUT from the environment to be used in Wait-on-Read + * * Revision 6.29 2004/02/23 15:23:43 lavr * New (last) parameter "how" added in CONN_Write() API call * diff --git a/connect/test/test_ncbisock.c b/connect/test/test_ncbisock.c deleted file mode 100644 index ca20b1ba..00000000 --- a/connect/test/test_ncbisock.c +++ /dev/null @@ -1,647 +0,0 @@ -/* $Id: test_ncbisock.c,v 6.1 1999/10/18 15:40:50 vakatov Exp $ - * =========================================================================== - * - * PUBLIC DOMAIN NOTICE - * National Center for Biotechnology Information - * - * This software/database is a "United States Government Work" under the - * terms of the United States Copyright Act. It was written as part of - * the author's official duties as a United States Government employee and - * thus cannot be copyrighted. This software/database is freely available - * to the public for use. The National Library of Medicine and the U.S. - * Government have not placed any restriction on its use or reproduction. - * - * Although all reasonable efforts have been taken to ensure the accuracy - * and reliability of the software and data, the NLM and the U.S. - * Government do not and cannot warrant the performance or results that - * may be obtained by using this software or data. The NLM and the U.S. - * Government disclaim all warranties, express or implied, including - * warranties of performance, merchantability or fitness for any particular - * purpose. - * - * Please cite the author in any work or product based on this material. - * - * =========================================================================== - * - * Author: Denis Vakatov - * - * File Description: - * Test suite for "ncbisock.[ch]" - * - * --------------------------------------------------------------------------- - * $Log: test_ncbisock.c,v $ - * Revision 6.1 1999/10/18 15:40:50 vakatov - * Initial revision - * - * =========================================================================== - */ - -#include <ncbilcl.h> -#if defined(OS_UNIX) -# include <unistd.h> -# define X_SLEEP(x) ((void) sleep(x)) -#elif defined(OS_MSWIN) -# include <windows.h> -# define X_SLEEP(x) ((void) Sleep(1000 * x)) -#else -# define X_SLEEP(x) ((void) 0) -#endif - -#include <ncbi.h> -#include <ncbisock.h> - - -#define TEST_BUFSIZE 8192 - -/* exit server before sending the data expected by client(Test 1) */ -/*#define TEST_SRV1_SHUTDOWN*/ - -#ifndef TEST_SRV1_SHUTDOWN -/* exit server immediately after its first client is served(Test 1) */ -/*#define TEST_SRV1_ONCE*/ -#endif - - -#define ASS_RET(expr,retcode) \ -if ( !(expr) ) { ASSERT ( 0 ); return retcode; } else {;} - - -/* The simplest randezvous(plain request-reply) test functions - * "TEST__client_1(SOCK sock)" - * "TEST__server_1(SOCK sock)" - */ - -static const char s_C1[] = "C1"; -static const char s_S1[] = "S1"; - -#define N_SUB_BLOB 10 -#define SUB_BLOB_SIZE 7000 -#define BIG_BLOB_SIZE (N_SUB_BLOB * SUB_BLOB_SIZE) - - -static Int2 TEST__client_1(SOCK sock) -{ /* reserved ret.codes [110-119] */ - ESOCK_ErrCode err_code; - Uint4 n_io, n_io_done; - char buf[TEST_BUFSIZE]; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 110, "TC1()"); - - /* Send a short string */ - n_io = StrLen(s_C1) + 1; - err_code = SOCK_Write(sock, s_C1, n_io, &n_io_done); - ASS_RET((err_code == eSOCK_ESuccess && n_io == n_io_done), 101); - - n_io = StrLen(s_S1) + 1; - err_code = SOCK_Read(sock, buf, n_io, &n_io_done); - if (err_code == eSOCK_EClosed) { - ErrPostEx(SEV_WARNING, SOCK_ERRCODE, 103, "TC1(): connection closed"); - return 103; - } - ASS_RET((err_code == eSOCK_ESuccess && n_io == n_io_done), 104); - ASS_RET((StrCmp(buf, s_S1) == 0), 105); - ASS_RET(SOCK_PushBack(sock, buf, n_io_done) == eSOCK_ESuccess, 106); - MemSet(buf, '\xFF', n_io_done); - ASS_RET(SOCK_Read(sock, buf, n_io_done, &n_io_done) == eSOCK_ESuccess, 107); - ASS_RET((StrCmp(buf, s_S1) == 0), 108); - - /* Send a very big binary blob */ - {{ - size_t i; - char* blob = (char*) MemNew(BIG_BLOB_SIZE); - for (i = 0; i < BIG_BLOB_SIZE; blob[i] = (char)i, i++) - continue; - for (i = 0; i < 10; i++) { - err_code = SOCK_Write(sock, blob + i * SUB_BLOB_SIZE, SUB_BLOB_SIZE, - &n_io_done); - ASS_RET((err_code == eSOCK_ESuccess && n_io_done==SUB_BLOB_SIZE), 109); - } - MemFree(blob); - }} - - return 0; -} - - -static Int2 TEST__server_1(SOCK sock) -{ /* reserved ret.codes [210-219] */ - ESOCK_ErrCode err_code; - Uint4 n_io, n_io_done; - char buf[TEST_BUFSIZE]; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 210, "TS1()"); - - /* Receive and send back a short string */ - n_io = StrLen(s_C1) + 1; - err_code = SOCK_Read(sock, buf, n_io, &n_io_done); - ASS_RET((err_code == eSOCK_ESuccess && n_io == n_io_done), 210); - ASS_RET((StrCmp(buf, s_C1) == 0), 211); - -#ifdef TEST_SRV1_SHUTDOWN - return 212; -#endif - - n_io = StrLen(s_S1) + 1; - err_code = SOCK_Write(sock, s_S1, n_io, &n_io_done); - ASS_RET((err_code == eSOCK_ESuccess && n_io == n_io_done), 213); - - /* Receive a very big binary blob, and check its content */ - {{ - char* blob = (char*)MemNew(BIG_BLOB_SIZE); - err_code = SOCK_ReadPersist(sock, blob, BIG_BLOB_SIZE, &n_io_done); - ASS_RET((err_code == eSOCK_ESuccess && n_io_done == BIG_BLOB_SIZE), 214); - for (n_io = 0; n_io < BIG_BLOB_SIZE; n_io++) - ASSERT( blob[n_io] == (char)n_io ); - MemFree(blob); - }} - - return 0; -} - - -/* More complicated randezvous test functions - * "TEST__client_2(SOCK sock)" - * "TEST__server_2(SOCK sock)" - */ - -static void s_DoubleTimeout(STimeout *to) { - if (!to->sec && !to->usec) { - to->usec = 1; - } else { - to->sec = 2 * to->sec + (2 * to->usec) / 1000000; - to->usec = (2 * to->usec) % 1000000; - } -} - -static Int2 TEST__client_2(SOCK sock) -{ /* reserved ret.codes [120-139] */ -#define W_FIELD 10 -#define N_FIELD 1000 -#define N_REPEAT 10 -#define N_RECONNECT 3 - ESOCK_ErrCode err_code; - Uint4 n_io, n_io_done, i; - char buf[W_FIELD * N_FIELD + 1]; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 110, "TC2()"); - - /* 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; - Boolean w_timeout_on = (Boolean) (i%2 != 0); /* if to start from */ - Boolean r_timeout_on = (Boolean) (i%3 != 0); /* zero or inf. timeout */ - char* x_buf; - - /* set timeout */ - w_to.sec = 0; - w_to.usec = 0; - err_code = SOCK_SetTimeout(sock, eSOCK_OnWrite, - (w_timeout_on ? &w_to : 0), 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 111); - -#ifdef DO_RECONNECT - /* reconnect */ - if ((i % N_RECONNECT) == 0) { - Uint4 j = i / N_RECONNECT; - do { - err_code = SOCK_Reconnect(sock, 0, 0, 0); - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 117, - "TC2:reconnect: i=%d, err_code=%d", - (int)i, (int)err_code); - ASS_RET((err_code == eSOCK_ESuccess), 117); - ASSERT( !SOCK_Eof(sock) ); - - /* give a break to let server to reset the listening socket */ - X_SLEEP(1); - } while ( j-- ); - } -#endif - - /* send */ - x_buf = buf; - n_io = sizeof(buf); - do { - X_SLEEP(1); - err_code = SOCK_Write(sock, x_buf, n_io, &n_io_done); - if (err_code == eSOCK_EClosed) { - ErrPostEx(SEV_ERROR, SOCK_ERRCODE, 112, - "TC2:write: connection closed"); - return 112; - } - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 113, - "TC2:write: i=%d, err_code=%d, n_io=%5lu, n_io_done=%5lu" - "\ntimeout(%d): %5lu sec, %6lu msec", - (int)i, (int)err_code, - (unsigned long)n_io, (unsigned long)n_io_done, - (int)w_timeout_on, - (unsigned long)w_to.sec, (unsigned long)w_to.usec); - if ( !w_timeout_on ) { - ASS_RET((err_code == eSOCK_ESuccess && n_io_done == n_io), 113); - } else { - STimeout x_to; - ASS_RET((err_code == eSOCK_ESuccess || err_code == eSOCK_ETimeout), - 114); - ASS_RET((SOCK_SetTimeout(sock, eSOCK_OnWrite, SOCK_GET_TIMEOUT, - 0, &x_to) == eSOCK_ESuccess && - w_to.sec == x_to.sec && w_to.usec == x_to.usec), 115); - } - n_io -= n_io_done; - x_buf += n_io_done; - if (err_code == eSOCK_ETimeout) - s_DoubleTimeout(&w_to); - err_code = SOCK_SetTimeout(sock, eSOCK_OnWrite, &w_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 116); - w_timeout_on = TRUE; - } while ( n_io ); - - /* get back the just sent data */ - r_to.sec = 0; - r_to.usec = 0; - err_code = SOCK_SetTimeout(sock, eSOCK_OnRead, - (r_timeout_on ? &r_to : 0), 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 121); - - 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]; - Uint4 xx_io_done1, xx_io_done2; - if (SOCK_Peek(sock, xx_buf1, sizeof(xx_buf1), &xx_io_done1) - == eSOCK_ESuccess && - SOCK_Peek(sock, xx_buf2, xx_io_done1, &xx_io_done2) - == eSOCK_ESuccess) { - ASSERT ( xx_io_done1 >= xx_io_done2 ); - VERIFY ( !MemCmp(xx_buf1, xx_buf2, xx_io_done2) ); - } - } - err_code = SOCK_Read(sock, x_buf, n_io, &n_io_done); - if (err_code == eSOCK_EClosed) { - ErrPostEx(SEV_ERROR, SOCK_ERRCODE, 122, - "TC2:read: connection closed"); - ASSERT( SOCK_Eof(sock) ); - return 122; - } - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 123, - "TC2:read: i=%d, err_code=%d, n_io=%5lu, n_io_done=%5lu" - "\ntimeout(%d): %5lu sec, %6lu msec", - (int)i, (int)err_code, - (unsigned long)n_io, (unsigned long)n_io_done, - (int)r_timeout_on, - (unsigned long)r_to.sec, (unsigned long)r_to.usec); - if ( !r_timeout_on ) { - ASS_RET((err_code == eSOCK_ESuccess && n_io_done > 0), 124); - } else { - STimeout x_to; - ASS_RET((err_code == eSOCK_ESuccess || err_code == eSOCK_ETimeout), - 125); - ASS_RET((SOCK_SetTimeout(sock, eSOCK_OnRead, SOCK_GET_TIMEOUT, - &x_to, 0) == eSOCK_ESuccess && - r_to.sec == x_to.sec && r_to.usec == x_to.usec), 126); - } - - n_io -= n_io_done; - x_buf += n_io_done; - if (err_code == eSOCK_ETimeout) - s_DoubleTimeout(&r_to); - err_code = SOCK_SetTimeout(sock, eSOCK_OnRead, &r_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 127); - r_timeout_on = TRUE; - } while ( n_io ); - - ASS_RET((!MemCmp(buf, buf1, sizeof(buf))), 120); - } - - return 0; -} - - -static Int2 TEST__server_2(SOCK sock, LSOCK lsock) -{ /* reserved ret.codes [220-229] */ - ESOCK_ErrCode err_code; - Uint4 n_io, n_io_done; - char buf[TEST_BUFSIZE]; - STimeout r_to, w_to; - Uint4 i; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 220, "TS2()"); - - r_to.sec = 0; - r_to.usec = 0; - w_to = r_to; - - /* goto */ - l_reconnect: /* reconnection loopback */ - - err_code = SOCK_SetTimeout(sock, eSOCK_OnRead, &r_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 220); - err_code = SOCK_SetTimeout(sock, eSOCK_OnWrite, &w_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 221); - - for (i = 0; ; i++) { - char* x_buf; - - /* read data from socket */ - n_io = sizeof(buf); - err_code = SOCK_Read(sock, buf, n_io, &n_io_done); - switch ( err_code ) - { - case eSOCK_ESuccess: - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 222, - "TS2:read:[%lu], err_code=%d, n_io=%5lu, n_io_done=%5lu", - (unsigned long)i, (int)err_code, - (unsigned long)n_io, (unsigned long)n_io_done); - ASS_RET((n_io_done > 0), 222); - break; - - case eSOCK_EClosed: - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 223, - "TS2:read: connection closed"); - ASSERT( SOCK_Eof(sock) ); - - /* reconnect */ - if ( !lsock ) - return 0; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 223, "TS2:reconnect"); - SOCK_Close(sock); - err_code = LSOCK_Accept(lsock, NULL, &sock); - ASS_RET((err_code == eSOCK_ESuccess), 229); - ASSERT( !SOCK_Eof(sock) ); - /* !!! */ - goto l_reconnect; - - case eSOCK_ETimeout: - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 224, - "TS2:read:[%lu] timeout expired: %5lu sec, %6lu msec", - (unsigned long)i, - (unsigned long)r_to.sec, (unsigned long)r_to.usec); - ASS_RET((n_io_done == 0), 224); - s_DoubleTimeout(&r_to); - err_code = SOCK_SetTimeout(sock, eSOCK_OnRead, &r_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 225); - ASSERT( !SOCK_Eof(sock) ); - break; - - default: - ASS_RET(0, 226); - } - - /* write(just the same) data back to client */ - n_io = n_io_done; - x_buf = buf; - while ( n_io ) { - err_code = SOCK_Write(sock, buf, n_io, &n_io_done); - switch ( err_code ) - { - case eSOCK_ESuccess: - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 231, - "TS2:write:[%lu], err_code=%d, n_io=%5lu, n_io_done=%5lu", - (unsigned long)i, (int)err_code, - (unsigned long)n_io, (unsigned long)n_io_done); - ASS_RET((n_io_done > 0), 231); - break; - case eSOCK_EClosed: - ErrPostEx(SEV_ERROR, SOCK_ERRCODE, 232, - "TS2:write: connection closed"); - return 230; - case eSOCK_ETimeout: - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 233, - "TS2:write:[%lu] timeout expired: %5lu sec, %6lu msec", - (unsigned long)i, - (unsigned long)w_to.sec, (unsigned long)w_to.usec); - ASS_RET((n_io_done == 0), 233); - s_DoubleTimeout(&w_to); - err_code = SOCK_SetTimeout(sock, eSOCK_OnWrite, &w_to, 0, 0); - ASS_RET((err_code == eSOCK_ESuccess), 234); - break; - default: - ASS_RET(0, 235); - } - - n_io -= n_io_done; - x_buf += n_io_done; - } - } - - return 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 Int2 TEST__client(const char* server_host, - Uint2 server_port, - const STimeout* timeout) -{ /* reserved ret.codes [100-109] */ - SOCK sock; - ESOCK_ErrCode err_code; - Int2 ret_code; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 101, - "TEST__client(host = \"%s\", port = %u)", - server_host, (unsigned)server_port); - - /* Connect to server */ - err_code = SOCK_Create(server_host, server_port, timeout, &sock); - ASS_RET((err_code == eSOCK_ESuccess), 100); - - /* Test the simplest randezvous(plain request-reply) - * The two peer functions are: - * "TEST__[client|server]_1(SOCK sock)" - */ - ret_code = TEST__client_1(sock); - ASS_RET((ret_code == 0), 101); - - /* Test a more complex case - * The two peer functions are: - * "TEST__[client|server]_2(SOCK sock)" - */ - ret_code = TEST__client_2(sock); - ASS_RET((ret_code == 0), 102); - - /* Close connection and exit */ - err_code = SOCK_Close(sock); - ASS_RET((err_code == eSOCK_ESuccess || err_code == eSOCK_EClosed), 109); - return 0; -} - - -static Int2 TEST__server(Uint2 port) -{ /* reserved ret.codes [200-209] */ - LSOCK lsock; - ESOCK_ErrCode err_code; - - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 201, - "TEST__server(port = %u)", (unsigned)port); - - /* Create listening socket */ - err_code = LSOCK_Create(port, 1, &lsock); - ASS_RET((err_code == eSOCK_ESuccess), 200); - - /* Accept connections from clients and run test sessions */ - for (;;) - { - Int2 ret_code; - - /* Accept connection */ - SOCK sock; - err_code = LSOCK_Accept(lsock, NULL, &sock); - ASS_RET((err_code == eSOCK_ESuccess), 208); - - /* Test the simplest randezvous(plain request-reply) - * The two peer functions are: - * "TEST__[client|server]_1(SOCK sock)" - */ - ret_code = TEST__server_1(sock); - ASS_RET((ret_code == 0), 201); - - /* Test a more complex case - * The two peer functions are: - * "TEST__[client|server]_2(SOCK sock)" - */ -#ifdef DO_RECONNECT - ret_code = TEST__server_2(sock, lsock); -#else - ret_code = TEST__server_2(sock, 0); -#endif - ASS_RET((ret_code == 0), 202); - - /* Close connection */ - err_code = SOCK_Close(sock); - ASS_RET((err_code == eSOCK_ESuccess || err_code == eSOCK_EClosed), 209); - -#ifdef TEST_SRV1_ONCE - /* finish after the first session */ - break; -#endif - } - - /* Close listening socket */ - err_code = LSOCK_Close(lsock); - ASS_RET((err_code == eSOCK_ESuccess), 204); - return 0; -} - - -/* Main function - * Parse command-line options, initialize and cleanup API internals; - * run client or server test - */ -extern Int2 Main(void) -{ -#define MIN_PORT 5001 - Int4 argc = GetArgc(); - char** argv = GetArgv(); - - ErrSetOpts(ERR_TEE, ERR_LOG_ON); - ErrSetLogLevel(SEV_INFO); - ErrSetMessageLevel(SEV_INFO); - VERIFY ( ErrSetLog("ncbisock.log") ); - - {{ - char local_host[64]; - VERIFY ( GetHostName(local_host, sizeof(local_host)) ); - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 200, - "\nRunning NCBISOCK test on host \"%s\"", local_host); - }} - -#ifdef DO_SERVER - argc = 2; -#endif -#ifdef DO_CLIENT - argc = 3; -#endif - - switch ( argc ) - { - case 2: - { /* Server */ -#ifdef DO_SERVER - short port = 5555; -#else - short port; - if (sscanf(argv[1], "%hd", &port) != 1 || - port < MIN_PORT) - break; -#endif - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 200, - "Starting NCBISOCK server test..."); - VERIFY ( ErrSetLog("ncbisock.srv") ); - - {{ - Int2 ret_code = TEST__server((Uint2)port); - VERIFY ( SOCK_Destroy() == eSOCK_ESuccess ); - return ret_code; - }} - } - - case 3: - case 4: - { /* Client */ - STimeout* timeout = 0; - STimeout x_timeout; -#ifdef DO_CLIENT - char* server_host = "localhost"; - short server_port = 5555; - x_timeout.sec = x_timeout.usec = 999999; -#else - /* host */ - char* server_host = argv[1]; - - /* port */ - short server_port; - if (sscanf(argv[2], "%hd", &server_port) != 1 || - server_port < MIN_PORT) - break; - - /* timeout */ - if (argc == 4) { - double tm_out = atof(argv[3]); - if (tm_out < 0) - break; - x_timeout.sec = (Uint4) tm_out; - x_timeout.usec = (Uint4) ((tm_out - x_timeout.sec) * 1000000); - timeout = &x_timeout; - } else { - x_timeout.sec = x_timeout.usec = 999999; - } -#endif - ErrPostEx(SEV_INFO, SOCK_ERRCODE, 100, - "Starting NCBISOCK client test...\n" - "%s:%d, timeout=%lu.%06lu\n", - server_host, (int)server_port, - (unsigned long)x_timeout.sec, (unsigned long)x_timeout.usec); - VERIFY ( ErrSetLog("ncbisock.cli") ); - - {{ - Int2 ret_code = TEST__client(server_host, (Uint2)server_port, - timeout); - VERIFY ( SOCK_Destroy() == eSOCK_ESuccess ); - return ret_code; - }} - } - } - - /* Bad cmd-line arguments; Usage */ - ErrPostEx(SEV_ERROR, SOCK_ERRCODE, 666, - "Usage:\n" - " Client: %s <srv_host> <port> [conn_timeout]\n" - " Server: %s <port>\n" - " where <port> not less than %hd, and [conn_timeout] is double", - argv[0], argv[0], (short)MIN_PORT); - return 1; -} |