ncbi_connection.c
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:30k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_connection.c,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:44:48  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.42
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_connection.c,v 1000.3 2004/06/01 18:44:48 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a "United States Government Work" under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Author:  Denis Vakatov, Anton Lavrentiev
  35.  *
  36.  * File Description:
  37.  *   Generic API to open and handle connection to an abstract service.
  38.  *   For more detail, see in "ncbi_connection.h".
  39.  *
  40.  */
  41. #include "ncbi_priv.h"
  42. #include <connect/ncbi_buffer.h>
  43. #include <connect/ncbi_connection.h>
  44. #include <stdlib.h>
  45. #include <string.h>
  46. /***********************************************************************
  47.  *  INTERNAL
  48.  ***********************************************************************/
  49. /* Standard logging message
  50.  */
  51. #define CONN_LOG_EX(level, descr, status)                  
  52.   CORE_LOGF(level,                                         
  53.             ("%s (connector "%s", error "%s")", descr, 
  54.              conn->meta.get_type                           
  55.              ? conn->meta.get_type(conn->meta.c_get_type)  
  56.              : "Unknown", IO_StatusStr(status)))
  57. #define CONN_LOG(level, descr)  CONN_LOG_EX(level, descr, status)
  58. /* Standard macros to verify that the passed connection handle is not NULL
  59.  */
  60. #define CONN_NOT_NULL_EX(func_name, status)                     
  61.   if ( !conn ) {                                                
  62.       CORE_LOG(eLOG_Error, "CONN_" #func_name                   
  63.                "(conn, ...) -- passed NULL connection handle"); 
  64.       assert(conn);                                             
  65.       return status;                                            
  66.   }
  67. #define CONN_NOT_NULL(func_name)              
  68.   CONN_NOT_NULL_EX(func_name, eIO_InvalidArg)
  69. /* Connection state
  70.  */
  71. typedef enum ECONN_StateTag {
  72.     eCONN_Unusable = -1,               /* this should be iff !conn->meta.list*/
  73.     eCONN_Closed   =  0,
  74.     eCONN_Open     =  1
  75. } ECONN_State;
  76. /* Connection internal data
  77.  */
  78. typedef struct SConnectionTag {
  79.     SMetaConnector         meta;       /* VTable of operations and list      */
  80.     BUF                    buf;        /* storage for the Peek'd data        */
  81. #ifdef IMPLEMENTED__CONN_WaitAsync
  82.     SConnectorAsyncHandler async_data; /* info of curr. async event handler  */
  83. #endif
  84.     ECONN_State            state;      /* connection state                   */
  85.     /* "[c|r|w|l]_timeout" is either 0 (kInfiniteTimeout), kDefaultTimeout
  86.        (to use connector-specific one), or points to "[cc|rr|ww|ll]_timeout" */
  87.     const STimeout*        o_timeout;  /* timeout on open                    */
  88.     const STimeout*        r_timeout;  /* timeout on reading                 */
  89.     const STimeout*        w_timeout;  /* timeout on writing                 */
  90.     const STimeout*        c_timeout;  /* timeout on close                   */
  91.     STimeout               oo_timeout; /* storage for "o_timeout"            */
  92.     STimeout               rr_timeout; /* storage for "r_timeout"            */
  93.     STimeout               ww_timeout; /* storage for "w_timeout"            */
  94.     STimeout               cc_timeout; /* storage for "c_timeout"            */
  95.     SCONN_Callback         cbs[CONN_N_CALLBACKS];
  96. } SConnection;
  97. /***********************************************************************
  98.  *  EXTERNAL
  99.  ***********************************************************************/
  100. extern EIO_Status CONN_Create
  101. (CONNECTOR connector,
  102.  CONN*     connection)
  103. {
  104.     CONN conn = (SConnection*) calloc(1, sizeof(SConnection));
  105.     EIO_Status status = eIO_Unknown;
  106.     if ( conn ) {
  107.         conn->state     = eCONN_Unusable;
  108.         conn->o_timeout = kDefaultTimeout;
  109.         conn->r_timeout = kDefaultTimeout;
  110.         conn->w_timeout = kDefaultTimeout;
  111.         conn->c_timeout = kDefaultTimeout;
  112.         if ((status = CONN_ReInit(conn, connector)) != eIO_Success) {
  113.             free(conn);
  114.             conn = 0;
  115.         }
  116.     }
  117.     *connection = conn;
  118.     return status;
  119. }
  120. extern EIO_Status CONN_ReInit
  121. (CONN      conn,
  122.  CONNECTOR connector)
  123. {
  124.     CONNECTOR  x_conn = 0;
  125.     EIO_Status status;
  126.     CONN_NOT_NULL(ReInit);
  127.     /* check arg */
  128.     if (!connector  &&  !conn->meta.list) {
  129.         assert(conn->state == eCONN_Unusable);
  130.         status = eIO_Unknown;
  131.         CONN_LOG(eLOG_Error,
  132.                  "[CONN_ReInit]  Cannot re-init empty connection with NULL");
  133.         return status;
  134.     }
  135.     /* reset and close current connector(s), if any */
  136.     if ( conn->meta.list ) {
  137. #ifdef IMPLEMENTED__CONN_WaitAsync
  138.         /* cancel async. i/o event handler */
  139.         CONN_WaitAsync(conn, eIO_ReadWrite, 0, 0, 0);
  140. #endif
  141.         {{ /* erase unread data */
  142.             size_t buf_size = BUF_Size(conn->buf);
  143.             verify(BUF_Read(conn->buf, 0, buf_size) == buf_size);
  144.         }}
  145.         /* call current connector's "FLUSH" and "CLOSE" methods */
  146.         if (conn->state == eCONN_Open) {
  147.             if ( conn->meta.flush ) {
  148.                 conn->meta.flush(conn->meta.c_flush,
  149.                                  conn->c_timeout == kDefaultTimeout ?
  150.                                  conn->meta.default_timeout : conn->c_timeout);
  151.             }
  152.             if ( conn->meta.close ) {
  153.                 status = conn->meta.close(conn->meta.c_close,
  154.                                           conn->c_timeout == kDefaultTimeout
  155.                                           ? conn->meta.default_timeout
  156.                                           : conn->c_timeout);
  157.                 if (status != eIO_Success) {
  158.                     CONN_LOG(connector ? eLOG_Error : eLOG_Warning,
  159.                              "[CONN_ReInit]  Cannot close current connection");
  160.                     if (connector)
  161.                         return status;
  162.                 }
  163.             }
  164.             conn->state = eCONN_Closed;
  165.         }
  166.         for (x_conn = conn->meta.list;  x_conn;  x_conn = x_conn->next) {
  167.             if (x_conn == connector) {
  168.                 /* Reinit with the same and the only connector - allowed */
  169.                 if (!x_conn->next  &&  x_conn == conn->meta.list)
  170.                     break;
  171.                 status = eIO_Unknown;
  172.                 CONN_LOG(eLOG_Error,
  173.                          "[CONN_ReInit]  Partial re-init not allowed");
  174.                 return status;
  175.             }
  176.         }
  177.         if ( !x_conn ) {
  178.             /* Entirely new connector - remove the old connector stack first */
  179.             METACONN_Remove(&conn->meta, 0);
  180.             assert(conn->meta.list == 0);
  181.             memset(&conn->meta, 0, sizeof(conn->meta));
  182.             conn->state = eCONN_Unusable;
  183.         }
  184.     }
  185.     if (connector  &&  !x_conn) {
  186.         assert(conn->state == eCONN_Unusable);
  187.         /* Setup the new connector */
  188.         if (METACONN_Add(&conn->meta, connector) != eIO_Success)
  189.             return eIO_Unknown;
  190.         conn->state = eCONN_Closed;
  191.     }
  192.     assert(conn->state != eCONN_Open);
  193.     return eIO_Success;
  194. }
  195. static EIO_Status s_Open
  196. (CONN conn)
  197. {
  198.     EIO_Status status;
  199.     assert(conn->state == eCONN_Closed  &&  conn->meta.list != 0);
  200.     /* call current connector's "OPEN" method */
  201.     status = conn->meta.open
  202.         ? conn->meta.open(conn->meta.c_open,
  203.                           conn->o_timeout == kDefaultTimeout ?
  204.                           conn->meta.default_timeout : conn->o_timeout)
  205.         : eIO_NotSupported;
  206.     if (status != eIO_Success) {
  207.         CONN_LOG(eLOG_Error, "[CONN_Open]  Cannot open connection");
  208.         return status;
  209.     }
  210.     /* success */
  211.     conn->state = eCONN_Open;
  212.     return status;
  213. }
  214. extern const char* CONN_GetType(CONN conn)
  215. {
  216.     CONN_NOT_NULL_EX(GetType, 0);
  217.     return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||
  218.         !conn->meta.get_type ? 0 : conn->meta.get_type(conn->meta.c_get_type);
  219. }
  220. extern char* CONN_Description(CONN conn)
  221. {
  222.     CONN_NOT_NULL_EX(Description, 0);
  223.     return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||
  224.         !conn->meta.descr ? 0 : conn->meta.descr(conn->meta.c_descr);
  225. }
  226. extern EIO_Status CONN_SetTimeout
  227. (CONN            conn,
  228.  EIO_Event       event,
  229.  const STimeout* new_timeout)
  230. {
  231.     EIO_Status status = eIO_Success;
  232.     CONN_NOT_NULL(SetTimeout);
  233.     switch (event) {
  234.     case eIO_Open:
  235.         if (new_timeout  &&  new_timeout != kDefaultTimeout) {
  236.             conn->oo_timeout = *new_timeout;
  237.             conn->o_timeout  = &conn->oo_timeout;
  238.         } else {
  239.             conn->o_timeout  = new_timeout;
  240.         }
  241.         break;
  242.     case eIO_Close:
  243.         if (new_timeout  &&  new_timeout != kDefaultTimeout) {
  244.             conn->cc_timeout = *new_timeout;
  245.             conn->c_timeout  = &conn->cc_timeout;
  246.         } else {
  247.             conn->c_timeout  = new_timeout;
  248.         }
  249.         break;
  250.     case eIO_Read:
  251.     case eIO_ReadWrite:
  252.         if (new_timeout  &&  new_timeout != kDefaultTimeout) {
  253.             conn->rr_timeout = *new_timeout;
  254.             conn->r_timeout  = &conn->rr_timeout;
  255.         } else {
  256.             conn->r_timeout  = new_timeout;
  257.         }
  258.         if (event != eIO_ReadWrite)
  259.             break;
  260.         /*FALLTHRU*/
  261.     case eIO_Write:
  262.         if (new_timeout  &&  new_timeout != kDefaultTimeout) {
  263.             conn->ww_timeout = *new_timeout;
  264.             conn->w_timeout  = &conn->ww_timeout;
  265.         } else {
  266.             conn->w_timeout  = new_timeout;
  267.         }
  268.         break;
  269.     default:
  270.         status = eIO_InvalidArg;
  271.         CONN_LOG(eLOG_Error,
  272.                  "[CONN_SetTimeout]  Unknown event to set timeout for");
  273.         assert(0);
  274.         break;
  275.     }
  276.     return status;
  277. }
  278. extern const STimeout* CONN_GetTimeout
  279. (CONN      conn,
  280.  EIO_Event event)
  281. {
  282.     CONN_NOT_NULL_EX(GetTimeout, 0);
  283.     switch (event) {
  284.     case eIO_Open:
  285.         return conn->o_timeout;
  286.     case eIO_ReadWrite:
  287.         CONN_LOG_EX(eLOG_Warning,
  288.                     "[CONN_GetTimeout]  ReadWrite timeout requested",
  289.                     eIO_InvalidArg);
  290.         /*FALLTHRU*/
  291.     case eIO_Read:
  292.         return conn->r_timeout;
  293.     case eIO_Write:
  294.         return conn->w_timeout;
  295.     case eIO_Close:
  296.         return conn->c_timeout;
  297.     default:
  298.         CONN_LOG_EX(eLOG_Error,
  299.                     "[CONN_GetTimeout]  Unknown event to get timeout for",
  300.                     eIO_InvalidArg);
  301.         assert(0);
  302.         break;
  303.     }
  304.     return 0;
  305. }
  306. extern EIO_Status CONN_Wait
  307. (CONN            conn,
  308.  EIO_Event       event,
  309.  const STimeout* timeout)
  310. {
  311.     EIO_Status status;
  312.     CONN_NOT_NULL(Wait);
  313.     if (conn->state == eCONN_Unusable               ||
  314.         (event != eIO_Read  &&  event != eIO_Write) ||
  315.         timeout == kDefaultTimeout)
  316.         return eIO_InvalidArg;
  317.     /* perform open, if not opened yet */
  318.     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
  319.         return status;
  320.     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
  321.     /* check if there is a PEEK'ed data in the input */
  322.     if (event == eIO_Read && BUF_Size(conn->buf))
  323.         return eIO_Success;
  324.     /* call current connector's "WAIT" method */
  325.     status = conn->meta.wait
  326.         ? conn->meta.wait(conn->meta.c_wait, event, timeout)
  327.         : eIO_NotSupported;
  328.     if (status != eIO_Success) {
  329.         if (status != eIO_Timeout)
  330.             CONN_LOG(eLOG_Error, "[CONN_Wait]  Error waiting on I/O");
  331.         else if (!timeout || timeout->sec || timeout->usec)
  332.             CONN_LOG(eLOG_Warning, "[CONN_Wait]  I/O timed out");
  333.     }
  334.     return status;
  335. }
  336. static EIO_Status s_CONN_Write
  337. (CONN        conn,
  338.  const void* buf,
  339.  size_t      size,
  340.  size_t*     n_written)
  341. {
  342.     EIO_Status status;
  343.     assert(*n_written == 0);
  344.     /* check if the write method is specified at all */
  345.     if ( !conn->meta.write ) {
  346.         status = eIO_NotSupported;
  347.         CONN_LOG(eLOG_Error, "[CONN_Write]  Unable to write data");
  348.         return status;
  349.     }
  350.     /* call current connector's "WRITE" method */
  351.     status = conn->meta.write(conn->meta.c_write, buf, size, n_written,
  352.                               conn->w_timeout==kDefaultTimeout ?
  353.                               conn->meta.default_timeout :conn->w_timeout);
  354.     if (status != eIO_Success) {
  355.         if ( *n_written ) {
  356.             CONN_LOG(eLOG_Trace, "[CONN_Write]  Write error");
  357.             status = eIO_Success;
  358.         } else if ( size )
  359.             CONN_LOG(eLOG_Error, "[CONN_Write]  Cannot write data");
  360.     }
  361.     return status;
  362. }
  363. static EIO_Status s_CONN_WritePersist
  364. (CONN        conn,
  365.  const void* buf,
  366.  size_t      size,
  367.  size_t*     n_written)
  368. {
  369.     EIO_Status status;
  370.     assert(*n_written == 0);
  371.     for (;;) {
  372.         size_t x_written = 0;
  373.         status = s_CONN_Write(conn, (char*) buf + *n_written,
  374.                               size - *n_written, &x_written);
  375.         *n_written += x_written;
  376.         if (*n_written == size  ||  status != eIO_Success)
  377.             break;
  378.     }
  379.     return status;
  380. }
  381. extern EIO_Status CONN_Write
  382. (CONN            conn,
  383.  const void*     buf,
  384.  size_t          size,
  385.  size_t*         n_written,
  386.  EIO_WriteMethod how)
  387. {
  388.     EIO_Status status;
  389.     if (!n_written)
  390.         return eIO_InvalidArg;
  391.     *n_written = 0;
  392.     if (size && !buf)
  393.         return eIO_InvalidArg;
  394.     CONN_NOT_NULL(Write);
  395.     if (conn->state == eCONN_Unusable)
  396.         return eIO_InvalidArg;
  397.     /* open connection, if not yet opened */
  398.     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
  399.         return status;
  400.     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
  401.     switch (how) {
  402.     case eIO_WritePlain:
  403.         return s_CONN_Write(conn, buf, size, n_written);
  404.     case eIO_WritePersist:
  405.         return s_CONN_WritePersist(conn, buf, size, n_written);
  406.     default:
  407.         break;
  408.     }
  409.     return eIO_Unknown;
  410. }
  411. extern EIO_Status CONN_PushBack
  412. (CONN        conn,
  413.  const void* buf,
  414.  size_t      size)
  415. {
  416.     CONN_NOT_NULL(PushBack);
  417.     if (conn->state != eCONN_Open)
  418.         return eIO_InvalidArg;
  419.     return BUF_PushBack(&conn->buf, buf, size) ? eIO_Success : eIO_Unknown;
  420. }
  421. extern EIO_Status CONN_Flush
  422. (CONN conn)
  423. {
  424.     EIO_Status status;
  425.     CONN_NOT_NULL(Flush);
  426.     if (conn->state == eCONN_Unusable)
  427.         return eIO_InvalidArg;
  428.     /* perform open, if not opened yet */
  429.     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
  430.         return status;
  431.     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
  432.     /* call current connector's "FLUSH" method */
  433.     if ( !conn->meta.flush )
  434.         return eIO_Success;
  435.     status = conn->meta.flush(conn->meta.c_flush,
  436.                               conn->w_timeout == kDefaultTimeout ?
  437.                               conn->meta.default_timeout : conn->w_timeout);
  438.     if (status != eIO_Success)
  439.         CONN_LOG(eLOG_Warning, "[CONN_Flush]  Cannot flush data");
  440.     return status;
  441. }
  442. /* Read or peek data from the input queue, see CONN_Read()
  443.  */
  444. static EIO_Status s_CONN_Read
  445. (CONN        conn,
  446.  void*       buf,
  447.  size_t      size,
  448.  size_t*     n_read,
  449.  int/*bool*/ peek)
  450. {
  451.     EIO_Status status;
  452.     assert(*n_read == 0);
  453.     /* check if the read method is specified at all */
  454.     if ( !conn->meta.read ) {
  455.         status = eIO_NotSupported;
  456.         CONN_LOG(eLOG_Error, "[CONN_Read]  Unable to read data");
  457.         return status;
  458.     }
  459.     /* read data from the internal peek buffer, if any */
  460.     *n_read = peek
  461.         ? BUF_Peek(conn->buf, buf, size) : BUF_Read(conn->buf, buf, size);
  462.     if (*n_read == size)
  463.         return eIO_Success;
  464.     buf = (char*) buf + *n_read;
  465.     /* read data from the connection */
  466.     {{
  467.         size_t x_read = 0;
  468.         /* call current connector's "READ" method */
  469.         status = conn->meta.read(conn->meta.c_read, buf, size- *n_read,&x_read,
  470.                                  conn->r_timeout == kDefaultTimeout ?
  471.                                  conn->meta.default_timeout : conn->r_timeout);
  472.         *n_read += x_read;
  473.         if (peek  &&  x_read)  /* save data in the internal peek buffer */
  474.             verify(BUF_Write(&conn->buf, buf, x_read));
  475.     }}
  476.     if (status != eIO_Success) {
  477.         if ( *n_read ) {
  478.             CONN_LOG(eLOG_Trace, "[CONN_Read]  Read error");
  479.             status = eIO_Success;
  480.         } else if ( size ) {
  481.             CONN_LOG(status == eIO_Closed  ? eLOG_Trace   :
  482.                      status == eIO_Timeout ? eLOG_Warning : eLOG_Error,
  483.                      "[CONN_Read]  Cannot read data");
  484.         }
  485.     }
  486.     return status;
  487. }
  488. /* Persistently read data from the input queue, see CONN_Read()
  489.  */
  490. static EIO_Status s_CONN_ReadPersist
  491. (CONN    conn,
  492.  void*   buf,
  493.  size_t  size,
  494.  size_t* n_read)
  495. {
  496.     EIO_Status status;
  497.     assert(*n_read == 0);
  498.     for (;;) {
  499.         size_t x_read = 0;
  500.         status = s_CONN_Read(conn, (char*) buf + *n_read,
  501.                              size - *n_read, &x_read, 0/*no peek*/);
  502.         *n_read += x_read;
  503.         if (*n_read == size  ||  status != eIO_Success)
  504.             break;
  505.         /* flush the unwritten output data (if any) */
  506.         if ( conn->meta.flush ) {
  507.             conn->meta.flush(conn->meta.c_flush,
  508.                              conn->r_timeout == kDefaultTimeout ?
  509.                              conn->meta.default_timeout : conn->r_timeout);
  510.         }
  511.     }
  512.     return status;
  513. }
  514. extern EIO_Status CONN_Read
  515. (CONN           conn,
  516.  void*          buf,
  517.  size_t         size,
  518.  size_t*        n_read,
  519.  EIO_ReadMethod how)
  520. {
  521.     EIO_Status status;
  522.     if (!n_read)
  523.         return eIO_InvalidArg;
  524.     *n_read = 0;
  525.     if (size && !buf)
  526.         return eIO_InvalidArg;
  527.     CONN_NOT_NULL(Read);
  528.     if (conn->state == eCONN_Unusable)
  529.         return eIO_InvalidArg;
  530.     /* perform open, if not opened yet */
  531.     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
  532.         return status;
  533.     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
  534.     /* flush the unwritten output data (if any) */
  535.     if ( conn->meta.flush ) {
  536.         conn->meta.flush(conn->meta.c_flush,
  537.                          conn->r_timeout == kDefaultTimeout ?
  538.                          conn->meta.default_timeout : conn->r_timeout);
  539.     }
  540.     /* now do read */
  541.     switch (how) {
  542.     case eIO_ReadPlain:
  543.         return s_CONN_Read(conn, buf, size, n_read, 0/*no peek*/);
  544.     case eIO_ReadPeek:
  545.         return s_CONN_Read(conn, buf, size, n_read, 1/*peek*/);
  546.     case eIO_ReadPersist:
  547.         return s_CONN_ReadPersist(conn, buf, size, n_read);
  548.     default:
  549.         break;
  550.     }
  551.     return eIO_Unknown;
  552. }
  553. extern EIO_Status CONN_ReadLine
  554. (CONN    conn,
  555.  char*   line,
  556.  size_t  size,
  557.  size_t* n_read
  558.  )
  559. {
  560.     EIO_Status status = eIO_Success;
  561.     char       w[1024];
  562.     size_t     len;
  563.     if (!n_read)
  564.         return eIO_InvalidArg;
  565.     *n_read = 0;
  566.     if (size && !line)
  567.         return eIO_InvalidArg;
  568.     CONN_NOT_NULL(ReadLine);
  569.     /* perform open, if not opened yet */
  570.     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
  571.         return status;
  572.     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
  573.     /* flush the unwritten output data (if any) */
  574.     if ( conn->meta.flush ) {
  575.         conn->meta.flush(conn->meta.c_flush,
  576.                          conn->r_timeout == kDefaultTimeout ?
  577.                          conn->meta.default_timeout : conn->r_timeout);
  578.     }
  579.     len = 0;
  580.     while (len < size) {
  581.         size_t i;
  582.         size_t x_read = 0;
  583.         size_t x_size = BUF_Size(conn->buf);
  584.         char*  buf = size - len < sizeof(w) ? w : &line[len];
  585.         if (x_size == 0 || x_size > sizeof(w))
  586.             x_size = sizeof(w);
  587.         status = s_CONN_Read(conn, buf, x_size, &x_read, 0);
  588.         for (i = 0; i < x_read; i++) {
  589.             if (buf == w)
  590.                 line[len] = buf[i];
  591.             if (buf[i] == 'n') {
  592.                 line[len] = '';
  593.                 i++;
  594.                 break;
  595.             } else if (++len >= size) {
  596.                 i++;
  597.                 break;
  598.             }
  599.         }
  600.         if (i < x_read) {
  601.             if (!BUF_PushBack(&conn->buf, &buf[i], x_read - i))
  602.                 status = eIO_Unknown;
  603.             break;
  604.         } else if (status != eIO_Success) {
  605.             if (len < size)
  606.                 line[len] = '';
  607.             break;
  608.         }
  609.     }
  610.     *n_read = len;
  611.     return status;
  612. }
  613. extern EIO_Status CONN_Status(CONN conn, EIO_Event dir)
  614. {
  615.     CONN_NOT_NULL(Status);
  616.     if (conn->state == eCONN_Unusable  ||  !conn->meta.list)
  617.         return eIO_Unknown;
  618.     if (dir != eIO_Read  &&  dir != eIO_Write)
  619.         return eIO_InvalidArg;
  620.     if (conn->state == eCONN_Closed)
  621.         return eIO_Closed;
  622.     if ( !conn->meta.status )
  623.         return eIO_NotSupported;
  624.     return conn->meta.status(conn->meta.c_status, dir);
  625. }
  626. extern EIO_Status CONN_Close(CONN conn)
  627. {
  628.     FConnCallback func = 0;
  629.     void*         data = 0;
  630.     CONN_NOT_NULL(Close);
  631.     if (conn->state != eCONN_Unusable) {
  632.         func = conn->cbs[eCONN_OnClose].func;
  633.         data = conn->cbs[eCONN_OnClose].data;
  634.     }
  635.     /* allow close CB only once */
  636.     memset(&conn->cbs[eCONN_OnClose], 0, sizeof(conn->cbs[eCONN_OnClose]));
  637.     /* call it! */
  638.     if ( func )
  639.         (*func)(conn, eCONN_OnClose, data);
  640.     /* now close the connection - this also makes it "eCONN_Unusable" */
  641.     if ( conn->meta.list )
  642.         CONN_ReInit(conn, 0);
  643.     BUF_Destroy(conn->buf);
  644.     conn->buf = 0;
  645.     free(conn);
  646.     return eIO_Success;
  647. }
  648. extern EIO_Status CONN_SetCallback
  649. (CONN                  conn,
  650.  ECONN_Callback        type,
  651.  const SCONN_Callback* new_cb,
  652.  SCONN_Callback*       old_cb)
  653. {
  654.     int i = (int) type;
  655.     if (i >= CONN_N_CALLBACKS)
  656.         return eIO_InvalidArg;
  657.     CONN_NOT_NULL(SetCallback);
  658.     if ( old_cb )
  659.         *old_cb = conn->cbs[i];
  660.     if ( new_cb )
  661.         conn->cbs[i] = *new_cb;
  662.     return eIO_Success;
  663. }
  664. #ifdef IMPLEMENTED__CONN_WaitAsync
  665. /* Internal handler(wrapper for the user-provided handler) for CONN_WaitAsync()
  666.  */
  667. static void s_ConnectorAsyncHandler
  668. (SConnectorAsyncHandler* data,
  669.  EIO_Event               event,
  670.  EIO_Status              status)
  671. {
  672.     /* handle the async. event */
  673.     data->handler(data->conn, event, status, data->data);
  674.     /* reset */
  675.     verify(CONN_WaitAsync(data->conn, eIO_ReadWrite, 0, 0, 0) == eIO_Success);
  676. }
  677. extern EIO_Status CONN_WaitAsync
  678. (CONN              conn,
  679.  EIO_Event         event,
  680.  FConnAsyncHandler handler,
  681.  void*             data,
  682.  FConnAsyncCleanup cleanup)
  683. {
  684.     EIO_Status status;
  685.     CONNECTOR  x_connector = conn->connector;
  686.     SConnectorAsyncHandler* x_data = &conn->async_data;
  687.     CONN_NOT_NULL(WaitAsync);
  688.     /* perform connect, if not connected yet */
  689.     if (!conn->connected  &&  (status = s_Connect(conn)) != eIO_Success)
  690.         return status;
  691.     /* reset previous handler, cleanup its data */
  692.     /* (call current connector's "WAIT_ASYNC" method with NULLs) */
  693.     status = x_connector->vtable.wait_async ?
  694.         x_connector->vtable.wait_async(x_connector->handle, 0, 0) :
  695.         eIO_NotSupported;
  696.     if (status != eIO_Success) {
  697.         CONN_LOG(eLOG_Error, "[CONN_WaitAsync]  Cannot reset the handler");
  698.         return status;
  699.     }
  700.     if ( x_data->cleanup )
  701.         x_data->cleanup(x_data->data);
  702.     memset(x_data, '', sizeof(*x_data));
  703.     /* set new handler, if specified */
  704.     /* (call current connector's "WAIT_ASYNC" method with new handler/data) */
  705.     if ( !handler )
  706.         return eIO_Success;
  707.     x_data->conn       = conn;
  708.     x_data->wait_event = event;
  709.     x_data->handler    = handler;
  710.     x_data->data       = data;
  711.     x_data->cleanup    = cleanup;
  712.     status = x_connector->vtable.wait_async(x_connector->handle,
  713.                                             s_ConnectorAsyncHandler, x_data);
  714.     if (status != eIO_Success) {
  715.         CONN_LOG(eLOG_Error, "[CONN_WaitAsync]  Cannot set new handler");
  716.     }
  717.     return status;
  718. }
  719. #endif /* IMPLEMENTED__CONN_WaitAsync */
  720. /*
  721.  * --------------------------------------------------------------------------
  722.  * $Log: ncbi_connection.c,v $
  723.  * Revision 1000.3  2004/06/01 18:44:48  gouriano
  724.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.42
  725.  *
  726.  * Revision 6.42  2004/05/26 16:00:06  lavr
  727.  * Minor status fixes in CONN_SetTimeout() and CONN_ReadLine()
  728.  *
  729.  * Revision 6.41  2004/05/24 20:19:19  lavr
  730.  * Fix eIO_InvalidArg conditions (size and no buffer)
  731.  *
  732.  * Revision 6.40  2004/05/24 19:54:59  lavr
  733.  * +CONN_ReadLine()
  734.  *
  735.  * Revision 6.39  2004/03/23 02:27:37  lavr
  736.  * Code formatting
  737.  *
  738.  * Revision 6.38  2004/02/23 15:23:39  lavr
  739.  * New (last) parameter "how" added in CONN_Write() API call
  740.  *
  741.  * Revision 6.37  2003/08/25 14:40:53  lavr
  742.  * Employ new k..Timeout constants
  743.  *
  744.  * Revision 6.36  2003/05/31 05:18:26  lavr
  745.  * Optimize on calling flush; do not require to have flush method
  746.  *
  747.  * Revision 6.35  2003/05/21 17:53:06  lavr
  748.  * Better check for {0,0} timeout in CONN_Read()
  749.  *
  750.  * Revision 6.34  2003/05/20 21:21:45  lavr
  751.  * CONN_Write(): log with different log levels on write errors
  752.  *
  753.  * Revision 6.33  2003/05/19 16:43:40  lavr
  754.  * Bugfix in CONN_SetTimeout();  better close callback sequence
  755.  *
  756.  * Revision 6.32  2003/05/14 03:51:16  lavr
  757.  * +CONN_Description()
  758.  *
  759.  * Revision 6.31  2003/05/12 18:33:21  lavr
  760.  * Names of timeout variables uniformed
  761.  *
  762.  * Revision 6.30  2003/01/28 15:16:37  lavr
  763.  * Fix "NULL" message not to contain double quotes in call names
  764.  *
  765.  * Revision 6.29  2003/01/17 19:44:46  lavr
  766.  * Reduce dependencies
  767.  *
  768.  * Revision 6.28  2003/01/15 19:51:17  lavr
  769.  * +CONN_PushBack()
  770.  *
  771.  * Revision 6.27  2002/09/19 19:43:46  lavr
  772.  * Add more assert()'s and do not rely on CONN_Flush() to open in CONN_Read()
  773.  *
  774.  * Revision 6.26  2002/09/06 15:43:20  lavr
  775.  * Bug fixes of late assignments in Read and Write; Flush changed to open
  776.  * connection if not yet open; more error logging
  777.  *
  778.  * Revision 6.25  2002/08/07 16:32:32  lavr
  779.  * Changed EIO_ReadMethod enums accordingly; log moved to end
  780.  *
  781.  * Revision 6.24  2002/04/26 16:30:26  lavr
  782.  * Checks for kDefaultTimeout and use of default_timeout of meta-connector
  783.  *
  784.  * Revision 6.23  2002/04/24 21:18:04  lavr
  785.  * Beautifying: pup open check before buffer check in CONN_Wait()
  786.  *
  787.  * Revision 6.22  2002/04/22 19:30:01  lavr
  788.  * Do not put trace message on polling wait (tmo={0,0})
  789.  * More effective CONN_Read w/o repeatitive checkings for eIO_ReadPersist
  790.  *
  791.  * Revision 6.21  2002/03/22 22:17:01  lavr
  792.  * Better check when formally timed out but technically polled in CONN_Wait()
  793.  *
  794.  * Revision 6.20  2002/02/05 22:04:12  lavr
  795.  * Included header files rearranged
  796.  *
  797.  * Revision 6.19  2002/01/30 20:10:56  lavr
  798.  * Remove *n_read = 0 assignment in s_CONN_Read; replace it with assert()
  799.  *
  800.  * Revision 6.18  2001/08/20 20:13:15  vakatov
  801.  * CONN_ReInit() -- Check connection handle for NULL (it was missed in R6.17)
  802.  *
  803.  * Revision 6.17  2001/08/20 20:00:43  vakatov
  804.  * CONN_SetTimeout() to return "EIO_Status".
  805.  * CONN_***() -- Check connection handle for NULL.
  806.  *
  807.  * Revision 6.16  2001/07/10 15:08:35  lavr
  808.  * Edit for style
  809.  *
  810.  * Revision 6.15  2001/06/29 21:06:46  lavr
  811.  * BUGFIX: CONN_LOG now checks for non-NULL get_type virtual function
  812.  *
  813.  * Revision 6.14  2001/06/28 22:00:48  lavr
  814.  * Added function: CONN_SetCallback
  815.  * Added callback: eCONN_OnClose
  816.  *
  817.  * Revision 6.13  2001/06/07 17:54:36  lavr
  818.  * Modified exit branch in s_CONN_Read()
  819.  *
  820.  * Revision 6.12  2001/05/30 19:42:44  vakatov
  821.  * s_CONN_Read() -- do not issue warning if requested zero bytes
  822.  * (by A.Lavrentiev)
  823.  *
  824.  * Revision 6.11  2001/04/24 21:29:04  lavr
  825.  * kDefaultTimeout is used everywhere when timeout is not set explicitly
  826.  *
  827.  * Revision 6.10  2001/02/26 22:52:44  kans
  828.  * Initialize x_read in s_CONN_Read
  829.  *
  830.  * Revision 6.9  2001/02/26 16:32:01  kans
  831.  * Including string.h instead of cstring
  832.  *
  833.  * Revision 6.8  2001/02/25 21:41:50  kans
  834.  * Include <cstring> on Mac to get memset
  835.  *
  836.  * Revision 6.7  2001/02/09 17:34:18  lavr
  837.  * CONN_GetType added; severities of some messages changed
  838.  *
  839.  * Revision 6.6  2001/01/25 16:55:48  lavr
  840.  * CONN_ReInit bugs fixed
  841.  *
  842.  * Revision 6.5  2001/01/23 23:10:53  lavr
  843.  * Typo corrected in description of connection structure
  844.  *
  845.  * Revision 6.4  2001/01/12 23:51:38  lavr
  846.  * Message logging modified for use LOG facility only
  847.  *
  848.  * Revision 6.3  2001/01/03 22:29:59  lavr
  849.  * CONN_Status implemented
  850.  *
  851.  * Revision 6.2  2000/12/29 17:52:59  lavr
  852.  * Adapted to use new connector structure; modified to have
  853.  * Internal tri-state {Unusable | Open | Closed }.
  854.  *
  855.  * Revision 6.1  2000/03/24 22:53:34  vakatov
  856.  * Initial revision
  857.  *
  858.  * Revision 6.4  1999/11/01 16:14:23  vakatov
  859.  * s_CONN_Read() -- milder error levels when hitting EOF
  860.  *
  861.  * Revision 6.3  1999/04/05 15:32:53  vakatov
  862.  * CONN_Wait():  be more mild and discrete about the posted error severity
  863.  *
  864.  * Revision 6.1  1999/04/01 21:48:09  vakatov
  865.  * Fixed for the change in spec:  "n_written/n_read" args in
  866.  * CONN_Write/Read to be non-NULL and "*n_written / *n_read" := 0
  867.  *
  868.  * Revision 6.0  1999/03/25 23:04:57  vakatov
  869.  * Initial revision
  870.  *
  871.  * ==========================================================================
  872.  */