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

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: ncbi_namedpipe.cpp,v $
  4.  * PRODUCTION Revision 1000.5  2004/06/01 18:45:01  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.26
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: ncbi_namedpipe.cpp,v 1000.5 2004/06/01 18:45:01 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, Mike DiCuccio, Vladimir Ivanov
  35.  *
  36.  * File Description:
  37.  *   Portable interprocess named pipe API for:  UNIX, MS-Win
  38.  *
  39.  */
  40. #include <ncbi_pch.hpp>
  41. #include <connect/ncbi_namedpipe.hpp>
  42. #include <corelib/ncbi_system.hpp>
  43. #if defined(NCBI_OS_MSWIN)
  44. #elif defined(NCBI_OS_UNIX)
  45. #  include <unistd.h>
  46. #  include <errno.h>
  47. #  include <fcntl.h>
  48. #  include <errno.h>
  49. #  include <sys/socket.h>
  50. #  include <sys/stat.h>
  51. #  include <sys/time.h>
  52. #  include <sys/un.h>
  53. #  include <connect/ncbi_socket.h>
  54. #else
  55. #  error "Class CNamedPipe is supported only on Windows and Unix"
  56. #endif
  57. BEGIN_NCBI_SCOPE
  58. #if !defined(HAVE_SOCKLEN_T)
  59. typedef int socklen_t;
  60. #endif
  61. // Predefined timeouts
  62. const size_t kDefaultPipeBufSize = (size_t)CNamedPipe::eDefaultBufSize;
  63. //////////////////////////////////////////////////////////////////////////////
  64. //
  65. // Auxiliary functions
  66. //
  67. static STimeout* s_SetTimeout(const STimeout* from, STimeout* to)
  68. {
  69.     if ( !from ) {
  70.         return const_cast<STimeout*> (kInfiniteTimeout);
  71.     }
  72.     to->sec  = from->usec / 1000000 + from->sec;
  73.     to->usec = from->usec % 1000000;
  74.     return to;
  75. }
  76. static string s_FormatErrorMessage(const string& where, const string& what)
  77. {
  78.     return "[NamedPipe::" + where + "]  " + what + ".";
  79. }
  80. inline void s_AdjustPipeBufSize(size_t* bufsize) {
  81.     if (*bufsize == 0)
  82.         *bufsize = kDefaultPipeBufSize;
  83.     else if (*bufsize == (size_t)kMax_Int)
  84.         *bufsize = 0 /* use system default buffer size */;
  85. }
  86. //////////////////////////////////////////////////////////////////////////////
  87. //
  88. // Class CNamedPipeHandle handles forwarded requests from CNamedPipe.
  89. // This class is reimplemented in a platform-specific fashion where needed.
  90. //
  91. #if defined(NCBI_OS_MSWIN)
  92. const DWORD kSleepTime = 100;  // sleep time for timeouts
  93. //////////////////////////////////////////////////////////////////////////////
  94. //
  95. // CNamedPipeHandle -- MS Windows version
  96. //
  97. class CNamedPipeHandle
  98. {
  99. public:
  100.     CNamedPipeHandle(void);
  101.     ~CNamedPipeHandle(void);
  102.     // client-side
  103.     EIO_Status Open(const string& pipename, const STimeout* timeout,
  104.                     size_t pipebufsize);
  105.     // server-side
  106.     EIO_Status Create(const string& pipename, size_t pipebufsize);
  107.     EIO_Status Listen(const STimeout* timeout);
  108.     EIO_Status Disconnect(void);
  109.     // common
  110.     EIO_Status Close(void);
  111.     EIO_Status Read(void* buf, size_t count, size_t* n_read,
  112.                     const STimeout* timeout);
  113.     EIO_Status Write(const void* buf, size_t count, size_t* n_written,
  114.                      const STimeout* timeout);
  115.     EIO_Status Wait(EIO_Event event, const STimeout* timeout);
  116.     EIO_Status Status(EIO_Event direction) const;
  117. private:
  118.     long TimeoutToMSec(const STimeout* timeout) const;
  119. private:
  120.     HANDLE      m_Pipe;         // pipe I/O handle
  121.     string      m_PipeName;     // pipe name 
  122.     size_t      m_PipeBufSize;  // pipe buffer size
  123.     EIO_Status  m_ReadStatus;   // last read status
  124.     EIO_Status  m_WriteStatus;  // last write status
  125. };
  126. CNamedPipeHandle::CNamedPipeHandle(void)
  127.     : m_Pipe(INVALID_HANDLE_VALUE), m_PipeName(kEmptyStr),
  128.       m_PipeBufSize(0),
  129.       m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed)
  130. {
  131.     return;
  132. }
  133. CNamedPipeHandle::~CNamedPipeHandle(void)
  134. {
  135.     Close();
  136. }
  137. EIO_Status CNamedPipeHandle::Open(const string&   pipename,
  138.                                   const STimeout* timeout,
  139.                                   size_t          /* pipebufsize */)
  140. {
  141.     try {
  142.         if (m_Pipe != INVALID_HANDLE_VALUE) {
  143.             throw string("Pipe is already open");
  144.         }
  145.         // Save parameters
  146.         m_PipeName    = pipename;
  147.         m_PipeBufSize = 0 /* pipebufsize is not used on client side */;
  148.         // Set the base security attributes
  149.         SECURITY_ATTRIBUTES attr;
  150.         attr.nLength = sizeof(attr);
  151.         attr.bInheritHandle = TRUE;
  152.         attr.lpSecurityDescriptor = NULL;
  153.         // Waits until either a time-out interval elapses or an instance of
  154.         // the specified named pipe is available for connection (that is, the
  155.         // pipe's server process has a pending Listen() operation on the pipe).
  156.         // NOTE: We do not use here a WaitNamedPipe() because it works
  157.         //       incorrect in some cases.
  158.         DWORD x_timeout = TimeoutToMSec(timeout);
  159.         do {
  160.             // Open existing pipe
  161.             m_Pipe = CreateFile(pipename.c_str(),
  162.                                 GENERIC_READ | GENERIC_WRITE,
  163.                                 FILE_SHARE_READ | FILE_SHARE_WRITE,
  164.                                 &attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  165.                                 NULL);
  166.             if (m_Pipe != INVALID_HANDLE_VALUE) {
  167.                 m_ReadStatus  = eIO_Success;
  168.                 m_WriteStatus = eIO_Success;
  169.                 return eIO_Success;
  170.             }
  171.             DWORD x_sleep = kSleepTime;
  172.             if (x_timeout != INFINITE) {
  173.                 if (x_timeout < kSleepTime) {
  174.                     x_sleep = x_timeout;
  175.                 }
  176.                 x_timeout -= x_sleep;
  177.             }
  178.             SleepMilliSec(x_sleep);
  179.         } while (x_timeout == INFINITE  ||  x_timeout);
  180.         return eIO_Timeout;
  181.     }
  182.     catch (string& what) {
  183.         Close();
  184.         ERR_POST(s_FormatErrorMessage("Open", what));
  185.         return eIO_Unknown;
  186.     }
  187. }
  188. EIO_Status CNamedPipeHandle::Create(const string& pipename,
  189.                                     size_t        pipebufsize)
  190. {
  191.     try {
  192.         if (m_Pipe != INVALID_HANDLE_VALUE) {
  193.             throw string("Pipe is already open");
  194.         }
  195.         // Save parameters
  196.         m_PipeName    = pipename;
  197.         m_PipeBufSize = pipebufsize;
  198.         // Set the base security attributes
  199.         SECURITY_ATTRIBUTES attr;
  200.         attr.nLength = sizeof(attr);
  201.         attr.bInheritHandle = TRUE;
  202.         attr.lpSecurityDescriptor = NULL;
  203.         // Create pipe
  204.         m_Pipe = CreateNamedPipe(
  205.                  pipename.c_str(),              // pipe name 
  206.                  PIPE_ACCESS_DUPLEX,            // read/write access 
  207.                  PIPE_TYPE_BYTE | PIPE_NOWAIT,  // byte-type, nonblocking mode 
  208.                  1,                             // one instance only 
  209.                  pipebufsize,                   // output buffer size 
  210.                  pipebufsize,                   // input buffer size 
  211.                  INFINITE,                      // client time-out by default
  212.                  &attr);                        // security attributes
  213.         if (m_Pipe == INVALID_HANDLE_VALUE) {
  214.             throw "Create named pipe "" + pipename + "" failed";
  215.         }
  216.         m_ReadStatus  = eIO_Success;
  217.         m_WriteStatus = eIO_Success;
  218.         return eIO_Success;
  219.     }
  220.     catch (string& what) {
  221.         Close();
  222.         ERR_POST(s_FormatErrorMessage("Create", what));
  223.         return eIO_Unknown;
  224.     }
  225. }
  226. EIO_Status CNamedPipeHandle::Listen(const STimeout* timeout)
  227. {
  228.     EIO_Status status = eIO_Unknown;
  229.     // Wait for the client to connect, or time out.
  230.     // NOTE: The function WaitForSingleObject() do not work with pipes.
  231.     DWORD x_timeout = TimeoutToMSec(timeout);
  232.     try {
  233.         if (m_Pipe == INVALID_HANDLE_VALUE) {
  234.             status = eIO_Closed;
  235.             throw string("Pipe is closed");
  236.         }
  237.         do {
  238.             BOOL connected = ConnectNamedPipe(m_Pipe, NULL);
  239.             if ( !connected ) {
  240.                 DWORD error = GetLastError();
  241.                 connected = (error == ERROR_PIPE_CONNECTED); 
  242.                 // If client closed connection before we serve it
  243.                 if (error == ERROR_NO_DATA) {
  244.                     if (Disconnect() != eIO_Success) {
  245.                         throw string("Listening pipe: failed to close broken "
  246.                                      "client session");
  247.                     } 
  248.                 }
  249.             }
  250.             if ( connected ) {
  251.                 return eIO_Success;
  252.             }
  253.             DWORD x_sleep = kSleepTime;
  254.             if (x_timeout != INFINITE) {
  255.                 if (x_timeout < kSleepTime) {
  256.                     x_sleep = x_timeout;
  257.                 }
  258.                 x_timeout -= x_sleep;
  259.             }
  260.             SleepMilliSec(x_sleep);
  261.         } while (x_timeout == INFINITE  ||  x_timeout);
  262.         return eIO_Timeout;
  263.     }
  264.     catch (string& what) {
  265.         ERR_POST(s_FormatErrorMessage("Listen", what));
  266.         return status;
  267.     }
  268. }
  269. EIO_Status CNamedPipeHandle::Disconnect(void)
  270. {
  271.     EIO_Status status = eIO_Unknown;
  272.     try {
  273.         if (m_Pipe == INVALID_HANDLE_VALUE) {
  274.             status = eIO_Closed;
  275.             throw string("Pipe is already closed");
  276.         }
  277.         FlushFileBuffers(m_Pipe); 
  278.         if (!DisconnectNamedPipe(m_Pipe)) {
  279.             throw string("DisconnectNamedPipe() failed");
  280.         } 
  281.         Close();
  282.         return Create(m_PipeName, m_PipeBufSize);
  283.     }
  284.     catch (string& what) {
  285.         ERR_POST(s_FormatErrorMessage("Disconnect", what));
  286.         return status;
  287.     }
  288. }
  289. EIO_Status CNamedPipeHandle::Close(void)
  290. {
  291.     if (m_Pipe == INVALID_HANDLE_VALUE) {
  292.         return eIO_Closed;
  293.     }
  294.     FlushFileBuffers(m_Pipe);
  295.     CloseHandle(m_Pipe);
  296.     m_Pipe = INVALID_HANDLE_VALUE;
  297.     m_ReadStatus  = eIO_Closed;
  298.     m_WriteStatus = eIO_Closed;
  299.     return eIO_Success;
  300. }
  301. EIO_Status CNamedPipeHandle::Read(void* buf, size_t count, size_t* n_read,
  302.                                   const STimeout* timeout)
  303. {
  304.     EIO_Status status = eIO_Unknown;
  305.     try {
  306.         if (m_Pipe == INVALID_HANDLE_VALUE) {
  307.             status = eIO_Closed;
  308.             throw string("Pipe is closed");
  309.         }
  310.         if ( !count ) {
  311. m_ReadStatus = eIO_Success;
  312.             return m_ReadStatus;
  313.         }
  314.         DWORD x_timeout   = TimeoutToMSec(timeout);
  315.         DWORD bytes_avail = 0;
  316.         // Wait a data from the pipe with timeout.
  317.         // NOTE:  The function WaitForSingleObject() do not work with pipe.
  318.         do {
  319.             if ( !PeekNamedPipe(m_Pipe, NULL, 0, NULL, &bytes_avail, NULL) ) {
  320.                 // Peer has been closed the connection?
  321.                 if (GetLastError() == ERROR_BROKEN_PIPE) {
  322. m_ReadStatus = eIO_Closed;
  323.                     return m_ReadStatus;
  324.                 }
  325.                 throw string("Cannot peek data from the named pipe");
  326.             }
  327.             if ( bytes_avail ) {
  328.                 break;
  329.             }
  330.             DWORD x_sleep = kSleepTime;
  331.             if (x_timeout != INFINITE) {
  332.                 if (x_timeout < kSleepTime) {
  333.                     x_sleep = x_timeout;
  334.                 }
  335.                 x_timeout -= x_sleep;
  336.             }
  337.             SleepMilliSec(x_sleep);
  338.         } while (x_timeout == INFINITE  ||  x_timeout);
  339.         // Data is available to read or time out
  340.         if ( !bytes_avail ) {
  341. m_ReadStatus = eIO_Timeout;
  342.             return m_ReadStatus;
  343.         }
  344.         // We must read only "count" bytes of data regardless of the number
  345.         // available to read
  346.         if (bytes_avail > count) {
  347.             bytes_avail = count;
  348.         }
  349.         if (!ReadFile(m_Pipe, buf, count, &bytes_avail, NULL)) {
  350.             throw string("Failed to read data from the named pipe");
  351.         }
  352.         if ( n_read ) {
  353.             *n_read = bytes_avail;
  354.         }
  355.         status = eIO_Success;
  356.     }
  357.     catch (string& what) {
  358.         ERR_POST(s_FormatErrorMessage("Read", what));
  359.     }
  360.     m_ReadStatus = status;
  361.     return status;
  362. }
  363. EIO_Status CNamedPipeHandle::Write(const void* buf, size_t count,
  364.                                    size_t* n_written, const STimeout* timeout)
  365. {
  366.     EIO_Status status = eIO_Unknown;
  367.     try {
  368.         if (m_Pipe == INVALID_HANDLE_VALUE) {
  369.             status = eIO_Closed;
  370.             throw string("Pipe is closed");
  371.         }
  372.         if ( !count ) {
  373.             return eIO_Success;
  374.         }
  375.         DWORD x_timeout     = TimeoutToMSec(timeout);
  376.         DWORD bytes_written = 0;
  377.         // Wait a data from the pipe with timeout.
  378.         // NOTE:  The function WaitForSingleObject() do not work with pipe.
  379.         do {
  380.             if (!WriteFile(m_Pipe, (char*)buf, count, &bytes_written, NULL)) {
  381.                 if ( n_written ) {
  382.                     *n_written = bytes_written;
  383.                 }
  384.                 throw string("Failed to write data into the named pipe");
  385.             }
  386.             if ( bytes_written ) {
  387.                 break;
  388.             }
  389.             DWORD x_sleep = kSleepTime;
  390.             if (x_timeout != INFINITE) {
  391.                 if (x_timeout < kSleepTime) {
  392.                     x_sleep = x_timeout;
  393.                 }
  394.                 x_timeout -= x_sleep;
  395.             }
  396.             SleepMilliSec(x_sleep);
  397.         } while (x_timeout == INFINITE  ||  x_timeout);
  398.         if ( !bytes_written ) {
  399.             return eIO_Timeout;
  400.         }
  401.         if ( n_written ) {
  402.             *n_written = bytes_written;
  403.         }
  404.         status = eIO_Success;
  405.     }
  406.     catch (string& what) {
  407.         ERR_POST(s_FormatErrorMessage("Write", what));
  408.     }
  409.     m_WriteStatus = status;
  410.     return status;
  411. }
  412. EIO_Status CNamedPipeHandle::Wait(EIO_Event, const STimeout*)
  413. {
  414.     return eIO_Success;
  415. }
  416. EIO_Status CNamedPipeHandle::Status(EIO_Event direction) const
  417. {
  418.     switch ( direction ) {
  419.     case eIO_Read:
  420.         return m_ReadStatus;
  421.     case eIO_Write:
  422.         return m_WriteStatus;
  423.     default:
  424.         // Should never get here
  425.         assert(0);
  426.         break;
  427.     }
  428.     return eIO_InvalidArg;
  429. }
  430. // Convert STimeout value to number of milliseconds
  431. long CNamedPipeHandle::TimeoutToMSec(const STimeout* timeout) const
  432. {
  433.     return timeout ? timeout->sec * 1000 + timeout->usec / 1000 : INFINITE;
  434. }
  435. #elif defined(NCBI_OS_UNIX)
  436. //////////////////////////////////////////////////////////////////////////////
  437. //
  438. // CNamedPipeHandle -- Unix version
  439. //
  440. // The maximum length the queue of pending connections may grow to
  441. const int kListenQueueSize = 32;
  442. class CNamedPipeHandle
  443. {
  444. public:
  445.     CNamedPipeHandle(void);
  446.     ~CNamedPipeHandle(void);
  447.     // client-side
  448.     EIO_Status Open(const string& pipename,
  449.                     const STimeout* timeout, size_t pipebufsize);
  450.     // server-side
  451.     EIO_Status Create(const string& pipename, size_t pipebufsize);
  452.     EIO_Status Listen(const STimeout* timeout);
  453.     EIO_Status Disconnect(void);
  454.     // common
  455.     EIO_Status Close(void);
  456.     EIO_Status Read (void* buf, size_t count, size_t* n_read,
  457.                      const STimeout* timeout);
  458.     EIO_Status Write(const void* buf, size_t count, size_t* n_written,
  459.                      const STimeout* timeout);
  460.     EIO_Status Wait(EIO_Event event, const STimeout* timeout);
  461.     EIO_Status Status(EIO_Event direction) const;
  462. private:
  463.     // Close socket persistently
  464.     bool x_CloseSocket(int sock);
  465.     // Set socket i/o buffer size (dir: SO_SNDBUF, SO_RCVBUF)
  466.     bool x_SetSocketBufSize(int sock, size_t pipebufsize, int dir);
  467. private:
  468.     int     m_LSocket;      // listening socket
  469.     SOCK    m_IoSocket;     // I/O socket
  470.     size_t  m_PipeBufSize;  // pipe buffer size
  471. };
  472. CNamedPipeHandle::CNamedPipeHandle(void)
  473.     : m_LSocket(-1), m_IoSocket(0), m_PipeBufSize(0)
  474. {
  475.     return;
  476. }
  477. CNamedPipeHandle::~CNamedPipeHandle(void)
  478. {
  479.     Close();
  480. }
  481. EIO_Status CNamedPipeHandle::Open(const string&   pipename,
  482.                                   const STimeout* timeout,
  483.                                   size_t          pipebufsize)
  484. {
  485.     EIO_Status status = eIO_Unknown;
  486.     struct sockaddr_un addr;
  487.     int sock = -1;
  488.     try {
  489.         if (m_LSocket >= 0  ||  m_IoSocket) {
  490.             throw string("Pipe is already open");
  491.         }
  492.         if (sizeof(addr.sun_path) <= pipename.length()) {
  493.             status = eIO_InvalidArg;
  494.             throw "Pipe name too long: "" + pipename + '"';
  495.         }
  496.         m_PipeBufSize = pipebufsize;
  497.         // Create a UNIX socket
  498.         if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
  499.             throw string("UNIX socket() failed: ")
  500.                 + strerror(errno);
  501.         }
  502.         // Set buffer size
  503.         if ( m_PipeBufSize ) {
  504.             if ( !x_SetSocketBufSize(sock, m_PipeBufSize, SO_SNDBUF)  ||
  505.                  !x_SetSocketBufSize(sock, m_PipeBufSize, SO_RCVBUF) ) {
  506.                 throw string("UNIX socket set buffer size failed: ")
  507.                     + strerror(errno);
  508.             }
  509.         }
  510.         // Set non-blocking mode
  511.         if (fcntl(sock, F_SETFL,
  512.                   fcntl(sock, F_GETFL, 0) | O_NONBLOCK) == -1) {
  513.             throw string("UNIX socket set to non-blocking failed: ")
  514.                 + strerror(errno);
  515.         }
  516.         
  517.         // Connect to server
  518.         memset(&addr, 0, sizeof(addr));
  519.         addr.sun_family = AF_UNIX;
  520. #ifdef HAVE_SIN_LEN
  521.         addr.sun_len = (socklen_t) sizeof(addr);
  522. #endif
  523.         strcpy(addr.sun_path, pipename.c_str());
  524.         
  525.         int n;
  526.         int x_errno = 0;
  527.         // Auto-resume if interrupted by a signal
  528.         for (n = 0; ; n = 1) {
  529.             if (connect(sock, (struct sockaddr*) &addr, sizeof(addr)) == 0) {
  530.                 break;
  531.             }
  532.             x_errno = errno;
  533.             if (x_errno != EINTR) { 
  534.                 break;
  535.             }
  536.         }
  537.         // If not connected
  538.         if ( x_errno ) {
  539.             if ((n != 0  ||  x_errno != EINPROGRESS)  &&
  540.                 (n == 0  ||  x_errno != EALREADY)     &&
  541.                 x_errno != EWOULDBLOCK) {
  542.                 if (x_errno == EINTR) {
  543.                     status = eIO_Interrupt;
  544.                 }
  545.                 throw "UNIX socket connect("" + pipename + "") failed: "
  546.                     + strerror(x_errno);
  547.             }
  548.             if (!timeout  ||  timeout->sec  ||  timeout->usec) {
  549.                 // Wait for socket to connect (if timeout is set or infinite)
  550.                 for (;;) { // Auto-resume if interrupted by a signal
  551.                     struct timeval* tmp;
  552.                     struct timeval  tm;
  553.                     if ( !timeout ) {
  554.                         // NB: Timeout has been normalized already
  555.                         tm.tv_sec  = timeout->sec;
  556.                         tm.tv_usec = timeout->usec;
  557.                         tmp = &tm;
  558.                     } else
  559.                         tmp = 0;
  560.                     fd_set wfds;
  561.                     fd_set efds;
  562.                     FD_ZERO(&wfds);
  563.                     FD_ZERO(&efds);
  564.                     FD_SET(sock, &wfds);
  565.                     FD_SET(sock, &efds);
  566.                     n = select(sock + 1, 0, &wfds, &efds, tmp);
  567.                     if (n == 0) {
  568.                         x_CloseSocket(sock);
  569.                         Close();
  570.                         return eIO_Timeout;
  571.                     }
  572.                     if (n > 0) {
  573.                         if ( FD_ISSET(sock, &wfds) ) {
  574.                             break;
  575.                         }
  576.                         assert( FD_ISSET(sock, &efds) );
  577.                     }
  578.                     if (n < 0  &&  errno == EINTR) {
  579.                         continue;
  580.                     }
  581.                     throw string("UNIX socket select() failed: ")
  582.                         + strerror(errno);
  583.                 }
  584.                 // Check connection
  585.                 x_errno = 0;
  586.                 socklen_t x_len = (socklen_t) sizeof(x_errno);
  587.                 if ((getsockopt(sock, SOL_SOCKET, SO_ERROR, &x_errno, 
  588.                                 &x_len) != 0  ||  x_errno != 0)) {
  589.                     throw string("UNIX socket getsockopt() failed: ")
  590.                         + strerror(x_errno ? x_errno : errno);
  591.                 }
  592.                 if (x_errno == ECONNREFUSED) {
  593.                     status = eIO_Closed;
  594.                     throw "Connection refused in "" + pipename + '"';
  595.                 }
  596.             }
  597.         }
  598.         // Create I/O socket
  599.         if (SOCK_CreateOnTop(&sock, sizeof(sock), &m_IoSocket) != eIO_Success){
  600.             throw string("UNIX socket cannot convert to SOCK");
  601.         }
  602.     }
  603.     catch (string& what) {
  604.         if (sock >= 0) {
  605.             x_CloseSocket(sock);
  606.         }
  607.         Close();
  608.         ERR_POST(s_FormatErrorMessage("Open", what));
  609.         return status;
  610.     }
  611.     return eIO_Success;
  612. }
  613. EIO_Status CNamedPipeHandle::Create(const string& pipename,
  614.                                     size_t        pipebufsize)
  615. {
  616.     EIO_Status status = eIO_Unknown;
  617.     struct sockaddr_un addr;
  618.     try {
  619.         if (m_LSocket >= 0  ||  m_IoSocket) {
  620.             throw string("Pipe is already open");
  621.         }
  622.         if (sizeof(addr.sun_path) <= pipename.length()) {
  623.             status = eIO_InvalidArg;
  624.             throw "Pipe name too long: "" + pipename + '"';
  625.         }
  626.         m_PipeBufSize = pipebufsize;
  627.         // Create a UNIX socket
  628.         if ((m_LSocket = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) {
  629.             throw string("UNIX socket() failed: ")
  630.                 + strerror(errno);
  631.         }
  632.         // Remove any pre-existing socket (or other file)
  633.         if (unlink(pipename.c_str()) != 0  &&  errno != ENOENT) {
  634.             throw "UNIX socket unlink("" + pipename + "") failed: "
  635.                 + strerror(errno);
  636.         }
  637.         // Bind socket
  638.         memset(&addr, 0, sizeof(addr));
  639.         addr.sun_family = AF_UNIX;
  640. #ifdef HAVE_SIN_LEN
  641.         addr.sun_len = (socklen_t) sizeof(addr);
  642. #endif
  643.         strcpy(addr.sun_path, pipename.c_str());
  644.         mode_t u = umask(0);
  645.         if (bind(m_LSocket, (struct sockaddr*) &addr, sizeof(addr)) != 0) {
  646.             umask(u);
  647.             throw "UNIX socket bind("" + pipename + "") failed: "
  648.                 + strerror(errno);
  649.         }
  650.         umask(u);
  651. #ifndef NCBI_OS_IRIX
  652.         fchmod(m_LSocket, S_IRWXU | S_IRWXG | S_IRWXO);
  653. #endif
  654.         // Listen for connections on a socket
  655.         if (listen(m_LSocket, kListenQueueSize) != 0) {
  656.             throw "UNIX socket listen("" + pipename + "") failed: "
  657.                 + strerror(errno);
  658.         }
  659.         if (fcntl(m_LSocket, F_SETFL,
  660.                   fcntl(m_LSocket, F_GETFL, 0) | O_NONBLOCK) == -1) {
  661.             throw string("UNIX socket set to non-blocking failed: ")
  662.                 + strerror(errno);
  663.         }
  664.     }
  665.     catch (string& what) {
  666.         Close();
  667.         ERR_POST(s_FormatErrorMessage("Create", what));
  668.         return status;
  669.     }
  670.     return eIO_Success;
  671. }
  672. EIO_Status CNamedPipeHandle::Listen(const STimeout* timeout)
  673. {
  674.     EIO_Status status = eIO_Unknown;
  675.     int        sock   = -1;
  676.     try {
  677.         if (m_LSocket < 0) {
  678.             status = eIO_Closed;
  679.             throw string("Pipe is closed");
  680.         }
  681.         // Wait for the client to connect
  682.         for (;;) { // Auto-resume if interrupted by a signal
  683.             struct timeval* tmp;
  684.             struct timeval  tm;
  685.             if (timeout) {
  686.                 // NB: Timeout has been normalized already
  687.                 tm.tv_sec  = timeout->sec;
  688.                 tm.tv_usec = timeout->usec;
  689.                 tmp = &tm;
  690.             } else {
  691.                 tmp = 0;
  692.             }
  693.             fd_set rfds;
  694.             fd_set efds;
  695.             FD_ZERO(&rfds);
  696.             FD_ZERO(&efds);
  697.             FD_SET(m_LSocket, &rfds);
  698.             FD_SET(m_LSocket, &efds);
  699.             int n = select(m_LSocket + 1, &rfds, 0, &efds, tmp);
  700.             if (n == 0) {
  701.                 return eIO_Timeout;
  702.             }
  703.             if (n > 0) {
  704.                 if ( FD_ISSET(m_LSocket, &rfds) )
  705.                     break;
  706.                 assert( FD_ISSET(m_LSocket, &efds) );
  707.             }
  708.             if (n < 0  &&  errno == EINTR) {
  709.                 continue;
  710.             }
  711.             throw string("UNIX socket select() failed: ")
  712.                 + strerror(errno);
  713.         }
  714.         // Can accept next connection from the list of waiting ones
  715.         struct sockaddr_un addr;
  716.         socklen_t addrlen = (socklen_t) sizeof(addr);
  717.         memset(&addr, 0, sizeof(addr));
  718. #  ifdef HAVE_SIN_LEN
  719.         addr.sun_len = sizeof(addr);
  720. #  endif
  721.         if ((sock = accept(m_LSocket, (struct sockaddr*)&addr, &addrlen)) < 0){
  722.             throw string("UNIX socket accept() failed: ")
  723.                 + strerror(errno);
  724.         }
  725.         // Set buffer size
  726.         if ( m_PipeBufSize ) {
  727.             if ( !x_SetSocketBufSize(sock, m_PipeBufSize, SO_SNDBUF)  ||
  728.                  !x_SetSocketBufSize(sock, m_PipeBufSize, SO_RCVBUF) ) {
  729.                 throw string("UNIX socket set buffer size failed: ")
  730.                     + strerror(errno);
  731.             }
  732.         }
  733.         // Create new I/O socket
  734.         if (SOCK_CreateOnTop(&sock, sizeof(sock), &m_IoSocket) != eIO_Success){
  735.             throw string("UNIX socket cannot convert to SOCK");
  736.         }
  737.     }
  738.     catch (string& what) {
  739.         if (sock >= 0) {
  740.             x_CloseSocket(sock);
  741.         }
  742.         Close();
  743.         ERR_POST(s_FormatErrorMessage("Listen", what));
  744.         return status;
  745.     }
  746.     return eIO_Success;
  747. }
  748. EIO_Status CNamedPipeHandle::Disconnect(void)
  749. {
  750.     if ( !m_IoSocket ) {
  751.         return eIO_Closed;
  752.     }
  753.     // Close I/O socket
  754.     EIO_Status status = SOCK_Close(m_IoSocket);
  755.     m_IoSocket = 0;
  756.     return status;
  757. }
  758. EIO_Status CNamedPipeHandle::Close(void)
  759. {
  760.     // Disconnect current client
  761.     EIO_Status status = Disconnect();
  762.     // Close listening socket
  763.     if (m_LSocket >= 0) {
  764.         if ( !x_CloseSocket(m_LSocket) ) {
  765.             ERR_POST(s_FormatErrorMessage
  766.                      ("Close", string("UNIX socket close() failed: ") +
  767.                       strerror(errno)));
  768.         }
  769.         m_LSocket = -1;
  770.     }
  771.     return status;
  772. }
  773. EIO_Status CNamedPipeHandle::Read(void* buf, size_t count, size_t* n_read,
  774.                                   const STimeout* timeout)
  775. {
  776.     EIO_Status status = eIO_Closed;
  777.     try {
  778.         if ( !m_IoSocket ) {
  779.             throw string("Pipe is closed");
  780.         }
  781.         if ( !count ) {
  782.             // *n_read == 0
  783.             return eIO_Success;
  784.         }
  785.         status = SOCK_SetTimeout(m_IoSocket, eIO_Read, timeout);
  786.         if (status == eIO_Success) {
  787.             status = SOCK_Read(m_IoSocket, buf, count, n_read, eIO_ReadPlain);
  788.         }
  789.     }
  790.     catch (string& what) {
  791.         ERR_POST(s_FormatErrorMessage("Read", what));
  792.     }
  793.     return status;
  794. }
  795. EIO_Status CNamedPipeHandle::Write(const void* buf, size_t count,
  796.                                    size_t* n_written, const STimeout* timeout)
  797. {
  798.     EIO_Status status = eIO_Closed;
  799.     try {
  800.         if ( !m_IoSocket ) {
  801.             throw string("Pipe is closed");
  802.         }
  803.         if ( !count ) {
  804.             // *n_written == 0
  805.             return eIO_Success;
  806.         }
  807.         status = SOCK_SetTimeout(m_IoSocket, eIO_Write, timeout);
  808.         if (status == eIO_Success) {
  809.             status = SOCK_Write(m_IoSocket, buf, count, n_written,
  810.                                 eIO_WritePlain);
  811.         }
  812.     }
  813.     catch (string& what) {
  814.         ERR_POST(s_FormatErrorMessage("Write", what));
  815.     }
  816.     return status;
  817. }
  818. EIO_Status CNamedPipeHandle::Wait(EIO_Event event, const STimeout* timeout)
  819. {
  820.     if ( m_IoSocket )
  821.         return SOCK_Wait(m_IoSocket, event, timeout);
  822.     ERR_POST(s_FormatErrorMessage("Wait", "Pipe is closed"));
  823.     return eIO_Closed;
  824. }
  825. EIO_Status CNamedPipeHandle::Status(EIO_Event direction) const
  826. {
  827.     if ( !m_IoSocket ) {
  828.         return eIO_Closed;
  829.     }
  830.     return SOCK_Status(m_IoSocket, direction);
  831. }
  832. bool CNamedPipeHandle::x_CloseSocket(int sock)
  833. {
  834.     if (sock >= 0) {
  835.         for (;;) { // Close persistently
  836.             if (close(sock) == 0) {
  837.                 break;
  838.             }
  839.             if (errno != EINTR) {
  840.                 return false;
  841.             }
  842.         }
  843.     }
  844.     return true;
  845. }
  846. bool CNamedPipeHandle::x_SetSocketBufSize(int sock, size_t bufsize, int dir)
  847. {
  848.     int       bs_old = 0;
  849.     int       bs_new = (int) bufsize;
  850.     socklen_t bs_len = (socklen_t) sizeof(bs_old);
  851.     if (getsockopt(sock, SOL_SOCKET, dir, &bs_old, &bs_len) == 0  &&
  852.         bs_new > bs_old) {
  853.         if (setsockopt(sock, SOL_SOCKET, dir, &bs_new, bs_len) != 0) {
  854.             return false;
  855.         }
  856.     }
  857.     return true;
  858. }
  859. #endif  /* NCBI_OS_UNIX | NCBI_OS_MSWIN */
  860. //////////////////////////////////////////////////////////////////////////////
  861. //
  862. // CNamedPipe
  863. //
  864. CNamedPipe::CNamedPipe(void)
  865.     : m_PipeName(kEmptyStr), m_PipeBufSize(kDefaultPipeBufSize),
  866.       m_OpenTimeout(0), m_ReadTimeout(0), m_WriteTimeout(0)
  867. {
  868.     m_NamedPipeHandle = new CNamedPipeHandle;
  869. }
  870. CNamedPipe::~CNamedPipe(void)
  871. {
  872.     Close();
  873.     delete m_NamedPipeHandle;
  874. }
  875. EIO_Status CNamedPipe::Close()
  876. {
  877.     return m_NamedPipeHandle ? m_NamedPipeHandle->Close() : eIO_Unknown;
  878. }
  879.      
  880. EIO_Status CNamedPipe::Read(void* buf, size_t count, size_t* n_read)
  881. {
  882.     if ( n_read ) {
  883.         *n_read = 0;
  884.     }
  885.     if (count  &&  !buf) {
  886.         return eIO_InvalidArg;
  887.     }
  888.     return m_NamedPipeHandle
  889.         ? m_NamedPipeHandle->Read(buf, count, n_read, m_ReadTimeout)
  890.         : eIO_Unknown;
  891. }
  892. EIO_Status CNamedPipe::Write(const void* buf, size_t count, size_t* n_written)
  893. {
  894.     if ( n_written ) {
  895.         *n_written = 0;
  896.     }
  897.     if (count  &&  !buf) {
  898.         return eIO_InvalidArg;
  899.     }
  900.     return m_NamedPipeHandle
  901.         ? m_NamedPipeHandle->Write(buf, count, n_written, m_WriteTimeout)
  902.         : eIO_Unknown;
  903. }
  904. EIO_Status CNamedPipe::Wait(EIO_Event event, const STimeout* timeout)
  905. {
  906.     switch (event) {
  907.     case eIO_Read:
  908.     case eIO_Write:
  909.     case eIO_ReadWrite:
  910.         break;
  911.     default:
  912.         return eIO_InvalidArg;
  913.     }
  914.     return m_NamedPipeHandle
  915.         ? m_NamedPipeHandle->Wait(event, timeout)
  916.         : eIO_Unknown;
  917. }
  918. EIO_Status CNamedPipe::Status(EIO_Event direction) const
  919. {
  920.     switch (direction) {
  921.     case eIO_Read:
  922.     case eIO_Write:
  923.         break;
  924.     default:
  925.         return eIO_InvalidArg;
  926.     }
  927.     return m_NamedPipeHandle
  928.         ? m_NamedPipeHandle->Status(direction)
  929.         : eIO_Unknown;
  930. }
  931. EIO_Status CNamedPipe::SetTimeout(EIO_Event event, const STimeout* timeout)
  932. {
  933.     if (timeout == kDefaultTimeout) {
  934.         return eIO_Success;
  935.     }
  936.     switch ( event ) {
  937.     case eIO_Open:
  938.         m_OpenTimeout  = s_SetTimeout(timeout, &m_OpenTimeoutValue);
  939.         break;
  940.     case eIO_Read:
  941.         m_ReadTimeout  = s_SetTimeout(timeout, &m_ReadTimeoutValue);
  942.         break;
  943.     case eIO_Write:
  944.         m_WriteTimeout = s_SetTimeout(timeout, &m_WriteTimeoutValue);
  945.         break;
  946.     case eIO_ReadWrite:
  947.         m_ReadTimeout  = s_SetTimeout(timeout, &m_ReadTimeoutValue);
  948.         m_WriteTimeout = s_SetTimeout(timeout, &m_WriteTimeoutValue);
  949.         break;
  950.     default:
  951.         return eIO_InvalidArg;
  952.     }
  953.     return eIO_Success;
  954. }
  955. const STimeout* CNamedPipe::GetTimeout(EIO_Event event) const
  956. {
  957.     switch ( event ) {
  958.     case eIO_Open:
  959.         return m_OpenTimeout;
  960.     case eIO_Read:
  961.         return m_ReadTimeout;
  962.     case eIO_Write:
  963.         return m_WriteTimeout;
  964.     default:
  965.         ;
  966.     }
  967.     return kDefaultTimeout;
  968. }
  969. //////////////////////////////////////////////////////////////////////////////
  970. //
  971. // CNamedPipeClient
  972. //
  973. CNamedPipeClient::CNamedPipeClient(void)
  974. {
  975.     m_IsClientSide = true;
  976. }
  977. CNamedPipeClient::CNamedPipeClient(const string&   pipename,
  978.                                    const STimeout* timeout, 
  979.                                    size_t          pipebufsize)
  980. {
  981.     m_IsClientSide = true;
  982.     Open(pipename, timeout, pipebufsize);
  983. }
  984. EIO_Status CNamedPipeClient::Open(const string&    pipename,
  985.                                   const STimeout*  timeout,
  986.                                   size_t           pipebufsize)
  987. {
  988.     if ( !m_NamedPipeHandle ) {
  989.         return eIO_Unknown;
  990.     }
  991.     s_AdjustPipeBufSize(&pipebufsize);
  992.     m_PipeName    = pipename;
  993.     m_PipeBufSize = pipebufsize;
  994.     SetTimeout(eIO_Open, timeout);
  995.     return m_NamedPipeHandle->Open(pipename, m_OpenTimeout, m_PipeBufSize);
  996. }
  997. EIO_Status CNamedPipeClient::Create(const string&, const STimeout*, size_t)
  998. {
  999.     return eIO_Unknown;
  1000. }
  1001. //////////////////////////////////////////////////////////////////////////////
  1002. //
  1003. // CNamedPipeServer
  1004. //
  1005. CNamedPipeServer::CNamedPipeServer(void)
  1006. {
  1007.     m_IsClientSide = false;
  1008. }
  1009. CNamedPipeServer::CNamedPipeServer(const string&   pipename,
  1010.                                    const STimeout* timeout,
  1011.                                    size_t          pipebufsize)
  1012. {
  1013.     m_IsClientSide = false;
  1014.     Create(pipename, timeout, pipebufsize);
  1015. }
  1016. EIO_Status CNamedPipeServer::Create(const string&   pipename,
  1017.                                     const STimeout* timeout,
  1018.                                     size_t          pipebufsize)
  1019. {
  1020.     if ( !m_NamedPipeHandle ) {
  1021.         return eIO_Unknown;
  1022.     }
  1023.     s_AdjustPipeBufSize(&pipebufsize);
  1024.     m_PipeName    = pipename;
  1025.     m_PipeBufSize = pipebufsize;
  1026.     SetTimeout(eIO_Open, timeout);
  1027.     return m_NamedPipeHandle->Create(pipename, pipebufsize);
  1028. }
  1029. EIO_Status CNamedPipeServer::Open(const string&, const STimeout*, size_t)
  1030. {
  1031.     return eIO_Unknown;
  1032. }
  1033. EIO_Status CNamedPipeServer::Listen(void)
  1034. {
  1035.     return m_NamedPipeHandle
  1036.         ? m_NamedPipeHandle->Listen(m_OpenTimeout)
  1037.         : eIO_Unknown;
  1038. }
  1039. EIO_Status CNamedPipeServer::Disconnect(void)
  1040. {
  1041.     return m_NamedPipeHandle
  1042.         ? m_NamedPipeHandle->Disconnect()
  1043.         : eIO_Unknown;
  1044. }
  1045. END_NCBI_SCOPE
  1046. /*
  1047.  * ===========================================================================
  1048.  * $Log: ncbi_namedpipe.cpp,v $
  1049.  * Revision 1000.5  2004/06/01 18:45:01  gouriano
  1050.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.26
  1051.  *
  1052.  * Revision 1.26  2004/05/17 20:58:13  gorelenk
  1053.  * Added include of PCH ncbi_pch.hpp
  1054.  *
  1055.  * Revision 1.25  2004/03/22 17:03:20  ivanov
  1056.  * Replaced static member CNamedPipe::kDefaultPipeSize with enum values
  1057.  * for default and system pipe buffer size (by Denis Vakatov).
  1058.  *
  1059.  * Revision 1.24  2004/03/17 15:45:30  jcherry
  1060.  * Always record read status in Windows version of
  1061.  * CNamedPipeHandle::Read
  1062.  *
  1063.  * Revision 1.23  2004/03/10 16:09:00  jcherry
  1064.  * Reversed sense of test in unix version of CNamedPipeHandle::Listen
  1065.  *
  1066.  * Revision 1.22  2004/01/23 12:30:42  lavr
  1067.  * More explanatory stuff in posted error messages
  1068.  *
  1069.  * Revision 1.21  2003/12/02 19:16:20  ivanov
  1070.  * Fixed typo -- use x_errno instead of errno
  1071.  *
  1072.  * Revision 1.20  2003/12/02 17:50:46  ivanov
  1073.  * throw/catch strings exceptions instead char*
  1074.  *
  1075.  * Revision 1.19  2003/11/03 17:34:31  lavr
  1076.  * Print strerror() along with most syscall-related errors
  1077.  *
  1078.  * Revision 1.18  2003/10/24 16:52:38  lavr
  1079.  * Check RW bits before E bits in select()
  1080.  *
  1081.  * Revision 1.17  2003/09/25 04:41:22  lavr
  1082.  * Few minor style and performance changes
  1083.  *
  1084.  * Revision 1.16  2003/09/23 21:31:10  ucko
  1085.  * Fix typo (FD_SET for FD_ISSET in two adjacent lines)
  1086.  *
  1087.  * Revision 1.15  2003/09/23 21:07:06  lavr
  1088.  * Slightly reworked to fit in CConn_...Streams better; Wait() methods added
  1089.  *
  1090.  * Revision 1.14  2003/09/16 13:42:36  ivanov
  1091.  * Added deleting OS-specific pipe handle in the destructor
  1092.  *
  1093.  * Revision 1.13  2003/09/05 19:52:37  ivanov
  1094.  * + UNIX CNamedPipeHandle::SetSocketBufSize()
  1095.  *
  1096.  * Revision 1.12  2003/09/03 14:48:32  ivanov
  1097.  * Fix for previous commit
  1098.  *
  1099.  * Revision 1.11  2003/09/03 14:29:58  ivanov
  1100.  * Set r/w status to eIO_Success in the CNamedPipeHandle::Open/Create
  1101.  *
  1102.  * Revision 1.10  2003/09/02 19:51:17  ivanov
  1103.  * Fixed incorrect infinite timeout handling in the CNamedPipeHandle::Open()
  1104.  *
  1105.  * Revision 1.9  2003/08/28 16:03:05  ivanov
  1106.  * Use os-specific Status() function
  1107.  *
  1108.  * Revision 1.8  2003/08/25 14:41:22  lavr
  1109.  * Employ new k..Timeout constants
  1110.  *
  1111.  * Revision 1.7  2003/08/20 14:22:20  ivanov
  1112.  * Get rid of warning -- double variable declaration
  1113.  *
  1114.  * Revision 1.6  2003/08/19 21:02:12  ivanov
  1115.  * Other fix for error messages and comments.
  1116.  *
  1117.  * Revision 1.5  2003/08/19 20:52:45  ivanov
  1118.  * UNIX: Fixed a waiting method for socket connection in the
  1119.  * CNamedPipeHandle::Open() (by Anton Lavrentiev). Fixed some error
  1120.  * messages and comments. UNIX sockets can have a zero value.
  1121.  *
  1122.  * Revision 1.4  2003/08/19 14:34:43  ivanov
  1123.  * + #include <sys/time.h> for UNIX
  1124.  *
  1125.  * Revision 1.3  2003/08/18 22:53:59  vakatov
  1126.  * Fix for the platforms which are missing type 'socklen_t'
  1127.  *
  1128.  * Revision 1.2  2003/08/18 20:51:56  ivanov
  1129.  * Retry 'connect()' syscall if interrupted and allowed to restart
  1130.  * (by Anton Lavrentiev)
  1131.  *
  1132.  * Revision 1.1  2003/08/18 19:18:23  ivanov
  1133.  * Initial revision
  1134.  *
  1135.  * ===========================================================================
  1136.  */