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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_socket_cxx.cpp,v $
  4.  * PRODUCTION Revision 1000.3  2004/06/01 18:45:29  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.24
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_socket_cxx.cpp,v 1000.3 2004/06/01 18:45:29 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:  Anton Lavrentiev
  35.  *
  36.  * File Description:
  37.  *   C++ wrappers for the C "SOCK" API (UNIX, MS-Win, MacOS, Darwin)
  38.  *   Implementation of out-of-line methods
  39.  *
  40.  */
  41. #include <ncbi_pch.hpp>
  42. #include <connect/ncbi_socket.hpp>
  43. #include <limits.h>                     // for PATH_MAX
  44. #if defined(NCBI_OS_MSWIN) && !defined(PATH_MAX)
  45. #  define PATH_MAX 512                  // will actually use less than 32 chars
  46. #endif
  47. BEGIN_NCBI_SCOPE
  48. /////////////////////////////////////////////////////////////////////////////
  49. //  CSocket::
  50. //
  51. CSocket::CSocket(void)
  52.     : m_Socket(0),
  53.       m_IsOwned(eTakeOwnership),
  54.       o_timeout(0), r_timeout(0), w_timeout(0), c_timeout(0)
  55. {
  56.     return;
  57. }
  58. CSocket::CSocket(const string&   host,
  59.                  unsigned short  port,
  60.                  const STimeout* timeout,
  61.                  ESwitch         log)
  62.     : m_IsOwned(eTakeOwnership),
  63.       r_timeout(0), w_timeout(0), c_timeout(0)
  64. {
  65.     const char* x_host = host.c_str();
  66.     if (timeout && timeout != kDefaultTimeout) {
  67.         oo_timeout = *timeout;
  68.         o_timeout  = &oo_timeout;
  69.     } else
  70.         o_timeout  = 0;
  71.     if (SOCK_CreateEx(x_host, port, o_timeout, &m_Socket, 0, 0, log)
  72.         != eIO_Success) {
  73.         m_Socket = 0;
  74.     }
  75. }
  76. CSocket::~CSocket(void)
  77. {
  78.     if (m_Socket  &&  m_IsOwned != eNoOwnership)
  79.         SOCK_Close(m_Socket);
  80. }
  81. void CSocket::Reset(SOCK sock, EOwnership if_to_own, ECopyTimeout whence)
  82. {
  83.     if (m_Socket  &&  m_IsOwned != eNoOwnership)
  84.         SOCK_Close(m_Socket);
  85.     m_Socket  = sock;
  86.     m_IsOwned = if_to_own;
  87.     if ( sock ) {
  88.         if (whence == eCopyTimeoutsFromSOCK) {
  89.             const STimeout* timeout;
  90.             timeout = SOCK_GetTimeout(sock, eIO_Read);
  91.             if ( timeout ) {
  92.                 rr_timeout = *timeout;
  93.                 r_timeout  = &rr_timeout;
  94.             } else
  95.                 r_timeout  = 0;
  96.             timeout = SOCK_GetTimeout(sock, eIO_Write);
  97.             if ( timeout ) {
  98.                 ww_timeout = *timeout;
  99.                 w_timeout  = &ww_timeout;
  100.             } else
  101.                 w_timeout  = 0;
  102.             timeout = SOCK_GetTimeout(sock, eIO_Close);
  103.             if ( timeout ) {
  104.                 cc_timeout = *timeout;
  105.                 c_timeout  = &cc_timeout;
  106.             } else
  107.                 c_timeout  = 0;
  108.         } else {
  109.             SOCK_SetTimeout(sock, eIO_Read,  r_timeout);
  110.             SOCK_SetTimeout(sock, eIO_Write, w_timeout);
  111.             SOCK_SetTimeout(sock, eIO_Close, c_timeout);
  112.         }
  113.     }
  114. }
  115. EIO_Status CSocket::Connect(const string&   host,
  116.                             unsigned short  port,
  117.                             const STimeout* timeout,
  118.                             ESwitch         log)
  119. {
  120.     if ( m_Socket ) {
  121.         if (SOCK_Status(m_Socket, eIO_Open) != eIO_Closed)
  122.             return eIO_Unknown;
  123.         SOCK_Close(m_Socket);
  124.     }
  125.     const char* x_host = host.c_str();
  126.     if (timeout != kDefaultTimeout) {
  127.         if ( timeout ) {
  128.             oo_timeout = *timeout;
  129.             o_timeout  = &oo_timeout;
  130.         } else
  131.             o_timeout = 0;
  132.     }
  133.     EIO_Status status = SOCK_CreateEx(x_host, port, o_timeout,
  134.                                       &m_Socket, 0, 0, log);
  135.     if (status == eIO_Success) {
  136.         SOCK_SetTimeout(m_Socket, eIO_Read,  r_timeout);
  137.         SOCK_SetTimeout(m_Socket, eIO_Write, w_timeout);
  138.         SOCK_SetTimeout(m_Socket, eIO_Close, c_timeout);        
  139.     } else
  140.         m_Socket = 0;
  141.     return status;
  142. }
  143. EIO_Status CSocket::Reconnect(const STimeout* timeout)
  144. {
  145.     if (timeout != kDefaultTimeout) {
  146.         if ( timeout ) {
  147.             oo_timeout = *timeout;
  148.             o_timeout  = &oo_timeout;
  149.         } else
  150.             o_timeout = 0;
  151.     }
  152.     return m_Socket ? SOCK_Reconnect(m_Socket, 0, 0, o_timeout) : eIO_Closed;
  153. }
  154. EIO_Status CSocket::Close(void)
  155. {
  156.     if ( !m_Socket )
  157.         return eIO_Success;
  158.     EIO_Status status = m_IsOwned != eNoOwnership
  159.         ? SOCK_CloseEx(m_Socket, 0) : eIO_Success;
  160.     return status;
  161. }
  162. EIO_Status CSocket::SetTimeout(EIO_Event event, const STimeout* timeout)
  163. {
  164.     if (timeout == kDefaultTimeout)
  165.         return eIO_Success;
  166.     switch (event) {
  167.     case eIO_Open:
  168.         if ( timeout ) {
  169.             oo_timeout = *timeout;
  170.             o_timeout  = &oo_timeout;
  171.         } else
  172.             o_timeout  = 0;
  173.         break;
  174.     case eIO_Read:
  175.         if ( timeout ) {
  176.             rr_timeout = *timeout;
  177.             r_timeout  = &rr_timeout;
  178.         } else
  179.             r_timeout  = 0;
  180.         break;
  181.     case eIO_Write:
  182.         if ( timeout ) {
  183.             ww_timeout = *timeout;
  184.             w_timeout  = &ww_timeout;
  185.         } else
  186.             w_timeout  = 0;
  187.         break;
  188.     case eIO_ReadWrite:
  189.         if ( timeout ) {
  190.             rr_timeout = *timeout;
  191.             ww_timeout = *timeout;
  192.             r_timeout  = &rr_timeout;
  193.             w_timeout  = &ww_timeout;
  194.         } else {
  195.             r_timeout  = 0;
  196.             w_timeout  = 0;
  197.         }
  198.         break;
  199.     case eIO_Close:
  200.         if ( timeout ) {
  201.             cc_timeout = *timeout;
  202.             c_timeout  = &cc_timeout;
  203.         } else
  204.             c_timeout  = 0;
  205.         break;
  206.     default:
  207.         return eIO_InvalidArg;
  208.     }
  209.     return m_Socket ? SOCK_SetTimeout(m_Socket, event, timeout) : eIO_Success;
  210. }
  211. const STimeout* CSocket::GetTimeout(EIO_Event event) const
  212. {
  213.     switch (event) {
  214.     case eIO_Open:
  215.         return o_timeout;
  216.     case eIO_Read:
  217.         return r_timeout;
  218.     case eIO_Write:
  219.         return w_timeout;
  220.     case eIO_ReadWrite:
  221.         if ( !r_timeout )
  222.             return w_timeout;
  223.         if ( !w_timeout )
  224.             return r_timeout;
  225.         return ((unsigned long) r_timeout->sec*1000000 + r_timeout->usec >
  226.                 (unsigned long) w_timeout->sec*1000000 + w_timeout->usec)
  227.             ? w_timeout : r_timeout;
  228.     case eIO_Close:
  229.         return c_timeout;
  230.     default:
  231.         break;
  232.     }
  233.     return kDefaultTimeout;
  234. }
  235. EIO_Status CSocket::Read(void*          buf,
  236.                          size_t         size,
  237.                          size_t*        n_read,
  238.                          EIO_ReadMethod how)
  239. {
  240.     if ( m_Socket )
  241.         return SOCK_Read(m_Socket, buf, size, n_read, how);
  242.     if ( n_read )
  243.         *n_read = 0;
  244.     return eIO_Closed;
  245. }
  246. EIO_Status CSocket::Write(const void*     buf,
  247.                           size_t          size,
  248.                           size_t*         n_written,
  249.                           EIO_WriteMethod how)
  250. {
  251.     if ( m_Socket )
  252.         return SOCK_Write(m_Socket, buf, size, n_written, how);
  253.     if ( n_written )
  254.         *n_written = 0;
  255.     return eIO_Closed;
  256. }
  257. void CSocket::GetPeerAddress(unsigned int* host, unsigned short* port,
  258.                              ENH_ByteOrder byte_order) const
  259. {
  260.     if ( !m_Socket ) {
  261.         if ( host )
  262.             *host = 0;
  263.         if ( port )
  264.             *port = 0;
  265.     } else
  266.         SOCK_GetPeerAddress(m_Socket, host, port, byte_order);
  267. }
  268. string CSocket::GetPeerAddress(void) const
  269. {
  270.     char buf[PATH_MAX + 1];
  271.     if (m_Socket  &&
  272.         SOCK_GetPeerAddressString(m_Socket, buf, sizeof(buf)) != 0) {
  273.         return string(buf);
  274.     }
  275.     return "";
  276. }
  277. /////////////////////////////////////////////////////////////////////////////
  278. //  CDatagramSocket::
  279. //
  280. CDatagramSocket::CDatagramSocket(ESwitch log)
  281. {
  282.     if (DSOCK_CreateEx(&m_Socket, log) != eIO_Success)
  283.         m_Socket = 0;
  284. }
  285. EIO_Status CDatagramSocket::Bind(unsigned short  port)
  286. {
  287.     return m_Socket ? DSOCK_Bind(m_Socket, port) : eIO_Closed;
  288. }
  289. EIO_Status CDatagramSocket::Connect(const string&  host,
  290.                                     unsigned short port)
  291. {
  292.     return m_Socket ? DSOCK_Connect(m_Socket, host.c_str(), port) : eIO_Closed;
  293. }
  294. EIO_Status CDatagramSocket::Send(const void*     data,
  295.                                  size_t          datalen,
  296.                                  const string&   host,
  297.                                  unsigned short  port)
  298. {
  299.     return m_Socket
  300.         ? DSOCK_SendMsg(m_Socket, host.c_str(), port, data, datalen)
  301.         : eIO_Closed;
  302. }
  303. EIO_Status CDatagramSocket::Recv(void*           buf,
  304.                                  size_t          buflen,
  305.                                  size_t*         msglen,
  306.                                  string*         sender_host,
  307.                                  unsigned short* sender_port,
  308.                                  size_t          maxmsglen)
  309. {
  310.     if ( !m_Socket )
  311.         return eIO_Closed;
  312.     unsigned int addr;
  313.     EIO_Status status = DSOCK_RecvMsg(m_Socket, buf, buflen, maxmsglen,
  314.                                       msglen, &addr, sender_port);
  315.     if ( sender_host )
  316.         *sender_host = CSocketAPI::ntoa(addr);
  317.     return status;
  318. }
  319. /////////////////////////////////////////////////////////////////////////////
  320. //  CListeningSocket::
  321. //
  322. CListeningSocket::CListeningSocket(void)
  323.     : m_Socket(0),
  324.       m_IsOwned(eTakeOwnership)
  325. {
  326.     return;
  327. }
  328. CListeningSocket::CListeningSocket(unsigned short port, unsigned short backlog)
  329.     : m_Socket(0),
  330.       m_IsOwned(eTakeOwnership)
  331. {
  332.     if (LSOCK_Create(port, backlog, &m_Socket) != eIO_Success)
  333.         m_Socket = 0;
  334. }
  335. CListeningSocket::~CListeningSocket(void)
  336. {
  337.     Close();
  338. }
  339. EIO_Status CListeningSocket::Listen(unsigned short port,
  340.                                     unsigned short backlog)
  341. {
  342.     if ( m_Socket )
  343.         return eIO_Unknown;
  344.     EIO_Status status = LSOCK_Create(port, backlog, &m_Socket);
  345.     if (status != eIO_Success)
  346.         m_Socket = 0;
  347.     return status;
  348. }
  349. EIO_Status CListeningSocket::Accept(CSocket*&       sock,
  350.                                     const STimeout* timeout) const
  351. {
  352.     if ( !m_Socket )
  353.         return eIO_Closed;
  354.     SOCK x_sock;
  355.     EIO_Status status = LSOCK_Accept(m_Socket, timeout, &x_sock);
  356.     if (status != eIO_Success) {
  357.         sock = 0;
  358.     } else if ( !(sock = new CSocket) ) {
  359.         SOCK_CloseEx(x_sock, 1);
  360.         status = eIO_Unknown;
  361.     } else
  362.         sock->Reset(x_sock, eTakeOwnership, eCopyTimeoutsToSOCK);
  363.     return status;
  364. }
  365. EIO_Status CListeningSocket::Accept(CSocket&        sock,
  366.                                     const STimeout* timeout) const
  367. {
  368.     if ( !m_Socket )
  369.         return eIO_Closed;
  370.     SOCK x_sock;
  371.     EIO_Status status = LSOCK_Accept(m_Socket, timeout, &x_sock);
  372.     if (status == eIO_Success)
  373.         sock.Reset(x_sock, eTakeOwnership, eCopyTimeoutsToSOCK);
  374.     return status;
  375. }
  376. EIO_Status CListeningSocket::Close(void)
  377. {
  378.     if ( !m_Socket )
  379.         return eIO_Success;
  380.     EIO_Status status = m_IsOwned != eNoOwnership
  381.         ? LSOCK_Close(m_Socket) : eIO_Success;
  382.     m_Socket = 0;
  383.     return status;
  384. }
  385. /////////////////////////////////////////////////////////////////////////////
  386. //  CSocketAPI::
  387. //
  388. string CSocketAPI::gethostname(void)
  389. {
  390.     char hostname[256];
  391.     if (SOCK_gethostname(hostname, sizeof(hostname)) != 0)
  392.         *hostname = 0;
  393.     return string(hostname);
  394. }
  395. string CSocketAPI::ntoa(unsigned int host)
  396. {
  397.     char ipaddr[64];
  398.     if (SOCK_ntoa(host, ipaddr, sizeof(ipaddr)) != 0)
  399.         *ipaddr = 0;
  400.     return string(ipaddr);
  401. }
  402. string CSocketAPI::gethostbyaddr(unsigned int host)
  403. {
  404.     char hostname[256];
  405.     if ( !SOCK_gethostbyaddr(host, hostname, sizeof(hostname)) )
  406.         *hostname = 0;
  407.     return string(hostname);
  408. }    
  409. unsigned int CSocketAPI::gethostbyname(const string& hostname)
  410. {
  411.     const char* host = hostname.c_str();
  412.     return SOCK_gethostbyname(*host ? host : 0);
  413. }
  414. EIO_Status CSocketAPI::Poll(vector<SPoll>&  polls,
  415.                             const STimeout* timeout,
  416.                             size_t*         n_ready)
  417. {
  418.     size_t          x_n     = polls.size();
  419.     SPOLLABLE_Poll* x_polls = 0;
  420.     if (x_n  &&  !(x_polls = new SPOLLABLE_Poll[x_n]))
  421.         return eIO_Unknown;
  422.     for (size_t i = 0;  i < x_n;  i++) {
  423.         CPollable* p     = polls[i].m_Pollable;
  424.         EIO_Event  event = polls[i].m_Event;
  425.         if (p  &&  event) {
  426.             CSocket* s = dynamic_cast<CSocket*> (p);
  427.             if (!s) {
  428.                 CListeningSocket* ls = dynamic_cast<CListeningSocket*> (p);
  429.                 x_polls[i].poll = POLLABLE_FromLSOCK(ls ? ls->GetLSOCK() : 0);
  430.             } else {
  431.                 x_polls[i].poll =
  432.                     POLLABLE_FromSOCK(s->GetStatus(eIO_Open) == eIO_Success ?
  433.                                       s->GetSOCK() : 0);
  434.             }
  435.             x_polls[i].event = event;
  436.         } else
  437.             x_polls[i].poll  = 0;
  438.     }
  439.     size_t x_ready;
  440.     EIO_Status status = POLLABLE_Poll(x_n, x_polls, timeout, &x_ready);
  441.     if (status == eIO_Success) {
  442.         for (size_t i = 0;  i < x_n;  i++)
  443.             polls[i].m_REvent = x_polls[i].revent;
  444.     }
  445.     if ( n_ready )
  446.         *n_ready = x_ready;
  447.     delete[] x_polls;
  448.     return status;
  449. }
  450. END_NCBI_SCOPE
  451. /*
  452.  * ---------------------------------------------------------------------------
  453.  * $Log: ncbi_socket_cxx.cpp,v $
  454.  * Revision 1000.3  2004/06/01 18:45:29  gouriano
  455.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R6.24
  456.  *
  457.  * Revision 6.24  2004/05/17 20:58:13  gorelenk
  458.  * Added include of PCH ncbi_pch.hpp
  459.  *
  460.  * Revision 6.23  2003/11/25 15:09:47  lavr
  461.  * Allow CSocket::Connect() after closing with CSocket::Close()
  462.  *
  463.  * Revision 6.22  2003/11/12 17:47:58  lavr
  464.  * Few fixes of return status; take advantage of SOCK_CloseEx()
  465.  *
  466.  * Revision 6.21  2003/10/24 16:51:36  lavr
  467.  * GetTimeout(eIO_ReadWrite): return the lesser of eIO_Read and eIO_Write
  468.  *
  469.  * Revision 6.20  2003/08/25 14:42:42  lavr
  470.  * Employ new k..Timeout constants;  reimplement more generic form of Poll()
  471.  *
  472.  * Revision 6.19  2003/07/15 19:04:04  lavr
  473.  * Yet another fix for MS-Win compilation
  474.  *
  475.  * Revision 6.18  2003/07/15 18:16:44  lavr
  476.  * Fix MS-Win compilation
  477.  *
  478.  * Revision 6.17  2003/07/15 18:09:51  lavr
  479.  * Use <limits.h> instead of <stdlib.h> to fetch PATH_MAX
  480.  *
  481.  * Revision 6.16  2003/07/15 16:50:57  lavr
  482.  * Implementation of CSocket::GetPeerAddress(void) added
  483.  *
  484.  * Revision 6.15  2003/05/14 03:50:54  lavr
  485.  * Match changes in ncbi_socket.hpp
  486.  *
  487.  * Revision 6.14  2003/04/30 17:03:33  lavr
  488.  * Modified prototypes for CDatagramSocket::Send() and CDatagramSocket::Recv()
  489.  *
  490.  * Revision 6.13  2003/04/11 20:59:30  lavr
  491.  * CDatagramSocket:: API defined completely
  492.  *
  493.  * Revision 6.12  2003/02/20 17:55:39  lavr
  494.  * Inlining CSocket::Shutdown() and CSocket::Wait()
  495.  *
  496.  * Revision 6.11  2003/02/14 22:03:43  lavr
  497.  * Add internal CSocket timeouts and document them
  498.  *
  499.  * Revision 6.10  2003/01/24 23:01:19  lavr
  500.  * Added class CDatagramSocket
  501.  *
  502.  * Revision 6.9  2002/12/04 16:56:02  lavr
  503.  * Employ SOCK_CreateEx()
  504.  *
  505.  * Revision 6.8  2002/11/14 01:11:49  lavr
  506.  * Minor formatting changes
  507.  *
  508.  * Revision 6.7  2002/11/01 20:13:15  lavr
  509.  * Expand hostname buffers to hold up to 256 chars
  510.  *
  511.  * Revision 6.6  2002/09/17 20:43:49  lavr
  512.  * Style conforming tiny little change
  513.  *
  514.  * Revision 6.5  2002/09/16 22:32:49  vakatov
  515.  * Allow to change ownership for the underlying sockets "on-the-fly";
  516.  * plus some minor (mostly formal) code and comments rearrangements
  517.  *
  518.  * Revision 6.4  2002/08/15 18:48:01  lavr
  519.  * Change all internal variables to have "x_" prefix in CSocketAPI::Poll()
  520.  *
  521.  * Revision 6.3  2002/08/14 15:16:25  lavr
  522.  * Do not use kEmptyStr for not to depend on xncbi(corelib) library
  523.  *
  524.  * Revision 6.2  2002/08/13 19:29:02  lavr
  525.  * Move most methods out-of-line to this file
  526.  *
  527.  * Revision 6.1  2002/08/12 15:15:36  lavr
  528.  * Initial revision
  529.  *
  530.  * ===========================================================================
  531.  */