⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 ncbi_connection.c

📁 ncbi源码
💻 C
📖 第 1 页 / 共 2 页
字号:
/* * =========================================================================== * PRODUCTION $Log: ncbi_connection.c,v $ * PRODUCTION Revision 1000.3  2004/06/01 18:44:48  gouriano * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.42 * PRODUCTION * =========================================================================== *//*  $Id: ncbi_connection.c,v 1000.3 2004/06/01 18:44:48 gouriano 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, Anton Lavrentiev * * File Description: *   Generic API to open and handle connection to an abstract service. *   For more detail, see in "ncbi_connection.h". * */#include "ncbi_priv.h"#include <connect/ncbi_buffer.h>#include <connect/ncbi_connection.h>#include <stdlib.h>#include <string.h>/*********************************************************************** *  INTERNAL ***********************************************************************//* Standard logging message */#define CONN_LOG_EX(level, descr, status)                  \  CORE_LOGF(level,                                         \            ("%s (connector \"%s\", error \"%s\")", descr, \             conn->meta.get_type                           \             ? conn->meta.get_type(conn->meta.c_get_type)  \             : "Unknown", IO_StatusStr(status)))#define CONN_LOG(level, descr)  CONN_LOG_EX(level, descr, status)/* Standard macros to verify that the passed connection handle is not NULL */#define CONN_NOT_NULL_EX(func_name, status)                     \  if ( !conn ) {                                                \      CORE_LOG(eLOG_Error, "CONN_" #func_name                   \               "(conn, ...) -- passed NULL connection handle"); \      assert(conn);                                             \      return status;                                            \  }#define CONN_NOT_NULL(func_name)              \  CONN_NOT_NULL_EX(func_name, eIO_InvalidArg)/* Connection state */typedef enum ECONN_StateTag {    eCONN_Unusable = -1,               /* this should be iff !conn->meta.list*/    eCONN_Closed   =  0,    eCONN_Open     =  1} ECONN_State;/* Connection internal data */typedef struct SConnectionTag {    SMetaConnector         meta;       /* VTable of operations and list      */    BUF                    buf;        /* storage for the Peek'd data        */#ifdef IMPLEMENTED__CONN_WaitAsync    SConnectorAsyncHandler async_data; /* info of curr. async event handler  */#endif    ECONN_State            state;      /* connection state                   */    /* "[c|r|w|l]_timeout" is either 0 (kInfiniteTimeout), kDefaultTimeout       (to use connector-specific one), or points to "[cc|rr|ww|ll]_timeout" */    const STimeout*        o_timeout;  /* timeout on open                    */    const STimeout*        r_timeout;  /* timeout on reading                 */    const STimeout*        w_timeout;  /* timeout on writing                 */    const STimeout*        c_timeout;  /* timeout on close                   */    STimeout               oo_timeout; /* storage for "o_timeout"            */    STimeout               rr_timeout; /* storage for "r_timeout"            */    STimeout               ww_timeout; /* storage for "w_timeout"            */    STimeout               cc_timeout; /* storage for "c_timeout"            */    SCONN_Callback         cbs[CONN_N_CALLBACKS];} SConnection;/*********************************************************************** *  EXTERNAL ***********************************************************************/extern EIO_Status CONN_Create(CONNECTOR connector, CONN*     connection){    CONN conn = (SConnection*) calloc(1, sizeof(SConnection));    EIO_Status status = eIO_Unknown;    if ( conn ) {        conn->state     = eCONN_Unusable;        conn->o_timeout = kDefaultTimeout;        conn->r_timeout = kDefaultTimeout;        conn->w_timeout = kDefaultTimeout;        conn->c_timeout = kDefaultTimeout;        if ((status = CONN_ReInit(conn, connector)) != eIO_Success) {            free(conn);            conn = 0;        }    }    *connection = conn;    return status;}extern EIO_Status CONN_ReInit(CONN      conn, CONNECTOR connector){    CONNECTOR  x_conn = 0;    EIO_Status status;    CONN_NOT_NULL(ReInit);    /* check arg */    if (!connector  &&  !conn->meta.list) {        assert(conn->state == eCONN_Unusable);        status = eIO_Unknown;        CONN_LOG(eLOG_Error,                 "[CONN_ReInit]  Cannot re-init empty connection with NULL");        return status;    }    /* reset and close current connector(s), if any */    if ( conn->meta.list ) {#ifdef IMPLEMENTED__CONN_WaitAsync        /* cancel async. i/o event handler */        CONN_WaitAsync(conn, eIO_ReadWrite, 0, 0, 0);#endif        {{ /* erase unread data */            size_t buf_size = BUF_Size(conn->buf);            verify(BUF_Read(conn->buf, 0, buf_size) == buf_size);        }}        /* call current connector's "FLUSH" and "CLOSE" methods */        if (conn->state == eCONN_Open) {            if ( conn->meta.flush ) {                conn->meta.flush(conn->meta.c_flush,                                 conn->c_timeout == kDefaultTimeout ?                                 conn->meta.default_timeout : conn->c_timeout);            }            if ( conn->meta.close ) {                status = conn->meta.close(conn->meta.c_close,                                          conn->c_timeout == kDefaultTimeout                                          ? conn->meta.default_timeout                                          : conn->c_timeout);                if (status != eIO_Success) {                    CONN_LOG(connector ? eLOG_Error : eLOG_Warning,                             "[CONN_ReInit]  Cannot close current connection");                    if (connector)                        return status;                }            }            conn->state = eCONN_Closed;        }        for (x_conn = conn->meta.list;  x_conn;  x_conn = x_conn->next) {            if (x_conn == connector) {                /* Reinit with the same and the only connector - allowed */                if (!x_conn->next  &&  x_conn == conn->meta.list)                    break;                status = eIO_Unknown;                CONN_LOG(eLOG_Error,                         "[CONN_ReInit]  Partial re-init not allowed");                return status;            }        }        if ( !x_conn ) {            /* Entirely new connector - remove the old connector stack first */            METACONN_Remove(&conn->meta, 0);            assert(conn->meta.list == 0);            memset(&conn->meta, 0, sizeof(conn->meta));            conn->state = eCONN_Unusable;        }    }    if (connector  &&  !x_conn) {        assert(conn->state == eCONN_Unusable);        /* Setup the new connector */        if (METACONN_Add(&conn->meta, connector) != eIO_Success)            return eIO_Unknown;        conn->state = eCONN_Closed;    }    assert(conn->state != eCONN_Open);    return eIO_Success;}static EIO_Status s_Open(CONN conn){    EIO_Status status;    assert(conn->state == eCONN_Closed  &&  conn->meta.list != 0);    /* call current connector's "OPEN" method */    status = conn->meta.open        ? conn->meta.open(conn->meta.c_open,                          conn->o_timeout == kDefaultTimeout ?                          conn->meta.default_timeout : conn->o_timeout)        : eIO_NotSupported;    if (status != eIO_Success) {        CONN_LOG(eLOG_Error, "[CONN_Open]  Cannot open connection");        return status;    }    /* success */    conn->state = eCONN_Open;    return status;}extern const char* CONN_GetType(CONN conn){    CONN_NOT_NULL_EX(GetType, 0);    return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||        !conn->meta.get_type ? 0 : conn->meta.get_type(conn->meta.c_get_type);}extern char* CONN_Description(CONN conn){    CONN_NOT_NULL_EX(Description, 0);    return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||        !conn->meta.descr ? 0 : conn->meta.descr(conn->meta.c_descr);}extern EIO_Status CONN_SetTimeout(CONN            conn, EIO_Event       event, const STimeout* new_timeout){    EIO_Status status = eIO_Success;    CONN_NOT_NULL(SetTimeout);    switch (event) {    case eIO_Open:        if (new_timeout  &&  new_timeout != kDefaultTimeout) {            conn->oo_timeout = *new_timeout;            conn->o_timeout  = &conn->oo_timeout;        } else {            conn->o_timeout  = new_timeout;        }        break;    case eIO_Close:        if (new_timeout  &&  new_timeout != kDefaultTimeout) {            conn->cc_timeout = *new_timeout;            conn->c_timeout  = &conn->cc_timeout;        } else {            conn->c_timeout  = new_timeout;        }        break;    case eIO_Read:    case eIO_ReadWrite:        if (new_timeout  &&  new_timeout != kDefaultTimeout) {            conn->rr_timeout = *new_timeout;            conn->r_timeout  = &conn->rr_timeout;        } else {            conn->r_timeout  = new_timeout;        }        if (event != eIO_ReadWrite)            break;        /*FALLTHRU*/    case eIO_Write:        if (new_timeout  &&  new_timeout != kDefaultTimeout) {            conn->ww_timeout = *new_timeout;            conn->w_timeout  = &conn->ww_timeout;        } else {            conn->w_timeout  = new_timeout;        }        break;    default:        status = eIO_InvalidArg;        CONN_LOG(eLOG_Error,                 "[CONN_SetTimeout]  Unknown event to set timeout for");        assert(0);        break;    }    return status;}extern const STimeout* CONN_GetTimeout(CONN      conn, EIO_Event event){    CONN_NOT_NULL_EX(GetTimeout, 0);    switch (event) {    case eIO_Open:        return conn->o_timeout;    case eIO_ReadWrite:        CONN_LOG_EX(eLOG_Warning,                    "[CONN_GetTimeout]  ReadWrite timeout requested",                    eIO_InvalidArg);        /*FALLTHRU*/    case eIO_Read:        return conn->r_timeout;    case eIO_Write:        return conn->w_timeout;    case eIO_Close:        return conn->c_timeout;    default:        CONN_LOG_EX(eLOG_Error,                    "[CONN_GetTimeout]  Unknown event to get timeout for",                    eIO_InvalidArg);        assert(0);        break;    }    return 0;}extern EIO_Status CONN_Wait(CONN            conn, EIO_Event       event, const STimeout* timeout){    EIO_Status status;    CONN_NOT_NULL(Wait);    if (conn->state == eCONN_Unusable               ||        (event != eIO_Read  &&  event != eIO_Write) ||        timeout == kDefaultTimeout)        return eIO_InvalidArg;    /* 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);    /* check if there is a PEEK'ed data in the input */    if (event == eIO_Read && BUF_Size(conn->buf))        return eIO_Success;    /* call current connector's "WAIT" method */    status = conn->meta.wait        ? conn->meta.wait(conn->meta.c_wait, event, timeout)        : eIO_NotSupported;    if (status != eIO_Success) {        if (status != eIO_Timeout)            CONN_LOG(eLOG_Error, "[CONN_Wait]  Error waiting on I/O");        else if (!timeout || timeout->sec || timeout->usec)            CONN_LOG(eLOG_Warning, "[CONN_Wait]  I/O timed out");    }    return status;}static EIO_Status s_CONN_Write(CONN        conn, const void* buf, size_t      size, size_t*     n_written){    EIO_Status status;    assert(*n_written == 0);    /* check if the write method is specified at all */    if ( !conn->meta.write ) {        status = eIO_NotSupported;        CONN_LOG(eLOG_Error, "[CONN_Write]  Unable to write data");        return status;    }    /* call current connector's "WRITE" method */    status = conn->meta.write(conn->meta.c_write, buf, size, n_written,                              conn->w_timeout==kDefaultTimeout ?                              conn->meta.default_timeout :conn->w_timeout);    if (status != eIO_Success) {        if ( *n_written ) {            CONN_LOG(eLOG_Trace, "[CONN_Write]  Write error");            status = eIO_Success;        } else if ( size )            CONN_LOG(eLOG_Error, "[CONN_Write]  Cannot write data");    }    return status;}static EIO_Status s_CONN_WritePersist(CONN        conn, const void* buf, size_t      size, size_t*     n_written){    EIO_Status status;    assert(*n_written == 0);    for (;;) {        size_t x_written = 0;        status = s_CONN_Write(conn, (char*) buf + *n_written,                              size - *n_written, &x_written);        *n_written += x_written;        if (*n_written == size  ||  status != eIO_Success)            break;    }    return status;}extern EIO_Status CONN_Write(CONN            conn, const void*     buf, size_t          size, size_t*         n_written, EIO_WriteMethod how){    EIO_Status status;    if (!n_written)        return eIO_InvalidArg;    *n_written = 0;    if (size && !buf)        return eIO_InvalidArg;    CONN_NOT_NULL(Write);    if (conn->state == eCONN_Unusable)        return eIO_InvalidArg;    /* open connection, if not yet opened */    if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)        return status;    assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);    switch (how) {    case eIO_WritePlain:        return s_CONN_Write(conn, buf, size, n_written);    case eIO_WritePersist:        return s_CONN_WritePersist(conn, buf, size, n_written);    default:        break;    }    return eIO_Unknown;}extern EIO_Status CONN_PushBack(CONN        conn, const void* buf, size_t      size){    CONN_NOT_NULL(PushBack);    if (conn->state != eCONN_Open)        return eIO_InvalidArg;    return BUF_PushBack(&conn->buf, buf, size) ? eIO_Success : eIO_Unknown;}extern EIO_Status CONN_Flush(CONN conn){    EIO_Status status;

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -