NCBI C++ ToolKit
ncbi_namedpipe.cpp
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_namedpipe.cpp 97246 2022-06-29 13:42:59Z lavr $
2  * ===========================================================================
3  *
4  * PUBLIC DOMAIN NOTICE
5  * National Center for Biotechnology Information
6  *
7  * This software/database is a "United States Government Work" under the
8  * terms of the United States Copyright Act. It was written as part of
9  * the author's official duties as a United States Government employee and
10  * thus cannot be copyrighted. This software/database is freely available
11  * to the public for use. The National Library of Medicine and the U.S.
12  * Government have not placed any restriction on its use or reproduction.
13  *
14  * Although all reasonable efforts have been taken to ensure the accuracy
15  * and reliability of the software and data, the NLM and the U.S.
16  * Government do not and cannot warrant the performance or results that
17  * may be obtained by using this software or data. The NLM and the U.S.
18  * Government disclaim all warranties, express or implied, including
19  * warranties of performance, merchantability or fitness for any particular
20  * purpose.
21  *
22  * Please cite the author in any work or product based on this material.
23  *
24  * ===========================================================================
25  *
26  * Author: Anton Lavrentiev, Mike DiCuccio, Vladimir Ivanov
27  *
28  * File Description:
29  * Portable interprocess named pipe API for: UNIX, MS-Win
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 #include <connect/error_codes.hpp>
36 #include <connect/ncbi_util.h>
37 #include <corelib/ncbifile.hpp>
38 
39 #if defined(NCBI_OS_UNIX)
40 
42 # include <errno.h>
43 # include <unistd.h>
44 # include <sys/socket.h>
45 # include <sys/types.h>
46 
47 #elif !defined(NCBI_OS_MSWIN)
48 # error "The CNamedPipe class is supported only on Windows and Unix"
49 #endif
50 
51 
52 #define NCBI_USE_ERRCODE_X Connect_Pipe
53 
54 
55 #define NAMEDPIPE_THROW(err, errtxt) \
56  THROW0_TRACE(x_FormatError(int(err), errtxt))
57 
58 
60 
61 
62 #if defined(HAVE_SOCKLEN_T) || defined(_SOCKLEN_T)
64 #else
65 typedef int SOCK_socklen_t;
66 #endif /*HAVE_SOCKLEN_T || _SOCKLEN_T*/
67 
68 
69 //////////////////////////////////////////////////////////////////////////////
70 //
71 // Auxiliary functions
72 //
73 
74 static inline const STimeout* s_SetTimeout(const STimeout* from, STimeout* to)
75 {
76  if ( !from ) {
77  return kInfiniteTimeout;
78  }
79  to->sec = from->usec / kMicroSecondsPerSecond + from->sec;
80  to->usec = from->usec % kMicroSecondsPerSecond;
81  return to;
82 }
83 
84 
86 
87 
88 static string x_FormatError(int error, const string& message)
89 {
90  const char* errstr;
91 
92 #ifdef NCBI_OS_MSWIN
93  string errmsg;
94  if ( error ) {
95  TCHAR* tmpstr = NULL;
96  DWORD rv = ::FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
97  FORMAT_MESSAGE_FROM_SYSTEM |
98  FORMAT_MESSAGE_MAX_WIDTH_MASK |
99  FORMAT_MESSAGE_IGNORE_INSERTS,
100  NULL, (DWORD) error,
101  MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
102  (LPTSTR) &tmpstr, 0, NULL);
103  if (rv && tmpstr) {
104  errmsg = _T_CSTRING(tmpstr);
105  errstr = errmsg.c_str();
106  } else {
107  errstr = "";
108  }
109  if ( tmpstr ) {
110  ::LocalFree((HLOCAL) tmpstr);
111  }
112  } else
113 #endif /*NCBI_OS_MSWIN*/
114  errstr = 0;
115 
116  int dynamic = 0/*false*/;
117  const char* result = ::NcbiMessagePlusError(&dynamic, message.c_str(),
118  error, errstr);
119  TTempCharPtr retval(const_cast<char*> (result),
120  dynamic ? eTakeOwnership : eNoOwnership);
121  return retval.get() ? retval.get() : message;
122 }
123 
124 
125 static string s_FormatErrorMessage(const string& where, const string& what)
126 {
127  return "[CNamedPipe::" + where + "] " + what;
128 }
129 
130 
131 
132 //////////////////////////////////////////////////////////////////////////////
133 //
134 // Class CNamedPipeHandle handles forwarded requests from CNamedPipe.
135 // This class is reimplemented in a platform-specific fashion where needed.
136 //
137 
138 #if defined(NCBI_OS_MSWIN)
139 
140 
141 const unsigned long kWaitPrecision = 100; // Timeout time slice (milliseconds)
142 
143 
144 static inline bool x_IsDisconnectError(DWORD error)
145 {
146  return (error == ERROR_NO_DATA ||
147  error == ERROR_BROKEN_PIPE ||
148  error == ERROR_PIPE_NOT_CONNECTED ? true : false);
149 }
150 
151 
152 //////////////////////////////////////////////////////////////////////////////
153 //
154 // CNamedPipeHandle -- MS Windows version
155 //
156 
158 {
159 public:
160  CNamedPipeHandle(void);
162 
163  // client-side
164 
165  EIO_Status Open(const string& pipename, const STimeout* timeout,
166  size_t pipesize, CNamedPipeClient::TFlags flags);
167 
168  // server-side
169 
170  EIO_Status Create(const string& pipename, size_t pipesize);
171  EIO_Status Listen(const STimeout* timeout);
172  EIO_Status Disconnect(void);
173 
174  // common
175 
176  EIO_Status Close(bool close = true);
177  EIO_Status Read (void* buf, size_t count, size_t* n_read,
178  const STimeout* timeout);
179  EIO_Status Write(const void* buf, size_t count, size_t* n_written,
180  const STimeout* timeout);
181  EIO_Status Wait(EIO_Event event, const STimeout* timeout);
182  EIO_Status Status(EIO_Event direction) const;
183 
184 private:
185  EIO_Status x_Disconnect(bool orderly);
186  EIO_Status x_WaitForRead(const STimeout* timeout, DWORD* in_avail);
187 
188  HANDLE m_Pipe; // pipe I/O handle
189  string m_PipeName; // pipe name
190  bool m_Flushed; // false if data written
191  int m_Connected; // if connected (-1=server; 1|3=client)
192  EIO_Status m_ReadStatus; // last read status
193  EIO_Status m_WriteStatus; // last write status
194 };
195 
196 
198  : m_Pipe(INVALID_HANDLE_VALUE), m_Flushed(true), m_Connected(0),
199  m_ReadStatus(eIO_Closed), m_WriteStatus(eIO_Closed)
200 {
201  return;
202 }
203 
204 
206 {
207  Close(false);
208 }
209 
210 
211 EIO_Status CNamedPipeHandle::Open(const string& pipename,
212  const STimeout* timeout,
213  size_t /*pipesize*/,
215 {
216  EIO_Status status = eIO_Unknown;
217 
218  try {
219  if (m_Pipe != INVALID_HANDLE_VALUE) {
220  NAMEDPIPE_THROW(0,
221  "Named pipe \"" + m_PipeName
222  + "\" already open");
223  }
225 
226  // Set the base security attributes
227  SECURITY_ATTRIBUTES attr;
228  attr.nLength = sizeof(attr);
229  attr.bInheritHandle = TRUE;
230  attr.lpSecurityDescriptor = NULL;
231 
232  // Wait until either a time-out interval elapses or an instance of
233  // the specified named pipe is available for connection (that is, the
234  // pipe's server process has a pending Listen() operation on the pipe).
235 
236  // NOTE: We do not use WaitNamedPipe() here because it works
237  // incorrectly in some cases!
238  HANDLE pipe;
239 
240  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
241 
242  unsigned long x_sleep = 1;
243  for (;;) {
244  // Try to open existing pipe
245  pipe = ::CreateFile(_T_XCSTRING(pipename),
246  GENERIC_READ | GENERIC_WRITE,
247  FILE_SHARE_READ | FILE_SHARE_WRITE,
248  &attr, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
249  NULL);
250  DWORD error;
251  if (pipe != INVALID_HANDLE_VALUE) {
252  DWORD mode = PIPE_READMODE_BYTE | PIPE_NOWAIT; // non-blocking
253  if ( ::SetNamedPipeHandleState(pipe, &mode, NULL, NULL) ) {
254  break;
255  }
256  error = ::GetLastError();
257  ::CloseHandle(pipe);
258  } else
259  error = ::GetLastError();
260  // NB: "pipe" is closed at this point
261  if ((pipe == INVALID_HANDLE_VALUE
262  && error != ERROR_PIPE_BUSY) ||
263  (pipe != INVALID_HANDLE_VALUE
264  && error != ERROR_PIPE_NOT_CONNECTED)) {
265  if (pipe == INVALID_HANDLE_VALUE
266  && error == ERROR_FILE_NOT_FOUND) {
267  status = eIO_Closed;
269  return status;
270  }
271  }
273  "Named pipe \"" + pipename
274  + "\" failed to "
275  + string(pipe == INVALID_HANDLE_VALUE
276  ? "open" : "set non-blocking"));
277  }
278 
279  if ( !x_timeout ) {
280  return eIO_Timeout;
281  }
282  if (x_timeout != INFINITE) {
283  if (x_sleep > x_timeout) {
284  x_sleep = x_timeout;
285  }
286  x_timeout -= x_sleep;
287  }
288  SleepMilliSec(x_sleep);
289  x_sleep <<= 1;
290  if (x_sleep > kWaitPrecision) {
291  x_sleep = kWaitPrecision;
292  }
293  }
294  _ASSERT(pipe != INVALID_HANDLE_VALUE);
295 
296  m_Pipe = pipe;
297  m_PipeName = pipename;
298  m_Connected = 1/*client*/;
301  return eIO_Success;
302  }
303  catch (string& what) {
304  ERR_POST_X(10, s_FormatErrorMessage("Open", what));
305  }
306 
307  return status;
308 }
309 
310 
311 EIO_Status CNamedPipeHandle::Create(const string& pipename,
312  size_t pipesize)
313 {
314  EIO_Status status = eIO_Unknown;
315 
316  try {
317  if (m_Pipe != INVALID_HANDLE_VALUE) {
318  NAMEDPIPE_THROW(0,
319  "Named pipe \"" + m_PipeName
320  + "\" already exists");
321  }
323 
324  if (pipesize > numeric_limits<DWORD>::max()) {
325  NAMEDPIPE_THROW(0,
326  "Named pipe \"" + pipename
327  + "\" buffer size "
328  + NStr::NumericToString(pipesize)
329  + " too large");
330  }
331 
332  // Set the base security attributes
333  SECURITY_ATTRIBUTES attr;
334  attr.nLength = sizeof(attr);
335  attr.bInheritHandle = TRUE;
336  attr.lpSecurityDescriptor = NULL;
337 
338  // Create pipe
339  m_Pipe = ::CreateNamedPipe
340  (_T_XCSTRING(pipename), // pipe name
341  PIPE_ACCESS_DUPLEX, // read/write access
342  PIPE_TYPE_BYTE | PIPE_NOWAIT, // byte-type, non-blocking mode
343  1, // one instance only
344  (DWORD) pipesize, // output buffer size
345  (DWORD) pipesize, // input buffer size
346  INFINITE, // default client timeout
347  &attr); // security attributes
348 
349  if (m_Pipe == INVALID_HANDLE_VALUE) {
350  DWORD error = ::GetLastError();
351  if (error == ERROR_ALREADY_EXISTS) {
352  status = eIO_Closed;
353  }
355  "Named pipe \"" + pipename
356  + "\" failed to create");
357  }
358 
359  m_PipeName = pipename;
362  return eIO_Success;
363  }
364  catch (string& what) {
365  ERR_POST_X(11, s_FormatErrorMessage("Create", what));
366  }
367 
368  return status;
369 }
370 
371 
373 {
374  EIO_Status status = eIO_Unknown;
375 
376  try {
378  status = eIO_Closed;
379  NAMEDPIPE_THROW(0,
380  "Named pipe \"" + m_PipeName
381  + '"' + string(m_Pipe == INVALID_HANDLE_VALUE
382  ? " closed"
383  : " busy"));
384  }
386 
387  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
388 
389  // Wait for the client to connect, or time out.
390  // NOTE: WaitForSingleObject() does not work with pipes.
391 
392  unsigned long x_sleep = 1;
393  for (;;) {
394  if ( ::ConnectNamedPipe(m_Pipe, NULL) ) {
395  break; // client connected while within ConnectNamedPipe()
396  }
397  DWORD error = ::GetLastError();
398  if (error == ERROR_PIPE_CONNECTED) {
399  break; // client connected before ConnectNamedPipe() was called
400  }
401 
402  // NB: status == eIO_Unknown
403  if (error == ERROR_NO_DATA/*not disconnected???*/) {
404  if (x_Disconnect(false/*abort*/) == eIO_Success) {
405  continue; // try again
406  }
408  "Named pipe \"" + m_PipeName
409  + "\" still connected");
410  }
411  if (error != ERROR_PIPE_LISTENING) {
413  "Named pipe \"" + m_PipeName
414  + "\" not listening");
415  }
416 
417  if ( !x_timeout ) {
418  return eIO_Timeout;
419  }
420  if (x_timeout != INFINITE) {
421  if (x_sleep > x_timeout) {
422  x_sleep = x_timeout;
423  }
424  x_timeout -= x_sleep;
425  }
426  SleepMilliSec(x_sleep);
427  x_sleep <<= 1;
428  if (x_sleep > kWaitPrecision) {
429  x_sleep = kWaitPrecision;
430  }
431  }
432 
433  // Pipe connected
434  m_Connected = -1/*server*/;
437  return eIO_Success;
438  }
439  catch (string& what) {
440  ERR_POST_X(12, s_FormatErrorMessage("Listen", what));
441  }
442 
443  return status;
444 }
445 
446 
448 {
450  if (m_Connected && orderly
451  && !m_Flushed && !::FlushFileBuffers(m_Pipe)) {
452  NAMEDPIPE_THROW(::GetLastError(),
453  "Named pipe \"" + m_PipeName
454  + "\" failed to flush");
455  }
456  m_Flushed = true;
457  EIO_Status status = eIO_Success;
458 
459  if (m_Connected <= 0) {
460  if (!::DisconnectNamedPipe(m_Pipe)) {
461  status = eIO_Unknown;
462  if (orderly) {
463  NAMEDPIPE_THROW(::GetLastError(),
464  "Named pipe \"" + m_PipeName
465  + "\" failed to disconnect");
466  }
467  }
468  // Per documentation, another client can now connect again
469  } else {
470  (void) ::CloseHandle(m_Pipe);
472  }
473  m_Connected = 0;
474  return status;
475 }
476 
477 
479 {
480  EIO_Status status = eIO_Unknown;
481 
482  try {
484  status = eIO_Closed;
485  NAMEDPIPE_THROW(0,
486  "Named pipe \"" + m_PipeName
487  + "\" already disconnected");
488  }
489  status = x_Disconnect(true);
491  m_ReadStatus = eIO_Closed;
492  m_WriteStatus = eIO_Closed;
493  }
494  catch (string& what) {
495  ERR_POST_X(13, s_FormatErrorMessage("Disconnect", what));
496  }
497 
498  return status;
499 }
500 
501 
503 {
504  if (m_Pipe == INVALID_HANDLE_VALUE) {
506  return eIO_Closed;
507  }
508  EIO_Status status = eIO_Unknown;
509  try {
512  }
513  catch (string& what) {
514  ERR_POST_X(8, s_FormatErrorMessage("Close", what));
515  m_Flushed = true;
516  m_Connected = 0;
517  }
518  if (m_Pipe != INVALID_HANDLE_VALUE) {
519  (void) ::CloseHandle(m_Pipe);
521  }
522  m_ReadStatus = eIO_Closed;
523  m_WriteStatus = eIO_Closed;
524  return status;
525 }
526 
527 
529  DWORD* in_avail)
530 {
532 
533  *in_avail = 0;
534 
535  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
536 
537  // Wait for data from the pipe with timeout.
538  // NOTE: WaitForSingleObject() does not work with pipes.
539 
540  unsigned long x_sleep = 1;
541  for (;;) {
542  BOOL ok = ::PeekNamedPipe(m_Pipe, NULL, 0, NULL, in_avail, NULL);
543  if ( *in_avail ) {
544  if (!(m_Connected & 2)) {
545  m_Connected |= 2;
546  }
547  m_Flushed = true;
548  break;
549  }
550  if ( !ok ) {
551  // Has peer closed the connection?
552  DWORD error = ::GetLastError();
553  if ((m_Connected & 2) || error != ERROR_PIPE_NOT_CONNECTED) {
554  if ( !x_IsDisconnectError(error) ) {
556  return eIO_Unknown;
557  }
558  m_ReadStatus = eIO_Closed;
559  m_WriteStatus = eIO_Closed;
560  return eIO_Closed;
561  }
562  }
563 
564  if ( !x_timeout ) {
565  return eIO_Timeout;
566  }
567  if (x_timeout != INFINITE) {
568  if (x_sleep > x_timeout) {
569  x_sleep = x_timeout;
570  }
571  x_timeout -= x_sleep;
572  }
573  SleepMilliSec(x_sleep);
574  x_sleep <<= 1;
575  if (x_sleep > kWaitPrecision) {
576  x_sleep = kWaitPrecision;
577  }
578  }
579 
580  _ASSERT(*in_avail);
581  return eIO_Success;
582 }
583 
584 
585 EIO_Status CNamedPipeHandle::Read(void* buf, size_t count, size_t* n_read,
586  const STimeout* timeout)
587 {
588  _ASSERT(n_read && !*n_read);
589 
590  EIO_Status status = eIO_Unknown;
591 
592  try {
594  NAMEDPIPE_THROW(0,
595  "Named pipe \"" + m_PipeName
596  + '"' + string(m_Pipe == INVALID_HANDLE_VALUE
597  ? " closed"
598  : " not connected"));
599  }
600  if (m_ReadStatus == eIO_Closed) {
601  return eIO_Closed;
602  }
603  if ( !count ) {
604  return eIO_Success;
605  }
606 
607  DWORD bytes_avail;
608  if ((status = x_WaitForRead(timeout, &bytes_avail)) == eIO_Success) {
609  _ASSERT(bytes_avail);
610  // We must read only "count" bytes of data regardless of the amount
611  // available to read.
612  if (bytes_avail > count) {
613  bytes_avail = (DWORD) count;
614  }
615  BOOL ok = ::ReadFile(m_Pipe, buf, bytes_avail, &bytes_avail, NULL);
616  if ( !bytes_avail ) {
617  status = eIO_Unknown;
619  NAMEDPIPE_THROW(!ok ? ::GetLastError() : 0,
620  "Named pipe \"" + m_PipeName
621  + "\" read failed");
622  } else {
623  // NB: status == eIO_Success
625  *n_read = bytes_avail;
627  }
628  } else if (status == eIO_Timeout) {
630  } else if (status != eIO_Closed) {
631  NAMEDPIPE_THROW(::GetLastError(),
632  "Named pipe \"" + m_PipeName
633  + "\" peek failed");
634  }
635  }
636  catch (string& what) {
637  ERR_POST_X(14, s_FormatErrorMessage("Read", what));
638  }
639 
640  return status;
641 }
642 
643 
645  size_t* n_written, const STimeout* timeout)
646 
647 {
648  _ASSERT(n_written && !*n_written);
649 
650  EIO_Status status = eIO_Unknown;
651 
652  try {
654  NAMEDPIPE_THROW(0,
655  "Named pipe \"" + m_PipeName
656  + '"' + string(m_Pipe == INVALID_HANDLE_VALUE
657  ? " closed"
658  : " not connected"));
659  }
660  if (m_WriteStatus == eIO_Closed) {
661  return eIO_Closed;
662  }
663  if ( !count ) {
664  return eIO_Success;
665  }
666 
667  DWORD x_timeout = timeout ? NcbiTimeoutToMs(timeout) : INFINITE;
668  DWORD to_write = (count > numeric_limits<DWORD>::max()
670  : (DWORD) count);
671  DWORD bytes_written = 0;
672 
673  unsigned long x_sleep = 1;
674  for (;;) {
675  BOOL ok = ::WriteFile(m_Pipe, buf, to_write, &bytes_written, NULL);
676  if ( bytes_written ) {
677  if (!(m_Connected & 2)) {
678  m_Connected |= 2;
679  }
681  m_Flushed = false;
682  break;
683  }
684  if ( !ok ) {
685  DWORD error = ::GetLastError();
686  if ((m_Connected & 2) || error != ERROR_PIPE_NOT_CONNECTED) {
687  if ( x_IsDisconnectError(error) ) {
688  m_ReadStatus = eIO_Closed;
689  m_WriteStatus = eIO_Closed;
690  status = eIO_Closed;
691  } else {
693  // NB: status == eIO_Unknown
694  }
696  "Named pipe \"" + m_PipeName
697  + "\" write failed");
698  }
699  }
700 
701  if ( !x_timeout ) {
703  return eIO_Timeout;
704  }
705  if (x_timeout != INFINITE) {
706  if (x_sleep > x_timeout) {
707  x_sleep = x_timeout;
708  }
709  x_timeout -= x_sleep;
710  }
711  SleepMilliSec(x_sleep);
712  x_sleep <<= 1;
713  if (x_sleep > kWaitPrecision) {
714  x_sleep = kWaitPrecision;
715  }
716  }
717  _ASSERT(bytes_written);
718 
719  *n_written = bytes_written;
720  status = eIO_Success;
721  }
722  catch (string& what) {
723  ERR_POST_X(15, s_FormatErrorMessage("Write", what));
724  }
725 
726  return status;
727 }
728 
729 
731 {
734  "Named pipe \"" + m_PipeName + '"'
735  + string(m_Pipe == INVALID_HANDLE_VALUE
736  ? " closed"
737  : " not connected")));
738  return eIO_Unknown;
739  }
740  if (m_ReadStatus == eIO_Closed) {
741  event = (EIO_Event)(event & ~eIO_Read);
742  }
743  if (m_WriteStatus == eIO_Closed) {
744  event = (EIO_Event)(event & ~eIO_Write);
745  }
746  if (!(event & eIO_Read)) {
747  return event ? eIO_Success : eIO_Closed;
748  }
749  DWORD x_avail;
750  EIO_Status status = x_WaitForRead(timeout, &x_avail);
751  return status == eIO_Closed ? eIO_Success : status;
752 }
753 
754 
756 {
757  _ASSERT(m_Connected || (m_ReadStatus == eIO_Closed &&
758  m_WriteStatus == eIO_Closed));
759  switch ( direction ) {
760  case eIO_Read:
761  return m_ReadStatus;
762  case eIO_Write:
763  return m_WriteStatus;
764  default:
765  _TROUBLE;
766  break;
767  }
768  return eIO_InvalidArg;
769 }
770 
771 
772 #elif defined(NCBI_OS_UNIX)
773 
774 
775 //////////////////////////////////////////////////////////////////////////////
776 //
777 // CNamedPipeHandle -- Unix version
778 //
779 
780 // The maximum length the queue of pending connections may grow to
781 static const int kListenQueueSize = 64;
782 
783 class CNamedPipeHandle
784 {
785 public:
786  CNamedPipeHandle(void);
788 
789  // client-side
790 
791  EIO_Status Open(const string& pipename, const STimeout* timeout,
792  size_t pipesize, CNamedPipeClient::TFlags flags);
793 
794  // server-side
795 
796  EIO_Status Create(const string& pipename, size_t pipesize);
797  EIO_Status Listen(const STimeout* timeout);
798  EIO_Status Disconnect(void);
799 
800  // common
801 
802  EIO_Status Close(bool close = true);
803  EIO_Status Read (void* buf, size_t count, size_t* n_read,
804  const STimeout* timeout);
805  EIO_Status Write(const void* buf, size_t count, size_t* n_written,
806  const STimeout* timeout);
807  EIO_Status Wait(EIO_Event event, const STimeout* timeout);
808  EIO_Status Status(EIO_Event direction) const;
809 
810 private:
811  // Set socket I/O buffer size (dir: SO_SNDBUF, SO_RCVBUF)
812  bool x_SetSocketBufSize(int sock, size_t bufsize, int dir);
813  // Disconnect implementation
814  EIO_Status x_Disconnect(const char* where);
815 
816 private:
817  LSOCK m_LSocket; // listening socket
818  SOCK m_IoSocket; // I/O socket
819  size_t m_PipeSize; // pipe size
820  string m_PipeName; // pipe name
821 };
822 
823 
825  : m_LSocket(0), m_IoSocket(0), m_PipeSize(0)
826 {
827  return;
828 }
829 
830 
832 {
833  Close(false);
834 }
835 
836 
837 EIO_Status CNamedPipeHandle::Open(const string& pipename,
838  const STimeout* timeout,
839  size_t pipesize,
841 {
842  EIO_Status status = eIO_Unknown;
843 
844  try {
845  if (m_LSocket || m_IoSocket) {
846  NAMEDPIPE_THROW(0,
847  "Named pipe \"" + m_PipeName
848  + "\" already open");
849  }
850 
851  status = SOCK_CreateUNIX(pipename.c_str(), timeout, &m_IoSocket,
852  NULL, 0, 0/*flags*/);
853  if (status == eIO_Closed
855  return status;
856  }
857  if (status != eIO_Success) {
858  NAMEDPIPE_THROW(0,
859  "Named pipe \"" + pipename
860  + "\" failed to open UNIX socket: "
861  + string(IO_StatusStr(status)));
862  }
863  SOCK_SetTimeout(m_IoSocket, eIO_Close, timeout);
864 
865  // Set buffer size
866  if (pipesize) {
867  int fd;
868  if (SOCK_GetOSHandle(m_IoSocket, &fd, sizeof(fd)) == eIO_Success) {
869  if (!x_SetSocketBufSize(fd, pipesize, SO_SNDBUF) ||
870  !x_SetSocketBufSize(fd, pipesize, SO_RCVBUF)) {
871  int error = errno;
872  _ASSERT(error);
874  "Named pipe \"" + pipename
875  + "\" failed to set"
876  " UNIX socket buffer size "
877  + NStr::NumericToString(pipesize));
878  }
879  }
880  }
881 
882  m_PipeSize = 0/*not needed*/;
883  m_PipeName = pipename;
884  return eIO_Success;
885  }
886  catch (string& what) {
887  ERR_POST_X(10, s_FormatErrorMessage("Open", what));
888  }
889 
890  return status;
891 }
892 
893 
894 EIO_Status CNamedPipeHandle::Create(const string& pipename,
895  size_t pipesize)
896 {
897  EIO_Status status = eIO_Unknown;
898 
899  try {
900  if (m_LSocket || m_IoSocket) {
901  NAMEDPIPE_THROW(0,
902  "Named pipe \"" + m_PipeName
903  + "\" already exists");
904  }
905 
906  CDirEntry pipe(pipename);
907  switch (pipe.GetType()) {
908  case CDirEntry::eSocket:
909  pipe.Remove();
910  /*FALLTHRU*/
911  case CDirEntry::eUnknown:
912  // File does not exist
913  break;
914  default:
915  status = eIO_Unknown;
916  NAMEDPIPE_THROW(0,
917  "Named pipe path \"" + pipename
918  + "\" already exists");
919  }
920 
921  status = LSOCK_CreateUNIX(pipename.c_str(),
922  kListenQueueSize,
923  &m_LSocket, 0);
924  if (status != eIO_Success) {
925  NAMEDPIPE_THROW(0,
926  "Named pipe \"" + pipename
927  + "\" failed to create listening"
928  " UNIX socket: " + string(IO_StatusStr(status)));
929  }
930 
931  m_PipeSize = pipesize;
932  m_PipeName = pipename;
933  return eIO_Success;
934  }
935  catch (string& what) {
936  ERR_POST_X(11, s_FormatErrorMessage("Create", what));
937  }
938 
939  return status;
940 }
941 
942 
944 {
945  EIO_Status status = eIO_Unknown;
946 
947  try {
948  if (!m_LSocket || m_IoSocket) {
949  status = eIO_Closed;
950  NAMEDPIPE_THROW(0,
951  "Named pipe \"" + m_PipeName
952  + '"' + string(m_LSocket
953  ? " closed"
954  : " busy"));
955  }
956 
957  status = LSOCK_Accept(m_LSocket, timeout, &m_IoSocket);
958  if (status == eIO_Timeout) {
959  return status;
960  }
961  if (status != eIO_Success) {
962  NAMEDPIPE_THROW(0,
963  "Named pipe \"" + m_PipeName
964  + "\" failed to accept in UNIX socket: "
965  + string(IO_StatusStr(status)));
966  }
967  _ASSERT(m_IoSocket);
968 
969  // Set buffer size
970  if (m_PipeSize) {
971  int fd;
972  if (SOCK_GetOSHandle(m_IoSocket, &fd, sizeof(fd)) == eIO_Success) {
973  if (!x_SetSocketBufSize(fd, m_PipeSize, SO_SNDBUF) ||
974  !x_SetSocketBufSize(fd, m_PipeSize, SO_RCVBUF)) {
975  NAMEDPIPE_THROW(errno,
976  "Named pipe \"" + m_PipeName
977  + "\" failed to set UNIX socket buffer "
978  "size "+NStr::NumericToString(m_PipeSize));
979  }
980  }
981  }
982 
983  return eIO_Success;
984  }
985  catch (string& what) {
986  ERR_POST_X(12, s_FormatErrorMessage("Listen", what));
987  }
988 
989  return status;
990 }
991 
992 
994 {
995  // Close I/O socket
996  _ASSERT(m_IoSocket);
997  if (!where) {
998  static const STimeout kZeroTimeout = {0, 0};
999  SOCK_SetTimeout(m_IoSocket, eIO_Close, &kZeroTimeout);
1000  }
1001  EIO_Status status = SOCK_Close(m_IoSocket);
1002  m_IoSocket = 0;
1003 
1004  if (status != eIO_Success && where) {
1005  string verb(where);
1007  x_FormatError(0,
1008  "Named pipe \""
1009  + m_PipeName
1010  + "\" failed to "
1011  + NStr::ToLower
1012  (verb))));
1013  }
1014  return status;
1015 }
1016 
1017 
1019 {
1020  if ( !m_IoSocket ) {
1021  ERR_POST_X(13, s_FormatErrorMessage("Disconnect",
1022  "Named pipe \"" + m_PipeName
1023  + "\" already disconnected"));
1024  return eIO_Closed;
1025  }
1026  return x_Disconnect("Disconnect");
1027 }
1028 
1029 
1031 {
1032  if (!m_LSocket && !m_IoSocket) {
1033  return eIO_Closed;
1034  }
1035  // Close listening socket
1036  if ( m_LSocket ) {
1037  (void) LSOCK_Close(m_LSocket);
1038  m_LSocket = 0;
1039  }
1040  // Disconnect if connected
1041  return m_IoSocket ? x_Disconnect(close ? "Close" : 0) : eIO_Success;
1042 }
1043 
1044 
1045 EIO_Status CNamedPipeHandle::Read(void* buf, size_t count, size_t* n_read,
1046  const STimeout* timeout)
1047 {
1048  _ASSERT(n_read && !*n_read);
1049 
1050  EIO_Status status = eIO_Unknown;
1051 
1052  try {
1053  if ( !m_IoSocket ) {
1054  NAMEDPIPE_THROW(0,
1055  "Named pipe \"" + m_PipeName
1056  + '"' + string(m_LSocket
1057  ? " not connected"
1058  : " closed"));
1059  }
1060  if ( !count ) {
1061  return eIO_Success;
1062  }
1063 
1064  _VERIFY(SOCK_SetTimeout(m_IoSocket, eIO_Read, timeout) == eIO_Success);
1065  status = SOCK_Read(m_IoSocket, buf, count, n_read,
1066  eIO_ReadPlain);
1067  if (status != eIO_Success) {
1068  NAMEDPIPE_THROW(0,
1069  "Named pipe \"" + m_PipeName
1070  + "\" read failed: "
1071  + string(IO_StatusStr(status)));
1072  }
1073  }
1074  catch (string& what) {
1075  ERR_POST_X(14, s_FormatErrorMessage("Read", what));
1076  }
1077 
1078  return status;
1079 }
1080 
1081 
1082 EIO_Status CNamedPipeHandle::Write(const void* buf, size_t count,
1083  size_t* n_written, const STimeout* timeout)
1084 
1085 {
1086  _ASSERT(n_written && !*n_written);
1087 
1088  EIO_Status status = eIO_Unknown;
1089 
1090  try {
1091  if ( !m_IoSocket ) {
1092  NAMEDPIPE_THROW(0,
1093  "Named pipe \"" + m_PipeName
1094  + '"' + string(m_LSocket
1095  ? " not connected"
1096  : " closed"));
1097  }
1098  if ( !count ) {
1099  return eIO_Success;
1100  }
1101 
1102  _VERIFY(SOCK_SetTimeout(m_IoSocket, eIO_Write, timeout)== eIO_Success);
1103  status = SOCK_Write(m_IoSocket, buf, count, n_written,
1104  eIO_WritePlain);
1105  if (status != eIO_Success) {
1106  NAMEDPIPE_THROW(0,
1107  "Named pipe \"" + m_PipeName
1108  + "\" write failed: "
1109  + string(IO_StatusStr(status)));
1110  }
1111  }
1112  catch (string& what) {
1113  ERR_POST_X(15, s_FormatErrorMessage("Write", what));
1114  }
1115 
1116  return status;
1117 }
1118 
1119 
1120 EIO_Status CNamedPipeHandle::Wait(EIO_Event event, const STimeout* timeout)
1121 {
1122  if ( !m_IoSocket ) {
1123  ERR_POST_X(9, s_FormatErrorMessage("Wait",
1124  "Named pipe \"" + m_PipeName + '"'
1125  + (m_LSocket
1126  ? " not connected"
1127  : " closed")));
1128  return eIO_Unknown;
1129  }
1130  return SOCK_Wait(m_IoSocket, event, timeout);
1131 }
1132 
1133 
1135 {
1136  return !m_IoSocket ? eIO_Closed : SOCK_Status(m_IoSocket, direction);
1137 }
1138 
1139 
1140 bool CNamedPipeHandle::x_SetSocketBufSize(int sock, size_t bufsize, int dir)
1141 {
1142  int bs_old = 0;
1143  int bs_new = (int) bufsize;
1144  SOCK_socklen_t bs_len = (SOCK_socklen_t) sizeof(bs_old);
1145 
1146  if (::getsockopt(sock, SOL_SOCKET, dir, &bs_old, &bs_len) == 0
1147  && bs_new > bs_old) {
1148  if (::setsockopt(sock, SOL_SOCKET, dir, &bs_new, bs_len) != 0) {
1149  return false;
1150  }
1151  }
1152  return true;
1153 }
1154 
1155 
1156 #endif /* NCBI_OS_UNIX | NCBI_OS_MSWIN */
1157 
1158 
1159 
1160 //////////////////////////////////////////////////////////////////////////////
1161 //
1162 // CNamedPipe
1163 //
1164 
1165 
1166 CNamedPipe::CNamedPipe(size_t pipesize)
1167  : m_PipeSize(pipesize),
1168  m_OpenTimeout(0), m_ReadTimeout(0), m_WriteTimeout(0)
1169 {
1171 }
1172 
1173 
1175 {
1176  Close();
1177  delete m_NamedPipeHandle;
1178 }
1179 
1180 
1182 {
1184  return m_NamedPipeHandle->Close();
1185 }
1186 
1187 
1188 EIO_Status CNamedPipe::Read(void* buf, size_t count, size_t* n_read)
1189 {
1191  size_t x_read;
1192  if ( !n_read ) {
1193  n_read = &x_read;
1194  }
1195  *n_read = 0;
1196  if (count && !buf) {
1197  return eIO_InvalidArg;
1198  }
1199  return m_NamedPipeHandle->Read(buf, count, n_read, m_ReadTimeout);
1200 }
1201 
1202 
1203 EIO_Status CNamedPipe::Write(const void* buf, size_t count, size_t* n_written)
1204 {
1206  size_t x_written;
1207  if ( !n_written ) {
1208  n_written = &x_written;
1209  }
1210  *n_written = 0;
1211  if (count && !buf) {
1212  return eIO_InvalidArg;
1213  }
1214  return m_NamedPipeHandle->Write(buf, count, n_written, m_WriteTimeout);
1215 }
1216 
1217 
1219 {
1221  if (timeout == kDefaultTimeout) {
1222  _TROUBLE;
1223  return eIO_InvalidArg;
1224  }
1225  switch (event) {
1226  case eIO_Read:
1227  case eIO_Write:
1228  case eIO_ReadWrite:
1229  break;
1230  default:
1231  _TROUBLE;
1232  return eIO_InvalidArg;
1233  }
1234  return m_NamedPipeHandle->Wait(event, timeout);
1235 }
1236 
1237 
1239 {
1241  switch (direction) {
1242  case eIO_Read:
1243  case eIO_Write:
1244  break;
1245  default:
1246  _TROUBLE;
1247  return eIO_InvalidArg;
1248  }
1249  return m_NamedPipeHandle->Status(direction);
1250 }
1251 
1252 
1254 {
1256  if (timeout == kDefaultTimeout) {
1257  return eIO_Success;
1258  }
1259  switch ( event ) {
1260  case eIO_Open:
1262  break;
1263  case eIO_Read:
1265  break;
1266  case eIO_Write:
1268  break;
1269  case eIO_ReadWrite:
1272  break;
1273  default:
1274  _TROUBLE;
1275  return eIO_InvalidArg;
1276  }
1277  return eIO_Success;
1278 }
1279 
1280 
1282 {
1284  switch ( event ) {
1285  case eIO_Open:
1286  return m_OpenTimeout;
1287  case eIO_Read:
1288  return m_ReadTimeout;
1289  case eIO_Write:
1290  return m_WriteTimeout;
1291  default:
1292  _TROUBLE;
1293  break;
1294  }
1295  return kDefaultTimeout;
1296 }
1297 
1298 
1299 void CNamedPipe::x_SetName(const string& pipename)
1300 {
1301 #ifdef NCBI_OS_MSWIN
1302  static const char kSeparators[] = ":/\\";
1303 #else
1304  static const char kSeparators[] = "/";
1305 #endif
1306  if (pipename.find_first_of(kSeparators) != NPOS) {
1307  m_PipeName = pipename;
1308  return;
1309  }
1310 
1311 #if defined(NCBI_OS_MSWIN)
1312  m_PipeName = "\\\\.\\pipe\\" + pipename;
1313 #elif defined(NCBI_OS_UNIX)
1314  struct stat st;
1315 
1316  const char* pipedir = "/var/tmp";
1317  if (::stat(pipedir, &st) != 0 || !S_ISDIR(st.st_mode)
1318  || ::access(pipedir, W_OK) != 0) {
1319  pipedir = "/tmp";
1320  if (::stat(pipedir, &st) != 0 || !S_ISDIR(st.st_mode)
1321  || ::access(pipedir, W_OK) != 0) {
1322  pipedir = ".";
1323  }
1324  }
1325  m_PipeName = string(pipedir) + '/' + pipename;
1326 #else
1327  m_PipeName = pipename;
1328 #endif
1329 }
1330 
1331 
1332 
1333 //////////////////////////////////////////////////////////////////////////////
1334 //
1335 // CNamedPipeClient
1336 //
1337 
1339  : CNamedPipe(pipesize)
1340 {
1342  m_IsClientSide = true;
1343 }
1344 
1345 
1346 CNamedPipeClient::CNamedPipeClient(const string& pipename,
1347  const STimeout* timeout,
1348  size_t pipesize,
1350  : CNamedPipe(pipesize)
1351 {
1352  m_IsClientSide = true;
1353  Open(pipename, timeout, flags);
1354 }
1355 
1356 
1357 EIO_Status CNamedPipeClient::Open(const string& pipename,
1358  const STimeout* timeout,
1359  size_t pipesize,
1361 {
1363  if (pipesize) {
1364  m_PipeSize = pipesize;
1365  }
1366  x_SetName(pipename);
1367 
1368  SetTimeout(eIO_Open, timeout);
1370  m_PipeSize, flags);
1371 }
1372 
1373 
1374 
1375 //////////////////////////////////////////////////////////////////////////////
1376 //
1377 // CNamedPipeServer
1378 //
1379 
1380 
1382  : CNamedPipe(pipesize)
1383 {
1385  m_IsClientSide = false;
1386 }
1387 
1388 
1389 CNamedPipeServer::CNamedPipeServer(const string& pipename,
1390  const STimeout* timeout,
1391  size_t pipesize)
1392  : CNamedPipe(pipesize)
1393 {
1394  m_IsClientSide = false;
1395  Create(pipename, timeout);
1396 }
1397 
1398 
1399 EIO_Status CNamedPipeServer::Create(const string& pipename,
1400  const STimeout* timeout,
1401  size_t pipesize)
1402 {
1404  if (pipesize) {
1405  m_PipeSize = pipesize;
1406  }
1407  x_SetName(pipename);
1408 
1409  SetTimeout(eIO_Open, timeout);
1411 }
1412 
1413 
1415 {
1418 }
1419 
1420 
1422 {
1424  return m_NamedPipeHandle->Disconnect();
1425 }
1426 
1427 
AutoPtr –.
Definition: ncbimisc.hpp:401
CDirEntry –.
Definition: ncbifile.hpp:262
EIO_Status Status(EIO_Event direction) const
EIO_Status Open(const string &pipename, const STimeout *timeout, size_t pipesize, CNamedPipeClient::TFlags flags)
EIO_Status x_WaitForRead(const STimeout *timeout, DWORD *in_avail)
EIO_Status Close(bool close=true)
EIO_Status Read(void *buf, size_t count, size_t *n_read, const STimeout *timeout)
EIO_Status Listen(const STimeout *timeout)
EIO_Status m_WriteStatus
EIO_Status x_Disconnect(bool orderly)
EIO_Status Disconnect(void)
EIO_Status Create(const string &pipename, size_t pipesize)
EIO_Status Wait(EIO_Event event, const STimeout *timeout)
EIO_Status Write(const void *buf, size_t count, size_t *n_written, const STimeout *timeout)
EIO_Status m_ReadStatus
CNamedPipe –.
static uch flags
int close(int fd)
Definition: connection.cpp:45
#define true
Definition: bool.h:35
int BOOL
Definition: sybdb.h:150
element_type * get(void) const
Get pointer.
Definition: ncbimisc.hpp:469
@ eTakeOwnership
An object can take ownership of another.
Definition: ncbi_types.h:136
@ eNoOwnership
No ownership is assumed.
Definition: ncbi_types.h:135
string
Definition: cgiapp.hpp:690
#define NULL
Definition: ncbistd.hpp:225
#define _VERIFY(expr)
Definition: ncbidbg.hpp:161
#define ERR_POST_X(err_subcode, message)
Error posting with default error code and given error subcode.
Definition: ncbidiag.hpp:550
@ eSocket
Socket (UNIX only)
Definition: ncbifile.hpp:789
@ eUnknown
Unknown type.
Definition: ncbifile.hpp:794
CNamedPipeClient(size_t pipesize=0)
Default constructor.
const STimeout * m_OpenTimeout
Timeouts.
EIO_Status Create(const string &pipename, const STimeout *timeout=kDefaultTimeout, size_t pipesize=0)
Create a server-side pipe.
CNamedPipeServer(size_t pipesize=0)
Default constructor.
EIO_Status Wait(EIO_Event event, const STimeout *timeout)
Wait for I/O readiness in the pipe.
EIO_Status Status(EIO_Event direction) const
Return (for the specified "direction"): eIO_Closed – if the pipe is closed for I/O; eIO_Timeout – if ...
const STimeout * GetTimeout(EIO_Event event) const
Get the pipe I/O timeout (or NULL, if the timeout is infinite).
bool m_IsClientSide
client/server-side pipe
STimeout m_ReadTimeoutValue
storage for m_ReadTimeout
string m_PipeName
pipe name
EIO_Status Close(void)
Close pipe connection.
EIO_Status Listen(void)
Listen on a pipe for new client connection.
void x_SetName(const string &pipename)
STimeout m_OpenTimeoutValue
storage for m_OpenTimeout
size_t m_PipeSize
pipe size
virtual ~CNamedPipe()
Destructor.
unsigned int TFlags
CNamedPipe(size_t pipe_size=0)
Constructor.
const STimeout * m_WriteTimeout
eIO_Write
EIO_Status Read(void *buf, size_t count, size_t *n_read=0)
Read data from the pipe.
STimeout m_WriteTimeoutValue
storage for m_WriteTimeout
const STimeout * m_ReadTimeout
eIO_Read
EIO_Status SetTimeout(EIO_Event event, const STimeout *timeout)
Specify timeout for the pipe I/O (see Open|Read|Write functions).
CNamedPipeHandle * m_NamedPipeHandle
OS-specific handle.
EIO_Status Open(const string &pipename, const STimeout *timeout=kDefaultTimeout, size_t pipesize=0, TFlags flags=0)
Open a client-side pipe connection.
EIO_Status Disconnect(void)
Disconnect the client.
EIO_Status Write(const void *buf, size_t count, size_t *n_written=0)
Write data to the pipe.
@ fNoLogIfClosed
Do not log error if server end is closed.
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
EIO_Status LSOCK_CreateUNIX(const char *path, unsigned short backlog, LSOCK *lsock, TSOCK_Flags flags)
Definition: ncbi_socket.c:6527
EIO_Status SOCK_SetTimeout(SOCK sock, EIO_Event event, const STimeout *timeout)
Specify timeout for the connection I/O (see SOCK_[Read|Write|Close]()).
Definition: ncbi_socket.c:7195
EIO_Status SOCK_Close(SOCK sock)
Close the SOCK handle, and destroy all relevant internal data.
Definition: ncbi_socket.c:6852
EIO_Status LSOCK_Accept(LSOCK lsock, const STimeout *timeout, SOCK *sock)
[SERVER-side] Accept connection from a client.
Definition: ncbi_socket.c:6539
EIO_Status SOCK_Read(SOCK sock, void *buf, size_t size, size_t *n_read, EIO_ReadMethod how)
Read/peek up to "size" bytes from "sock" to a buffer pointed to by "buf".
Definition: ncbi_socket.c:7271
EIO_Status SOCK_Status(SOCK sock, EIO_Event direction)
Return low-level socket I/O status of *last* socket operation.
Definition: ncbi_socket.c:7460
EIO_Status SOCK_Wait(SOCK sock, EIO_Event event, const STimeout *timeout)
Block on the socket until either the specified "event" is available or "timeout" expires (if "timeout...
Definition: ncbi_socket.c:6954
EIO_Status SOCK_Write(SOCK sock, const void *data, size_t size, size_t *n_written, EIO_WriteMethod how)
Write "size" bytes of "data" to "sock".
Definition: ncbi_socket.c:7487
EIO_Status LSOCK_Close(LSOCK lsock)
[SERVER-side] Close the listening socket, destroy relevant internal data.
Definition: ncbi_socket.c:6556
EIO_Status SOCK_CreateUNIX(const char *path, const STimeout *timeout, SOCK *sock, const void *data, size_t size, TSOCK_Flags flags)
Definition: ncbi_socket.c:6674
EIO_Status SOCK_GetOSHandle(SOCK sock, void *handle_buf, size_t handle_size)
Same as SOCK_GetOSHandleEx(sock, handle_buf, handle_size, eNoOwnership).
Definition: ncbi_socket.c:7745
#define NPOS
Definition: ncbistr.hpp:133
#define _T_CSTRING(x)
Definition: ncbistr.hpp:182
#define _T_XCSTRING(x)
Definition: ncbistr.hpp:181
static enable_if< is_arithmetic< TNumeric >::value||is_convertible< TNumeric, Int8 >::value, string >::type NumericToString(TNumeric value, TNumToStringFlags flags=0, int base=10)
Convert numeric value to string.
Definition: ncbistr.hpp:673
static string & ToLower(string &str)
Convert string to lower case – string& version.
Definition: ncbistr.cpp:405
const long kMicroSecondsPerSecond
Number of microseconds in one second.
Definition: ncbitime.hpp:91
#define kInfiniteTimeout
Definition: ncbi_types.h:82
unsigned long NcbiTimeoutToMs(const STimeout *timeout)
Definition: ncbi_types.c:40
EIO_Status
I/O status.
Definition: ncbi_core.h:132
unsigned int usec
microseconds (modulo 1,000,000)
Definition: ncbi_types.h:78
const char * IO_StatusStr(EIO_Status status)
Get the text form of an enum status value.
Definition: ncbi_core.c:56
unsigned int sec
seconds
Definition: ncbi_types.h:77
const char * NcbiMessagePlusError(int *dynamic, const char *message, int error, const char *descr)
Add current "error" (and maybe its description) to the message: <message>[ {error=[[<error>][,...
Definition: ncbi_util.c:335
EIO_Event
I/O event (or direction).
Definition: ncbi_core.h:118
#define kDefaultTimeout
Definition: ncbi_types.h:81
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ eIO_Unknown
unknown I/O error (likely fatal but can retry)
Definition: ncbi_core.h:139
@ eIO_InvalidArg
bad argument / parameter value(s) supplied
Definition: ncbi_core.h:137
@ eIO_ReadPlain
read readily available data only, wait if none
Definition: ncbi_core.h:90
@ eIO_WritePlain
write as much as possible, report back how much
Definition: ncbi_core.h:101
@ eIO_Write
write
Definition: ncbi_core.h:121
@ eIO_ReadWrite
eIO_Read | eIO_Write (also, eCONN_OnFlush)
Definition: ncbi_core.h:122
@ eIO_Open
also serves as no-event indicator in SOCK_Poll
Definition: ncbi_core.h:119
@ eIO_Close
also serves as an error indicator in SOCK_Poll
Definition: ncbi_core.h:123
@ eIO_Read
read
Definition: ncbi_core.h:120
#define INVALID_HANDLE_VALUE
A value for an invalid file handle.
Definition: mdb.c:389
#define HANDLE
An abstraction for a file handle.
Definition: mdb.c:383
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
Definition of all error codes used in connect library (xconnect.lib, xconnext.lib etc).
int socklen_t
Definition: config.h:95
char * buf
mdb_mode_t mode
Definition: lmdb++.h:38
static const STimeout kZeroTimeout
#define NAMEDPIPE_THROW(err, errtxt)
static string x_FormatError(int error, const string &message)
AutoPtr< char, CDeleter< char > > TTempCharPtr
static string s_FormatErrorMessage(const string &where, const string &what)
const unsigned long kWaitPrecision
static const STimeout * s_SetTimeout(const STimeout *from, STimeout *to)
int SOCK_socklen_t
static bool x_IsDisconnectError(DWORD error)
Portable interprocess named pipe API for: UNIX, MS-Win.
#define TRUE
bool replacment for C indicating true.
Definition: ncbi_std.h:97
void SleepMilliSec(unsigned long ml_sec, EInterruptOnSignal onsignal=eRestartOnSignal)
Defines classes: CDirEntry, CFile, CDir, CSymLink, CMemoryFile, CFileUtil, CFileLock,...
T max(T x_, T y_)
static PCRE2_SIZE bufsize
Definition: pcre2grep.c:237
#define count
static SLJIT_INLINE sljit_ins st(sljit_gpr r, sljit_s32 d, sljit_gpr x, sljit_gpr b)
char TCHAR
Definition: sqltypes.h:91
TCHAR * LPTSTR
Definition: sqltypes.h:111
unsigned int DWORD
Definition: sqltypes.h:98
Timeout structure.
Definition: ncbi_types.h:76
#define _TROUBLE
#define _ASSERT
else result
Definition: token2.c:20
Modified on Fri Sep 20 14:57:48 2024 by modify_doxy.py rev. 669887