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

Go to the SVN repository for this file.

1 /* $Id: ncbi_conn_streambuf.cpp 101111 2023-10-31 16:05:57Z 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  * Authors: Anton Lavrentiev, Denis Vakatov
27  *
28  * File Description:
29  * CONN-based C++ stream buffer
30  *
31  */
32 
33 #include <ncbi_pch.hpp>
34 #include "ncbi_conn_streambuf.hpp"
35 #include <corelib/ncbidbg.hpp>
36 #include <corelib/ncbi_limits.hpp>
38 #include <connect/error_codes.hpp>
39 #include <stdlib.h> // free()
40 
41 #define NCBI_USE_ERRCODE_X Connect_Stream
42 
43 
45 
46 
47 /*ARGSUSED*/
48 static inline bool x_IsThrowable(EIO_Status status)
49 {
50  _ASSERT(status != eIO_Success);
51 #if (defined(NCBI_COMPILER_GCC) && NCBI_COMPILER_VERSION < 700) \
52  || defined(NCBI_COMPILER_ANY_CLANG)
53  // For C++ STLs that have a bug that sentry ctor does not include try/catch
54  // so exceptions leak instead of setting badbit as the standard requires.
55  // https://bugs.llvm.org/show_bug.cgi?id=48912
56  // https://github.com/llvm/llvm-project/issues/48256
57  return false;
58 #else
59  return status != eIO_Timeout ? true : false;
60 #endif
61 }
62 
63 
64 static inline bool x_CheckConn(CONN conn)
65 {
66  if (conn)
67  return true;
68 #if !defined(NCBI_COMPILER_GCC) || NCBI_COMPILER_GCC >= 700
69  NCBI_IO_CHECK(eIO_Closed);
70 #endif // !NCBI_COMPILER_GCC || NCBI_COMPILER_VERSION>=700
71  return false;
72 }
73 
74 
75 string CConn_Streambuf::x_Message(const char* method,
76  const char* message,
77  EIO_Status status,
78  const STimeout* timeout)
79 {
80  const char*
81  type = m_Conn ? CONN_GetType(m_Conn) : 0;
82  unique_ptr<char, void (*)(void*)>
84  string result("[CConn_Streambuf::");
85  result += method;
86  result += '(';
87  if (type) {
88  result += type;
89  if (text)
90  result += "; ";
91  }
92  if (text) {
93  _ASSERT(*text.get());
94  result += text.get();
95  }
96  result += ")] ";
97  result += message;
98  result += ": ";
99  if (status == eIO_Success)
100  status = m_Status;
101  _ASSERT(status != eIO_Success);
102  result += IO_StatusStr(status);
103  if (status == eIO_Timeout && timeout/*!=kInfiniteTimeout*/) {
104  if (timeout != kDefaultTimeout) {
105  char x_timeout[40];
106  ::sprintf(x_timeout, "[%u.%06us]",
107  timeout->usec / 1000000 + timeout->sec,
108  timeout->usec % 1000000);
109  result += x_timeout;
110  } else
111  result += "(default)";
112  }
113  return result;
114 }
115 
116 
118  EIO_Status status,
119  const STimeout* timeout,
120  size_t buf_size,
122  CT_CHAR_TYPE* ptr,
123  size_t size)
124  : m_Conn(0), x_Connector(connector),
125  m_WriteBuf(0), m_ReadBuf(&x_Buf), m_BufSize(1), m_Status(status),
126  m_Tie(false), m_Close(true), m_CbValid(false), m_Initial(false),
127  x_Buf(), x_GPos((CT_OFF_TYPE)(ptr ? size : 0)), x_PPos((CT_OFF_TYPE)size)
128 {
129  if (!connector) {
130  if (m_Status == eIO_Success)
132  ERR_POST_X(2, x_Message("CConn_Streambuf", "NULL connector"));
133  //NCBI_IO_CHECK(m_Status); /*NB: should be able to throw here*/
134  return;
135  }
136  //
137  // CAUTION! May not throw from this point on in this ctor!
138  //
139  // This ctor must not throw from here on because otherwise it would either:
140  // a. leak memory allocated to the passed CONNECTOR (see the construction
141  // of CConn_IOStream-based classes); or
142  // b. if CONNECTOR's destroy method was called here to cleanup, that would
143  // have chained some of the CONNECTOR's cleanup callback(s) as well, yet
144  // with the callback data (user_data), which might still be unreleased
145  // by guard objects (e.g. smart pointers) that hold the ownership until
146  // after the construction's completion; thus, exception throwing would
147  // make those guards attempt to destroy user_data for the second time!
148  // So we just hold the error status and rely on CConn_IOStream to return a
149  // bad stream; and later to cleanup everything by a proper destructor.
150  //
151  if (!(flgs & (CConn_IOStream::fConn_Untie |
153  m_Tie = true;
154  }
155  if (m_Status != eIO_Success ||
157  | (m_Tie ? 0 : flgs & fCONN_Untie), &m_Conn))
158  != eIO_Success) {
159  ERR_POST_X(3, x_Message("CConn_Streambuf", "CONN_Create() failed"));
160  _ASSERT(!m_Conn && !connector->meta && !connector->next);
161  return;
162  }
163  _ASSERT(m_Conn);
164  x_Init(timeout, buf_size, flgs, ptr, size);
165 }
166 
167 
169  bool close,
170  const STimeout* timeout,
171  size_t buf_size,
173  CT_CHAR_TYPE* ptr,
174  size_t size)
175  : m_Conn(conn), x_Connector(0),
176  m_WriteBuf(0), m_ReadBuf(&x_Buf), m_BufSize(1), m_Status(eIO_Success),
177  m_Tie(false), m_Close(close), m_CbValid(false), m_Initial(false),
178  x_Buf(), x_GPos((CT_OFF_TYPE)(ptr ? size : 0)), x_PPos((CT_OFF_TYPE)size)
179 {
180  if (!m_Conn) {
182  ERR_POST_X(1, x_Message("CConn_Streambuf", "NULL connection"));
184  return;
185  }
186  if (!(flgs & (CConn_IOStream::fConn_Untie |
188  m_Tie = true;
189  }
190  x_Init(timeout, buf_size, flgs, ptr, size);
191 }
192 
193 
195 {
196  Close();
197 
198  _ASSERT(!m_Conn && !m_CbValid);
199 
202 
203  delete[] m_WriteBuf;
204 }
205 
206 
208 {
209  return direction == eIO_Close ? m_Status
210  : m_Conn ? CONN_Status(m_Conn, direction) : eIO_Closed;
211 }
212 
213 
214 void CConn_Streambuf::x_Init(const STimeout* timeout, size_t buf_size,
216  CT_CHAR_TYPE* ptr, size_t size)
217 {
219 
220  if (timeout != kDefaultTimeout) {
224  }
225 
230  buf_size = 0;
231  }
232  unique_ptr<CT_CHAR_TYPE[]> wbp;
233  if (buf_size) {
234  wbp.reset
235  (new
236  CT_CHAR_TYPE[buf_size
239  ? 0 : 1)]);
240  CT_CHAR_TYPE* write_buf = wbp.get();
242  m_BufSize = buf_size;
244  buf_size = 0;
246  m_ReadBuf = write_buf + buf_size;
247 #if 0/*unnecessary*/
249  write_buf = 0;
250 #endif
251  setp(write_buf, write_buf + buf_size);
252  }/* else
253  setp(0, 0) */
254 
255  if (ptr) {
256  m_Initial = true;
257  setg(ptr, ptr, ptr + size); // Initial get area
258  } else
259  setg(m_ReadBuf, m_ReadBuf, m_ReadBuf); // Empty get area
260  _ASSERT(m_ReadBuf && m_BufSize); // NB: See ctor
261 
262  SCONN_Callback cb;
263  cb.func = x_OnClose; /* NCBI_FAKE_WARNING: WorkShop */
264  cb.data = this;
266  m_CbValid = true;
267 
268  if (!(flgs & CConn_IOStream::fConn_DelayOpen)) {
269  SOCK unused;
270  // NB: CONN_Write(0 bytes) could have caused the same effect
271  (void) CONN_GetSOCK(m_Conn, &unused); // Prompt CONN to actually open
273  ERR_POST_X(17, x_Message("CConn_Streambuf",
274  "Failed to open", m_Status, timeout));
275  if (!x_Connector)
277  }
278  }
279 
280  if (m_Status == eIO_Success)
281  m_WriteBuf = wbp.release();
282 }
283 
284 
286 {
287  _ASSERT(m_Conn);
288 
289  size_t count = (size_t)(egptr() - gptr());
290  if (!count)
291  return eIO_Success;
292 
293  EIO_Status status = CONN_Pushback(m_Conn, gptr(), count);
294  if (status == eIO_Success)
295  gbump(int(count));
296  return status;
297 }
298 
299 
301 {
302  _ASSERT(m_Conn);
303 
304  EIO_Status status = eIO_Success;
305  bool cb_valid = m_CbValid;
306  m_CbValid = false;
307 
308  // push any still unread data from the buffer back to the device
309  if (!m_Close && close && !m_Initial) {
310  EIO_Status x_status = x_Pushback();
311  if (x_status != eIO_Success && x_status != eIO_NotSupported) {
312  status = m_Status = x_status;
313  ERR_POST_X(13, x_Message("Close",
314  "CONN_Pushback() failed"));
315  }
316  }
317  setg(0, 0, 0);
318 
319  // flush only if some data pending
320  if (pbase() < pptr()) {
321  EIO_Status x_status = CONN_Status(m_Conn, eIO_Write);
322  if (x_status != eIO_Success) {
323  status = m_Status = x_status;
325  _ALWAYS_TRACE(x_Message("Close",
326  "Cannot finalize implicitly"
327  ", data loss may result"));
328  }
329  } else {
330  bool synced = false;
331  try {
332  if (sync() == 0)
333  synced = true;
334  }
335  catch (...) {
336  _ASSERT(!synced);
337  }
338  if (!synced)
339  _VERIFY((status = m_Status) != eIO_Success);
340  }
341  }
342  setp(0, 0);
343 
344  CONN conn = m_Conn;
345  x_Connector = 0;
346  m_Conn = 0; // NB: no re-entry
347 
348  if (close) {
349  // Here when not called from the close callback x_OnClose
350  if (cb_valid) {
351  SCONN_Callback cb;
352  // Restore the original callback
354  if (cb.func != x_OnClose || cb.data != this) {
355  // Restore again if our callback was replaced
357  }
358  }
359  if (m_Close) {
360  STimeout xtmo;
361  const STimeout* ctmo = CONN_GetTimeout(conn, eIO_Close);
362  if (ctmo != kInfiniteTimeout && ctmo != kDefaultTimeout) {
363  xtmo = *ctmo;
364  ctmo = &xtmo;
365  }
366  if ((m_Status = CONN_Close(conn)) != eIO_Success) {
367  _ALWAYS_TRACE(x_Message("Close",
368  "CONN_Close() failed",
369  m_Status, ctmo));
370  if (status == eIO_Success)
371  status = m_Status;
372  }
373  }
374  } else if (cb_valid && m_Cb.func) {
375  // In x_OnClose callback here: upcall the original callback
377  if (cbstat != eIO_Success)
378  status = cbstat;
379  }
380 
381  return status;
382 }
383 
384 
385 // x_OnClose() is called when CONN gets closed from outside this class
388  void* data)
389 {
390  CConn_Streambuf* sb = reinterpret_cast<CConn_Streambuf*>(data);
391  _ASSERT(type == eCONN_OnClose && sb && conn);
392  _ASSERT(!sb->m_Conn || sb->m_Conn == conn);
393  return sb->m_Conn ? sb->x_Close(false) : eIO_Success;
394 }
395 
396 
398 {
399  if (buf || buf_size) {
400  NCBI_THROW(CConnException, eConn,
401  "CConn_Streambuf::setbuf() only allowed with (0, 0)");
402  }
403 
404  if (m_Conn) {
405  EIO_Status status;
406  if (!m_Initial && (status = x_Pushback()) != eIO_Success) {
407  ERR_POST_X(11, Critical << x_Message("setbuf",
408  "Read data pending",
409  status));
410  }
411  if (x_Sync() != 0) {
412  ERR_POST_X(12, Critical << x_Message("setbuf",
413  "Write data pending"));
414  }
415  }
416  setp(0, 0);
417 
418  delete[] m_WriteBuf;
419  m_WriteBuf = 0;
420 
421  m_ReadBuf = &x_Buf;
422  m_BufSize = 1;
423 
424  if (!m_Conn || !m_Initial)
425  setg(m_ReadBuf, m_ReadBuf, m_ReadBuf);
426  return this;
427 }
428 
429 
431 {
432  if (!x_CheckConn(m_Conn))
433  return CT_EOF;
434 
435  size_t n_written;
436  size_t n_towrite = (size_t)(pptr() - pbase());
437 
438  if (n_towrite) {
439  // send buffer
440  do {
441  m_Status = CONN_Write(m_Conn, pbase(),
442  n_towrite, &n_written, eIO_WritePlain);
443  _ASSERT(n_written <= n_towrite);
444  if (!n_written) {
446  break;
447  }
448  // update buffer content (get rid of the data just sent)
449  memmove(pbase(), pbase() + n_written, n_towrite - n_written);
450  x_PPos += (CT_OFF_TYPE) n_written;
451  pbump(-int(n_written));
452 
453  // store char
454  if (!CT_EQ_INT_TYPE(c, CT_EOF))
455  return sputc(CT_TO_CHAR_TYPE(c));
456  n_towrite -= n_written;
457  } while (n_towrite && m_Status == eIO_Success);
458  if (n_towrite) {
460  ERR_POST_X(4, x_Message("overflow",
461  "CONN_Write() failed", m_Status,
462  m_Status != eIO_Timeout ? 0 :
464  if (x_IsThrowable(m_Status))
466  return CT_EOF;
467  }
468  } else if (!CT_EQ_INT_TYPE(c, CT_EOF)) {
469  // send char
471  m_Status = CONN_Write(m_Conn, &b, 1, &n_written, eIO_WritePlain);
472  _ASSERT(n_written <= 1);
473  if (!n_written) {
475  ERR_POST_X(5, x_Message("overflow",
476  "CONN_Write(1) failed", m_Status,
477  m_Status != eIO_Timeout ? 0 :
479  if (x_IsThrowable(m_Status))
481  return CT_EOF;
482  }
483  x_PPos += (CT_OFF_TYPE) 1;
484  return c;
485  }
486 
488  if ((m_Status = CONN_Flush(m_Conn)) != eIO_Success) {
489  ERR_POST_X(9, x_Message("overflow",
490  "CONN_Flush() failed", m_Status,
491  m_Status != eIO_Timeout ? 0 :
493  if (x_IsThrowable(m_Status))
495  return CT_EOF;
496  }
497  return CT_NOT_EOF(CT_EOF);
498 }
499 
500 
501 streamsize CConn_Streambuf::xsputn(const CT_CHAR_TYPE* buf, streamsize m)
502 {
503  if (!x_CheckConn(m_Conn) || m < 0)
504  return 0;
505 
508  size_t n = (size_t) m;
509  size_t n_written = 0;
510  size_t x_written;
511 
512  do {
513  if (pbase()) {
514  if (n && pbase() + n < epptr()) {
515  // would entirely fit into the buffer not causing an overflow
516  x_written = (size_t)(epptr() - pptr());
517  if (x_written > n)
518  x_written = n;
519  if (x_written) {
520  memcpy(pptr(), buf, x_written);
521  pbump(int(x_written));
522  n_written += x_written;
523  n -= x_written;
524  if (!n)
525  return (streamsize) n_written;
526  buf += x_written;
527  }
528  }
529 
530  size_t x_towrite = (size_t)(pptr() - pbase());
531  if (x_towrite) {
532  m_Status = CONN_Write(m_Conn, pbase(), x_towrite,
533  &x_written, eIO_WritePlain);
534  _ASSERT(x_written <= x_towrite);
535  if (!x_written) {
537  ERR_POST_X(6, x_Message("xsputn",
538  "CONN_Write() failed", m_Status,
539  m_Status != eIO_Timeout ? 0 :
541  break;
542  }
543  memmove(pbase(), pbase() + x_written, x_towrite - x_written);
544  x_PPos += (CT_OFF_TYPE) x_written;
545  pbump(-int(x_written));
546  continue;
547  }
548  }
549 
551  m_Status = CONN_Write(m_Conn, buf, n, &x_written, eIO_WritePlain);
552  _ASSERT(x_written <= n);
553  if (!x_written && n) {
555  ERR_POST_X(7, x_Message("xsputn",
556  "CONN_Write(direct) failed", m_Status,
557  m_Status != eIO_Timeout ? 0 :
559  break;
560  }
561  x_PPos += (CT_OFF_TYPE) x_written;
562  n_written += x_written;
563  n -= x_written;
564  if (!n)
565  return (streamsize) n_written;
566  buf += x_written;
567  } while (m_Status == eIO_Success);
568 
569  _ASSERT(n && m_Status != eIO_Success);
570 
571  if (pbase()) {
572  x_written = (size_t)(epptr() - pptr());
573  if (x_written) {
574  if (x_written > n)
575  x_written = n;
576  memcpy(pptr(), buf, x_written);
577  n_written += x_written;
578  pbump(int(x_written));
579  }
580  }
581 
582  if (!n_written && x_IsThrowable(m_Status))
584  return (streamsize) n_written;
585 }
586 
587 
589 {
590  _ASSERT(gptr() >= egptr());
591 
592  if (!x_CheckConn(m_Conn))
593  return CT_EOF;
594 
595  // flush output buffer, if tied up to it
596  if (m_Tie && x_Sync() != 0)
597  return CT_EOF;
598 
599 #ifdef NCBI_COMPILER_MIPSPRO
600  if (m_MIPSPRO_ReadsomeGptrSetLevel && m_MIPSPRO_ReadsomeGptr != gptr())
601  return CT_EOF;
602  m_MIPSPRO_ReadsomeGptr = (CT_CHAR_TYPE*)(-1L);
603 #endif /*NCBI_COMPILER_MIPSPRO*/
604 
605  // read from connection
606  size_t n_read;
608  &n_read, eIO_ReadPlain);
609  _ASSERT(n_read <= m_BufSize);
610  if (!n_read) {
612  if (m_Status != eIO_Closed) {
613  ERR_POST_X(8, x_Message("underflow",
614  "CONN_Read() failed", m_Status,
615  m_Status != eIO_Timeout ? 0 :
617  if (x_IsThrowable(m_Status))
619  }
620  return CT_EOF;
621  }
622 
623  // update input buffer with the data just read
624  m_Initial = false;
625  x_GPos += (CT_OFF_TYPE) n_read;
626  setg(m_ReadBuf, m_ReadBuf, m_ReadBuf + n_read);
627 
628  return CT_TO_INT_TYPE(*m_ReadBuf);
629 }
630 
631 
632 streamsize CConn_Streambuf::x_Read(CT_CHAR_TYPE* buf, streamsize m)
633 {
634  _ASSERT(m_Conn);
635 
636  // flush output buffer, if tied up to it
637  if (m_Tie && x_Sync() != 0)
638  return 0;
639 
640  if (m < 0)
641  return 0;
642 
644  size_t n = (size_t) m;
645  size_t n_read;
646 
647  if (n) {
648  // first, read from the memory buffer
649  n_read = (size_t)(egptr() - gptr());
650  if (n_read > n)
651  n_read = n;
652  if (buf)
653  memcpy(buf, gptr(), n_read);
654  gbump(int(n_read));
655  n -= n_read;
656  if (!n)
657  return (streamsize) n_read;
658  if (buf)
659  buf += n_read;
660  } else
661  n_read = 0;
662 
663  do {
664  // next, read from the connection
665  size_t x_toread = !buf || (n && n < m_BufSize) ? m_BufSize : n;
666  CT_CHAR_TYPE* x_buf = !buf || ( n < m_BufSize) ? m_ReadBuf : buf;
667  size_t x_read;
668 
669  m_Status = CONN_Read(m_Conn, x_buf, x_toread,
670  &x_read, eIO_ReadPlain);
671  _ASSERT(x_read <= x_toread);
672  if (!x_read) {
673  _ASSERT(!x_toread || m_Status != eIO_Success);
674  if (m_Status != eIO_Success && m_Status != eIO_Closed) {
675  ERR_POST_X(10, x_Message("xsgetn",
676  "CONN_Read() failed", m_Status,
677  m_Status != eIO_Timeout ? 0 :
679  }
680  break;
681  }
682  m_Initial = false;
683  x_GPos += (CT_OFF_TYPE) x_read;
684  // satisfy "usual backup condition", see standard: 27.5.2.4.3.13
685  if (x_buf == m_ReadBuf) {
686  size_t xx_read = x_read;
687  if (x_read > n)
688  x_read = n;
689  if (buf)
690  memcpy(buf, m_ReadBuf, x_read);
691  setg(m_ReadBuf, m_ReadBuf + x_read, m_ReadBuf + xx_read);
692  } else {
693  _ASSERT(x_read <= n);
694  size_t xx_read = x_read > m_BufSize ? m_BufSize : x_read;
695  memcpy(m_ReadBuf, buf + x_read - xx_read, xx_read);
696  setg(m_ReadBuf, m_ReadBuf + xx_read, m_ReadBuf + xx_read);
697  }
698  n_read += x_read;
699  if (m_Status != eIO_Success)
700  break;
701  if (buf)
702  buf += x_read;
703  n -= x_read;
704  } while (n);
705 
706  if (!n_read && m_Status != eIO_Closed && x_IsThrowable(m_Status))
708  return (streamsize) n_read;
709 }
710 
711 
712 streamsize CConn_Streambuf::xsgetn(CT_CHAR_TYPE* buf, streamsize m)
713 {
714  _ASSERT(egptr() >= gptr());
715 
716  return x_CheckConn(m_Conn) ? x_Read(buf, m) : 0;
717 }
718 
719 
721 {
722 #define POLLING &CConn_IOStream::kZeroTimeout
723 
724  _ASSERT(gptr() >= egptr());
725 
726  if (!x_CheckConn(m_Conn))
727  return -1L;
728 
729  // flush output buffer, if tied up to it
730  if (m_Tie)
731  x_Sync();
732 
733  const STimeout* tmo;
734  const STimeout* timeout = CONN_GetTimeout(m_Conn, eIO_Read);
735  if (timeout == kDefaultTimeout) {
736  // HACK * HACK * HACK
737  tmo = ((SMetaConnector*) m_Conn)->default_timeout;
738  _ASSERT(tmo != kDefaultTimeout);
739  } else
740  tmo = timeout;
741 
742  if (!tmo)
744  size_t x_read;
746  if (!tmo)
748  _ASSERT(x_read > 0 || m_Status != eIO_Success);
749 
750  if (!x_read) {
751  switch (m_Status) {
752  case eIO_Timeout:
753  if (!tmo || (tmo->sec | tmo->usec))
754  break;
755  /*FALLTHRU*/
756  case eIO_Closed:
757  return -1L; // EOF
758  case eIO_Success:
759  _ASSERT(0);
760  /*FALLTHRU*/
761  default:
762  if (x_IsThrowable(m_Status))
764  break;
765  }
766  return 0; // no data available immediately
767  }
768 
769  m_Initial = false;
770  setg(m_ReadBuf, m_ReadBuf, m_ReadBuf + x_read);
771  x_GPos += x_read;
772  return x_read;
773 
774 #undef POLLING
775 }
776 
777 
779 {
781  return -1;
782  _ASSERT(pbase() == pptr());
783  return 0;
784 }
785 
786 
788  IOS_BASE::seekdir whence,
789  IOS_BASE::openmode which)
790 {
791  if (whence == IOS_BASE::cur && off == 0) {
792  // tellg()/tellp() support
793  switch (which) {
794  case IOS_BASE::in:
795  return x_GetGPos();
796  case IOS_BASE::out:
797  return x_GetPPos();
798  default:
799  break;
800  }
801  } else if (which == IOS_BASE::in
802  && ((whence == IOS_BASE::cur && (off > 0)) ||
803  (whence == IOS_BASE::beg && (off -= x_GetGPos()) >= 0))){
804  if (m_Conn && x_Read(0, (streamsize) off) == (streamsize) off)
805  return x_GetGPos();
806  }
807  return (CT_POS_TYPE)((CT_OFF_TYPE)(-1L));
808 }
809 
810 
812  streamsize size,
813  bool push)
814 {
815  if (!m_Conn)
816  return eIO_Closed;
817 
818  m_Status = x_Pushback();
819  if (m_Status == eIO_Success && size)
820  m_Status = CONN_Pushback(m_Conn, data, size);
821  if (m_Status != eIO_Success) {
822  ERR_POST_X(14, x_Message("Pushback",
823  "CONN_Pushback() failed"));
824  } else if (push)
825  x_PPos += (CT_OFF_TYPE) size;
826 
827  return m_Status;
828 }
829 
830 
832 {
833  if (!m_Conn)
834  return eIO_InvalidArg;
835 
836  if (timeout == kDefaultTimeout) {
837  // HACK * HACK * HACK
838  timeout = ((SMetaConnector*) m_Conn)->default_timeout;
839  _ASSERT(timeout != kDefaultTimeout);
840  if (!timeout)
841  timeout = &g_NcbiDefConnTimeout;
842  }
843 
844  // try to flush buffer first
845  if (pbase() < pptr()) {
846  const STimeout* x_tmo = CONN_GetTimeout(m_Conn, eIO_Write);
848  bool synced = false;
849  try {
850  if (sync() == 0)
851  synced = true;
852  }
853  catch (CIO_Exception& _DEBUG_ARG(ex)) {
854  _ASSERT(!synced && EIO_Status(ex.GetErrCode()) == m_Status);
855  }
856  catch (...) {
858  throw;
859  }
861 
862  if (!synced) {
864  ERR_POST_X(15, (m_Status != eIO_Timeout || !timeout ||
865  (timeout->sec | timeout->usec) ? Error : Trace)
866  << x_Message("Fetch",
867  "Failed to flush",
868  m_Status, timeout));
869  }
870  }
871 
872  // check if input is already pending
873  if (gptr() < egptr())
874  return eIO_Success;
875 
876  // now wait for some input
877  EIO_Status status = CONN_Wait(m_Conn, eIO_Read, timeout);
878  if (status != eIO_Success) {
879  ERR_POST_X(16, (status != eIO_Timeout || !timeout ? Error :
880  (timeout->sec | timeout->usec) ? Warning : Trace)
881  << x_Message("Fetch",
882  "CONN_Wait() failed",
883  status, timeout));
884  }
885  return status;
886 }
887 
888 
889 const char* CConnException::GetErrCodeString(void) const
890 {
891  switch (GetErrCode()) {
892  case eConn: return "eConn";
893  default: break;
894  }
896 }
897 
898 
899 const char* CIO_Exception::GetErrCodeString(void) const
900 {
901  switch (GetErrCode()) {
902  case eTimeout: return "eIO_Timeout";
903  case eInterrupt: return "eIO_Interrupt";
904  case eInvalidArg: return "eIO_InvalidArg";
905  case eNotSupported: return "eIO_NotSupported";
906  case eUnknown: return "eIO_Unknown";
907  case eClosed: return "eIO_Closed";
908  default: break;
909  }
911 }
912 
913 
#define true
Definition: bool.h:35
#define false
Definition: bool.h:36
Generic CONN exception.
EIO_Status Close(void)
CConn_Streambuf(CONNECTOR connector, EIO_Status status, const STimeout *timeout, size_t buf_size, CConn_IOStream::TConn_Flags flags, CT_CHAR_TYPE *ptr, size_t size)
EIO_Status Status(EIO_Event direction) const
virtual CT_INT_TYPE underflow(void)
streamsize x_Read(CT_CHAR_TYPE *buf, streamsize n)
void x_Init(const STimeout *timeout, size_t buf_size, CConn_IOStream::TConn_Flags flags, CT_CHAR_TYPE *ptr, size_t size)
CT_POS_TYPE x_GetPPos(void)
CT_CHAR_TYPE * m_WriteBuf
string x_Message(const char *method, const char *message, EIO_Status status=eIO_Success, const STimeout *timeout=kInfiniteTimeout)
virtual int sync(void)
virtual CT_INT_TYPE overflow(CT_INT_TYPE c)
virtual streamsize xsgetn(CT_CHAR_TYPE *buf, streamsize n)
static EIO_Status x_OnClose(CONN conn, TCONN_Callback type, void *data)
EIO_Status Fetch(const STimeout *timeout)
virtual CT_POS_TYPE seekoff(CT_OFF_TYPE off, IOS_BASE::seekdir whence, IOS_BASE::openmode which=IOS_BASE::in|IOS_BASE::out)
Only seekoff(0, IOS_BASE::cur, *) to obtain current position, and input skip-forward are permitted: s...
EIO_Status x_Close(bool close)
CT_CHAR_TYPE * m_ReadBuf
virtual streamsize xsputn(const CT_CHAR_TYPE *buf, streamsize n)
EIO_Status Pushback(const CT_CHAR_TYPE *data, streamsize size, bool push)
Push the specified data "data" of size "size" back into the underlying connection CONN.
virtual CNcbiStreambuf * setbuf(CT_CHAR_TYPE *buf, streamsize buf_size)
Only setbuf(0, 0) is allowed to make I/O unbuffered, other parameters will cause an exception thrown ...
virtual streamsize showmanyc(void)
EIO_Status x_Pushback(void) THROWS_NONE
CT_POS_TYPE x_GetGPos(void)
I/O exception.
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
int close(int fd)
Definition: connection.cpp:45
std::ofstream out("events_result.xml")
main entry point for tests
static int type
Definition: getdata.c:31
virtual const char * GetErrCodeString(void) const override
virtual const char * GetErrCodeString(void) const override
#define NCBI_IO_CHECK(errnum)
Check EIO_Status, throw an exception if something is wrong.
@ eConn
Unspecified connect problem.
unsigned int TConn_Flags
bitwise OR of EConn_Flag
@ fConn_ReadUnbuffered
read buffer NOT to be alloc'd
@ fConn_WriteUnbuffered
write buffer NOT 2.b. alloc'd
@ fConn_DelayOpen
do not force CONN open in ctor
@ fConn_Untie
do not flush before reading
EIO_Status CONN_CreateEx(CONNECTOR connector, TCONN_Flags flags, CONN *conn)
Create all data necessary to establish a new connection (merely bind it to the specified CONNECTOR).
EIO_Status CONN_Read(CONN conn, void *buf, size_t size, size_t *n_read, EIO_ReadMethod how)
EIO_Status CONN_Flush(CONN conn)
Explicitly flush connection from any pending data written by CONN_Write().
EIO_Status CONN_SetCallback(CONN conn, ECONN_Callback type, const SCONN_Callback *new_cb, SCONN_Callback *old_cb)
unsigned int TCONN_Callback
EIO_Status CONN_Write(CONN conn, const void *buf, size_t size, size_t *n_written, EIO_WriteMethod how)
CONNECTOR next
linked list
void * data
data to pass to the callback as its last arg
EIO_Status CONN_SetTimeout(CONN conn, EIO_Event event, const STimeout *timeout)
Specify timeout for the connection I/O, including "Connect" (aka "Open") and "Close".
char * CONN_Description(CONN conn)
Return a human-readable description of the connection as a character '\0'-terminated string.
FDestroy destroy
destroys handle, can be NULL
EIO_Status CONN_Wait(CONN conn, EIO_Event event, const STimeout *timeout)
Block on the connection until it becomes available for either reading or writing (depending on "event...
SMetaConnector * meta
back link to original meta
const char * CONN_GetType(CONN conn)
Get verbal representation of connection type as a character string.
EIO_Status CONN_Close(CONN conn)
Close the connection and destroy all relevant internal data.
EIO_Status CONN_GetSOCK(CONN conn, SOCK *sock)
Get an underlying SOCK handle for connection that is implemented as a socket.
const STimeout * CONN_GetTimeout(CONN conn, EIO_Event event)
Retrieve current timeout, return NULL(kInfiniteTimeout) if it is infinite.
const STimeout g_NcbiDefConnTimeout
DEF_CONN_TIMEOUT as STimeout.
Definition: ncbi_connutil.c:54
EIO_Status CONN_Status(CONN conn, EIO_Event dir)
Obtain status of the last I/O operation.
EIO_Status CONN_Pushback(CONN conn, const void *data, size_t size)
Push "size" bytes from the buffer "data" back into connection.
FCONN_Callback func
function address to call on the event
@ eCONN_OnClose
NB: CONN has been flushed prior to the call.
@ fCONN_Untie
do not call flush method prior to reading
@ fCONN_Supplement
supplement I/O with extended return codes
#define _ALWAYS_TRACE(message)
Define macros to support debugging.
Definition: ncbidbg.hpp:65
#define _DEBUG_ARG(arg)
Definition: ncbidbg.hpp:134
#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
void Critical(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1203
void Error(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1197
#define NCBI_THROW(exception_class, err_code, message)
Generic macro to throw an exception, given the exception class, error code and message string.
Definition: ncbiexpt.hpp:704
void Trace(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1179
void Warning(CExceptionArgs_Base &args)
Definition: ncbiexpt.hpp:1191
#define THROWS_NONE
Do not use 'throw' dynamic exception specification for C++11 compilers.
Definition: ncbiexpt.hpp:74
virtual const char * GetErrCodeString(void) const
Get error code interpreted as text.
Definition: ncbiexpt.cpp:444
uint64_t Uint8
8-byte (64-bit) unsigned integer
Definition: ncbitype.h:105
#define END_NCBI_SCOPE
End previously defined NCBI scope.
Definition: ncbistl.hpp:103
#define BEGIN_NCBI_SCOPE
Define ncbi namespace.
Definition: ncbistl.hpp:100
#define CT_OFF_TYPE
Definition: ncbistre.hpp:731
#define CT_TO_CHAR_TYPE
Definition: ncbistre.hpp:735
#define CT_EOF
Definition: ncbistre.hpp:732
#define CT_TO_INT_TYPE
Definition: ncbistre.hpp:734
#define CT_INT_TYPE
Definition: ncbistre.hpp:728
#define CT_EQ_INT_TYPE
Definition: ncbistre.hpp:736
#define CT_NOT_EOF
Definition: ncbistre.hpp:733
#define CT_POS_TYPE
Definition: ncbistre.hpp:730
#define CT_CHAR_TYPE
Definition: ncbistre.hpp:729
IO_PREFIX::streambuf CNcbiStreambuf
Portable alias for streambuf.
Definition: ncbistre.hpp:143
#define kInfiniteTimeout
Definition: ncbi_types.h:82
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
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_NotSupported
operation is not supported or is not available
Definition: ncbi_core.h:138
@ eIO_Success
everything is fine, no error occurred
Definition: ncbi_core.h:133
@ 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
Definition of all error codes used in connect library (xconnect.lib, xconnext.lib etc).
char * buf
yy_size_t n
static void text(MDB_val *v)
Definition: mdb_dump.c:62
list< Ts... > push
const struct ncbi::grid::netcache::search::fields::SIZE size
#define POLLING
static bool x_IsThrowable(EIO_Status status)
static bool x_CheckConn(CONN conn)
NCBI C++ auxiliary debug macros.
T max(T x_, T y_)
std::istream & in(std::istream &in_, double &x_)
#define memmove(a, b, c)
Connector specification.
Standard set of connector methods to handle a connection (corresponding connectors are also in here),...
Timeout structure.
Definition: ncbi_types.h:76
Definition: type.c:6
#define _ASSERT
else result
Definition: token2.c:20
void free(voidpf ptr)
Modified on Wed Dec 06 07:15:14 2023 by modify_doxy.py rev. 669887