NCBI C++ ToolKit
ncbi_connection.c
Go to the documentation of this file.

Go to the SVN repository for this file.

1 /* $Id: ncbi_connection.c 97270 2022-06-30 15:04:46Z 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: Denis Vakatov, Anton Lavrentiev
27  *
28  * File Description:
29  * Generic API to open and handle connection to an abstract service.
30  * For more detail, see in "ncbi_connection.h".
31  *
32  */
33 
34 #include "ncbi_priv.h"
35 #include "ncbi_socketp.h"
37 #include <stdlib.h>
38 #include <string.h>
39 
40 #define NCBI_USE_ERRCODE_X Connect_Conn
41 
42 
43 #define CONNECTION_MAGIC 0xEFCDAB09
44 
45 
46 /***********************************************************************
47  * INTERNAL
48  ***********************************************************************/
49 
50 /* Standard logging message
51  */
52 #define CONN_LOG_EX(subcode, func_name, level, message, status) \
53  do { \
54  const char* ststr = ((EIO_Status) status != eIO_Success \
55  ? IO_StatusStr((EIO_Status) status) \
56  : ""); \
57  const char* ctype = (conn && conn->meta.get_type \
58  ? conn->meta.get_type(conn->meta.c_get_type) \
59  : 0); \
60  char* descr = (conn && conn->meta.descr \
61  ? conn->meta.descr(conn->meta.c_descr) \
62  : 0); \
63  char stbuf[80]; \
64  if ((EIO_Status) status == eIO_Timeout && timeout) { \
65  assert(timeout != kDefaultTimeout); \
66  sprintf(stbuf, "%s[%u.%06u]", ststr, \
67  timeout->usec / 1000000 + timeout->sec, \
68  timeout->usec % 1000000); \
69  assert(strlen(stbuf) < sizeof(stbuf)); \
70  ststr = stbuf; \
71  } \
72  CORE_LOGF_X(subcode, level, \
73  ("[CONN_" #func_name "(%s%s%s)] %s%s%s", \
74  ctype && *ctype ? ctype : "UNDEF", \
75  descr && *descr ? "; " : "", descr ? descr : "", \
76  message, \
77  ststr && *ststr ? ": " : "", \
78  ststr ? ststr : "")); \
79  if (descr) \
80  free(descr); \
81  } while (0)
82 
83 #define CONN_LOG(s_c, f_n, lvl, msg) CONN_LOG_EX(s_c, f_n, lvl, msg, status)
84 
85 #if 0
86 # define CONN_CALLTRACE(func_name) \
87  do { \
88  static const STimeout* timeout = 0/*dummy*/; \
89  char handle[80]; \
90  sprintf(handle, "0x%p", conn); \
91  CONN_LOG_EX(0, func_name, eLOG_Trace, handle, 0); \
92  } while (0)
93 #else
94 # define CONN_CALLTRACE(func_name) /*((void) 0)*/
95 #endif /*0*/
96 
97 
98 /* Standard macros to verify that the connection handle is not NULL and valid.
99  * NB: "retval" must be either a valid EIO_Status or 0 (no status logged)
100  */
101 #define CONN_NOT_NULL_EX(subcode, func_name, retval) \
102  do { \
103  CONN_CALLTRACE(func_name); \
104  if (!conn) { \
105  static const STimeout* timeout = 0/*dummy*/; \
106  CONN_LOG_EX(subcode, func_name, eLOG_Error, \
107  "NULL connection handle", retval); \
108  assert(conn); \
109  return retval; \
110  } \
111  if (conn->magic != CONNECTION_MAGIC) { \
112  static const STimeout* timeout = 0/*dummy*/; \
113  CONN_LOG_EX(subcode, func_name, eLOG_Critical, \
114  "Corrupt connection handle", 0); \
115  assert(0); \
116  return retval; \
117  } \
118  } while (0)
119 
120 #define CONN_NOT_NULL(s_c, f_n) CONN_NOT_NULL_EX(s_c, f_n, eIO_InvalidArg)
121 
122 #ifdef _DEBUG
123 # define CONN_TRACE(f_n, msg) CONN_LOG(0, f_n, eLOG_Trace, msg)
124 #else
125 # define CONN_TRACE(f_n, msg) /*((void) 0)*/
126 #endif /*_DEBUG*/
127 
128 
129 /* Private flags, MUST NOT cross with ECONN_Flags defined in the header
130  */
132  fCONN_Flush = 1024 /* auto-flush was successful */
133 };
134 
135 
136 /* Connection state
137  */
138 typedef enum {
139  eCONN_Unusable = -1, /* iff !conn->meta.list */
140  eCONN_Closed = 0, /* "Open" can be attempted */
141  eCONN_Open = 1, /* operational state (I/O allowed) */
142  eCONN_Bad = 2, /* non-operational (I/O not allowed) */
143  eCONN_Cancel = 3, /* NB: |= eCONN_Open, user-canceled */
144  eCONN_Corrupt = 5 /* NB: |= eCONN_Open, non-operational */
146 
147 
148 /* Connection internal data.
149  *
150  * NOTE: "meta" *must* come first! (see ncbi_conn_streambuf.cpp)
151  */
152 typedef struct SConnectionTag {
153  SMetaConnector meta; /* VTable of operations and list */
154 
155  ECONN_State state; /* connection state */
156  TCONN_Flags flags; /* connection flags */
157  EIO_Status r_status; /* I/O status of last read */
158  EIO_Status w_status; /* I/O status of last write */
159 
160  BUF buf; /* storage for peek/pushback data */
161 
162  void* data; /* user data pointer */
163 
164  /* "[o|r|w|c]_timeout" is either 0 (kInfiniteTimeout), kDefaultTimeout
165  (to use connector-specific one), or points to "[oo|rr|ww|cc]_timeout";
166  timeouts are "as is" (may be not normalized) for performance reasons */
167  const STimeout* o_timeout; /* timeout on open */
168  const STimeout* r_timeout; /* timeout on read */
169  const STimeout* w_timeout; /* timeout on write */
170  const STimeout* c_timeout; /* timeout on close */
171  STimeout oo_timeout; /* storage for "o_timeout" */
172  STimeout rr_timeout; /* storage for "r_timeout" */
173  STimeout ww_timeout; /* storage for "w_timeout" */
174  STimeout cc_timeout; /* storage for "c_timeout" */
175 
176  TNCBI_BigCount r_pos; /* read and ... */
177  TNCBI_BigCount w_pos; /* ... write positions */
178 
179  SCONN_Callback cb[CONN_N_CALLBACKS+1]; /* +1 includes dummy no-callback */
180 
181  unsigned int magic; /* magic cookie for integrity checks */
183 
184 
186 {
187  size_t idx;
188  switch (type) {
189  case eCONN_OnClose:
190  idx = 0;
191  break;
192  case eCONN_OnRead:
193  idx = 1;
194  break;
195  case eCONN_OnWrite:
196  idx = 2;
197  break;
198  case eCONN_OnFlush:
199  idx = 3;
200  break;
201  case eCONN_OnTimeout:
202  idx = 4;
203  break;
204  case eCONN_OnOpen:
205  idx = 5;
206  break;
207  default:
208  /* to flag an API error */
209  idx = CONN_N_CALLBACKS;
210  break;
211  }
212  return idx;
213 }
214 
215 
216 static EIO_Status x_Callback(CONN conn, ECONN_Callback type, unsigned int flag)
217 {
218  size_t idx = x_CB2IDX(type);
219  FCONN_Callback func;
220  void* data;
221  EIO_Status status;
222 
223  assert(!flag || (type == eCONN_OnTimeout
224  && (flag | eIO_ReadWrite) == eIO_ReadWrite));
225  assert(conn && idx < CONN_N_CALLBACKS);
226  if (!(func = conn->cb[idx].func))
228  data = conn->cb[idx].data;
229  status = (*func)(conn, (TCONN_Callback) type | flag, data);
230  if (status == eIO_Interrupt)
231  conn->state = eCONN_Cancel;
232  return status;
233 }
234 
235 
236 static EIO_Status x_Flush(CONN conn, const STimeout* timeout,
237  int/*bool*/ isflush)
238 {
239  assert(isflush || !(conn->flags & fCONN_Flush));
240  for (;;) {
241  EIO_Status status;
242  if ((status = x_Callback(conn, eCONN_OnFlush, 0)) != eIO_Success)
243  return status;
244 
245  if (!conn->meta.flush)
246  break;
247  /* call current connector's "FLUSH" method */
248  if (timeout == kDefaultTimeout)
249  timeout = conn->meta.default_timeout;
250  assert(timeout != kDefaultTimeout);
251  status = conn->meta.flush(conn->meta.c_flush, timeout);
252  if (isflush)
253  conn->w_status = status;
254  if (status == eIO_Success)
255  break;
256 
257  if (status == eIO_Timeout)
259  if (status != eIO_Success)
260  return status;
261  }
262  conn->flags |= fCONN_Flush;
263  return eIO_Success;
264 }
265 
266 
267 static EIO_Status x_ReInit(CONN conn, CONNECTOR connector, int/*bool*/ close)
268 {
269  const STimeout* timeout = 0;
270  EIO_Status status;
271  CONNECTOR x_conn;
272 
273  assert(!close || !connector);
274  assert(!conn->meta.list == !(conn->state != eCONN_Unusable));
275 
276  /* flush connection first, if open & not flushed */
277  status = conn->meta.list
278  && conn->state == eCONN_Open
279  && !(conn->flags & fCONN_Flush)
280  ? x_Flush(conn, conn->c_timeout, 0/*no-flush*/) : eIO_Success;
281 
282  for (x_conn = conn->meta.list; x_conn; x_conn = x_conn->next) {
283  if (x_conn == connector) {
284  assert(!close);
285  /* reinit with the same and the only connector - allowed */
286  if (!x_conn->next && x_conn == conn->meta.list)
287  break;
288  status = eIO_NotSupported;
289  CONN_LOG(4, ReInit, eLOG_Critical, "Partial re-init not allowed");
290  conn->state = eCONN_Corrupt;
291  return status;
292  }
293  }
294 
295  if (conn->meta.list) {
296  /* erase unread data */
297  BUF_Erase(conn->buf);
298 
299  if (!x_conn)
300  status = x_Callback(conn, eCONN_OnClose, 0);
301  /* else: re-init with same connector does not cause the callback */
302 
303  if (conn->state & eCONN_Open) {
304  /* call current connector's "CLOSE" method */
305  if (conn->meta.close) {
306  EIO_Status closed;
307  timeout = (conn->c_timeout == kDefaultTimeout
308  ? conn->meta.default_timeout
309  : conn->c_timeout);
310  assert(timeout != kDefaultTimeout);
311  closed = conn->meta.close(conn->meta.c_close, timeout);
312  if (closed != eIO_Success)
313  status = closed;
314  }
315  if (status != eIO_Success
316  && (status != eIO_Closed || connector)) {
317  if (close) {
318  CONN_LOG(3, Close,
319  connector ? eLOG_Error : eLOG_Warning,
320  "Connection failed to close properly");
321  } else {
322  CONN_LOG(3, ReInit, eLOG_Error,
323  "Connection failed to close properly");
324  }
325  }
326  }
327 
328  if (!x_conn) {
329  /* entirely new connector - remove the old connector stack first */
330  METACONN_Remove(&conn->meta, 0); /* NB: always succeeds with "0" */
331  assert(!conn->meta.list);
332  memset(&conn->meta, 0, sizeof(conn->meta));
333  conn->state = eCONN_Unusable;
334  } else if (status != eIO_Success) {
335  conn->state = eCONN_Bad;
336  return status;
337  } else
338  conn->state = eCONN_Closed;
339  } else if (!connector)
340  status = eIO_Closed;
341 
342  if (!x_conn && connector) {
343  assert(conn->state == eCONN_Unusable);
344  /* setup the new connector */
345  if ((status = METACONN_Insert(&conn->meta, connector)) != eIO_Success)
346  return status;
347  assert(conn->meta.list);
348  conn->state = eCONN_Closed;
349  assert(conn->meta.default_timeout != kDefaultTimeout);
350  }
351 
352  assert(conn->state != eCONN_Open && conn->state != eCONN_Bad);
353  return status;
354 }
355 
356 
358 {
359  const STimeout* timeout = 0;
360  EIO_Status status;
361 
362  switch (conn->state) {
363  case eCONN_Unusable:
364  return eIO_InvalidArg;
365  case eCONN_Cancel:
366  return eIO_Interrupt;
367  case eCONN_Bad:
368  case eCONN_Corrupt:
369  return eIO_Unknown;
370  default:
371  break;
372  }
373  assert(conn->state == eCONN_Closed && conn->meta.list);
374  conn->r_pos = 0;
375  conn->w_pos = 0;
376 
377  if (conn->meta.open) {
378  for (;;) {
379  int/*bool*/ nocb = !conn->cb[x_CB2IDX(eCONN_OnOpen)].func;
380  if ((status = x_Callback(conn, eCONN_OnOpen, 0)) != eIO_Success)
381  break;
382 
383  /* call current connector's "OPEN" method */
384  timeout = (conn->o_timeout == kDefaultTimeout
385  ? conn->meta.default_timeout
386  : conn->o_timeout);
387  assert(timeout != kDefaultTimeout);
388  status = conn->meta.open(conn->meta.c_open, timeout);
389  if (status != eIO_Timeout || nocb)
390  break;
391 
392  /* eCONN_OnTimeout gets called only if eCONN_OnOpen was there */
394  if (status != eIO_Success)
395  break;
396  }
397  } else
398  status = eIO_NotSupported;
399  if (status == eIO_Success) {
400  conn->flags |= fCONN_Flush;
401  conn->r_status = eIO_Success;
402  conn->w_status = eIO_Success;
403  conn->state = eCONN_Open;
404  } else {
405  CONN_LOG(5, Open, eLOG_Error, "Failed to open connection");
406  if (conn->state == eCONN_Closed)
407  conn->state = eCONN_Bad;
408  }
409  return status == eIO_Closed ? eIO_Unknown : status;
410 }
411 
412 
413 /***********************************************************************
414  * EXTERNAL
415  ***********************************************************************/
416 
418 (CONNECTOR connector,
420  CONN* connection)
421 {
422  EIO_Status status;
423  CONN conn;
424 
425  if (connector) {
426  conn = (SConnection*) calloc(1, sizeof(SConnection));
427 
428  if (conn) {
429  conn->flags = flags & (TCONN_Flags)(~fCONN_Flush);
430  conn->state = eCONN_Unusable;
431  conn->o_timeout = kDefaultTimeout;
432  conn->r_timeout = kDefaultTimeout;
433  conn->w_timeout = kDefaultTimeout;
434  conn->c_timeout = kDefaultTimeout;
435  conn->magic = CONNECTION_MAGIC;
436  if ((status = x_ReInit(conn, connector, 0)) != eIO_Success) {
437  conn->magic = (unsigned int)(-1);
438  free(conn);
439  conn = 0;
440  }
441  } else
442  status = eIO_Unknown;
443  } else {
444  static const STimeout* timeout = 0/*dummy*/;
445  conn = 0;
446  status = eIO_InvalidArg;
447  CONN_LOG(2, Create, eLOG_Error, "NULL connector");
448  }
449 
450  assert(!conn == !(status == eIO_Success));
451  CONN_CALLTRACE(Create);
452  *connection = conn;
453  return status;
454 }
455 
456 
458 (CONNECTOR connector,
459  CONN* conn)
460 {
461  return CONN_CreateEx(connector, 0, conn);
462 }
463 
464 
466 (CONN conn,
467  CONNECTOR connector)
468 {
469  CONN_NOT_NULL(1, ReInit);
470 
471  return x_ReInit(conn, connector, 0/*reinit*/);
472 }
473 
474 
475 extern const char* CONN_GetType(CONN conn)
476 {
477  CONN_NOT_NULL_EX(6, GetType, 0);
478 
479  return conn->state == eCONN_Unusable || !conn->meta.list ||
480  !conn->meta.get_type ? 0 : conn->meta.get_type(conn->meta.c_get_type);
481 }
482 
483 
485 {
486  CONN_NOT_NULL_EX(7, Description, 0);
487 
488  return conn->state == eCONN_Unusable || !conn->meta.list ||
489  !conn->meta.descr ? 0 : conn->meta.descr(conn->meta.c_descr);
490 }
491 
492 
494 {
495  static const STimeout* timeout = 0/*dummy*/;
496  char errbuf[80];
497 
498  CONN_NOT_NULL_EX(30, GetPosition, 0);
499 
500  switch (event) {
501  case eIO_Open:
502  conn->r_pos = 0;
503  conn->w_pos = 0;
504  break;
505  case eIO_Read:
506  return conn->r_pos;
507  case eIO_Write:
508  return conn->w_pos;
509  default:
510  sprintf(errbuf, "Unknown direction #%u", (unsigned int) event);
511  CONN_LOG_EX(31, GetPosition, eLOG_Error, errbuf, 0);
512  assert(0);
513  break;
514  }
515 
516  return 0;
517 }
518 
519 
521 (CONN conn,
522  EIO_Event event,
523  const STimeout* timeout)
524 {
525  char errbuf[80];
526 
527  CONN_NOT_NULL(8, SetTimeout);
528 
529  switch (event) {
530  case eIO_Open:
531  if (timeout && timeout != kDefaultTimeout) {
532  if (&conn->oo_timeout != timeout)
533  conn->oo_timeout = *timeout;
534  conn->o_timeout = &conn->oo_timeout;
535  } else
536  conn->o_timeout = timeout;
537  break;
538  case eIO_Read:
539  case eIO_ReadWrite:
540  if (timeout && timeout != kDefaultTimeout) {
541  if (&conn->rr_timeout != timeout)
542  conn->rr_timeout = *timeout;
543  conn->r_timeout = &conn->rr_timeout;
544  } else
545  conn->r_timeout = timeout;
546  if (event != eIO_ReadWrite)
547  break;
548  /*FALLTHRU*/
549  case eIO_Write:
550  if (timeout && timeout != kDefaultTimeout) {
551  if (&conn->ww_timeout != timeout)
552  conn->ww_timeout = *timeout;
553  conn->w_timeout = &conn->ww_timeout;
554  } else
555  conn->w_timeout = timeout;
556  break;
557  case eIO_Close:
558  if (timeout && timeout != kDefaultTimeout) {
559  if (&conn->cc_timeout != timeout)
560  conn->cc_timeout = *timeout;
561  conn->c_timeout = &conn->cc_timeout;
562  } else
563  conn->c_timeout = timeout;
564  break;
565  default:
566  sprintf(errbuf, "Unknown event #%u", (unsigned int) event);
567  CONN_LOG_EX(9, SetTimeout, eLOG_Error, errbuf, eIO_InvalidArg);
568  assert(0);
569  return eIO_InvalidArg;
570  }
571 
572  return eIO_Success;
573 }
574 
575 
577 (CONN conn,
578  EIO_Event event)
579 {
580  const STimeout* timeout;
581  char errbuf[80];
582 
583  CONN_NOT_NULL_EX(10, GetTimeout, 0);
584 
585  switch (event) {
586  case eIO_Open:
587  timeout = conn->o_timeout;
588  break;
589  case eIO_ReadWrite:
590  timeout = 0/*dummy*/;
591  CONN_LOG_EX(11, GetTimeout, eLOG_Warning,
592  "ReadWrite timeout requested", 0);
593  /*FALLTHRU*/
594  case eIO_Read:
595  timeout = conn->r_timeout;
596  break;
597  case eIO_Write:
598  timeout = conn->w_timeout;
599  break;
600  case eIO_Close:
601  timeout = conn->c_timeout;
602  break;
603  default:
604  timeout = 0;
605  sprintf(errbuf, "Unknown event #%u", (unsigned int) event);
606  CONN_LOG_EX(12, GetTimeout, eLOG_Error, errbuf, 0);
607  assert(0);
608  break;
609  }
610 
611  return timeout;
612 }
613 
614 
616 (CONN conn,
617  EIO_Event event,
618  const STimeout* timeout)
619 {
620  EIO_Status status;
621 
622  CONN_NOT_NULL(13, Wait);
623 
624  if (event != eIO_Read && event != eIO_Write) {
625  assert(0);
626  return eIO_InvalidArg;
627  }
628 
629  /* perform open, if not opened yet */
630  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
631  return status;
632  assert((conn->state & eCONN_Open) && conn->meta.list);
633 
634  /* check if there is a PEEK'ed data in the input */
635  if (event == eIO_Read && BUF_Size(conn->buf))
636  return eIO_Success;
637 
638  /* call current connector's "WAIT" method */
639  if (timeout == kDefaultTimeout) {
640  timeout = conn->meta.default_timeout;
641  assert(timeout != kDefaultTimeout);
642  }
643  status = conn->meta.wait
644  ? conn->meta.wait(conn->meta.c_wait, event, timeout)
646 
647  if (status != eIO_Success) {
648  static const char* kErrMsg[] = { "Read event failed",
649  "Write event failed" };
650  ELOG_Level level;
651  switch (status) {
652  case eIO_Timeout:
653  if (!timeout/*impossible*/)
654  level = eLOG_Error;
655  else if (timeout->sec | timeout->usec)
656  level = eLOG_Trace;
657  else
658  return status;
659  break;
660  case eIO_Closed:
661  level = event == eIO_Read ? eLOG_Trace : eLOG_Error;
662  break;
663  case eIO_Interrupt:
664  level = eLOG_Warning;
665  break;
666  default:
667  level = eLOG_Error;
668  break;
669  }
670  CONN_LOG(event != eIO_Read ? 15 : 14, Wait, level,
671  kErrMsg[event != eIO_Read]);
672  }
673  return status;
674 }
675 
676 
678 (CONN conn,
679  const void* data,
680  const size_t size,
681  size_t* n_written)
682 {
683  const STimeout* timeout = 0/*dummy*/;
684  EIO_Status status;
685 
686  assert(*n_written == 0);
687 
688  /* check if the write method is specified at all */
689  if (!conn->meta.write) {
690  status = eIO_NotSupported;
691  CONN_LOG(16, Write, eLOG_Critical, "Cannot write data");
692  return status;
693  }
694 
695  for (;;) {
696  if ((status = x_Callback(conn, eCONN_OnWrite, 0)) != eIO_Success)
697  break;
698 
699  /* call current connector's "WRITE" method */
700  timeout = (conn->w_timeout == kDefaultTimeout
701  ? conn->meta.default_timeout
702  : conn->w_timeout);
703  assert(timeout != kDefaultTimeout);
704  status = conn->meta.write(conn->meta.c_write, data, size,
705  n_written, timeout);
706  assert(status != eIO_Success || *n_written || !size);
707  assert(*n_written <= size);
708  conn->w_status = status;
709 
710  if (*n_written) {
711  conn->w_pos += *n_written;
712  conn->flags &= (TCONN_Flags)(~fCONN_Flush);
713  break;
714  }
715  if (!size || status != eIO_Timeout)
716  break;
717 
719  if (status != eIO_Success)
720  break;
721  }
722 
723  if (status != eIO_Success) {
724  if (*n_written) {
725  CONN_TRACE(Write, "Write error");
726  /*status = eIO_Success;*/
727  } else if (size) {
728  ELOG_Level level;
729  if (status != eIO_Timeout || conn->w_timeout == kDefaultTimeout)
730  level = eLOG_Error;
731  else if (!timeout/*impossible*/ || (timeout->sec | timeout->usec))
732  level = eLOG_Warning;
733  else
734  level = eLOG_Trace;
735  CONN_LOG(17, Write, level, "Unable to write data");
736  }
737  }
738  return status;
739 }
740 
741 
743 (CONN conn,
744  const void* data,
745  const size_t size,
746  size_t* n_written)
747 {
748  EIO_Status status;
749 
750  assert(*n_written == 0);
751 
752  do {
753  size_t x_written = 0;
754  status = s_CONN_Write(conn, (char*) data + *n_written,
755  size - *n_written, &x_written);
756  *n_written += x_written;
757  if (*n_written == size)
758  return conn->flags & fCONN_Supplement ? status : eIO_Success;
759  } while (status == eIO_Success);
760 
761  return status;
762 }
763 
764 
766 (CONN conn,
767  const void* data,
768  size_t size,
769  size_t* n_written,
770  EIO_WriteMethod how)
771 {
772  EIO_Status status;
773 
774  if (!n_written) {
775  assert(0);
776  return eIO_InvalidArg;
777  }
778  *n_written = 0;
779  if (size && !data) {
780  assert(0);
781  return eIO_InvalidArg;
782  }
783 
784  CONN_NOT_NULL(18, Write);
785 
786  /* open connection, if not yet opened */
787  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
788  return status;
789  assert((conn->state & eCONN_Open) && conn->meta.list);
790 
791  switch (how) {
792  case eIO_WritePlain:
793  status = s_CONN_Write(conn, data, size, n_written);
794  break;
795  case eIO_WritePersist:
796  return s_CONN_WritePersist(conn, data, size, n_written);
797  default:
798  assert(0);
799  return eIO_NotSupported;
800  }
801 
802  if (conn->flags & fCONN_Supplement)
803  return status;
804  return *n_written ? eIO_Success : status;
805 }
806 
807 
809 (CONN conn,
810  const void* data,
811  size_t size)
812 {
813  if (size && !data) {
814  assert(0);
815  return eIO_InvalidArg;
816  }
817 
818  CONN_NOT_NULL(19, Pushback);
819 
820  if (conn->state == eCONN_Unusable)
821  return eIO_InvalidArg;
822 
823  if (conn->state != eCONN_Open)
824  return eIO_Closed;
825 
826  if (!conn->meta.read)
827  return eIO_NotSupported;
828 
829  return BUF_Pushback(&conn->buf, data, size) ? eIO_Success : eIO_Unknown;
830 }
831 
832 
834 (CONN conn)
835 {
836  EIO_Status status;
837 
838  CONN_NOT_NULL(20, Flush);
839 
840  /* perform open, if not opened yet */
841  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
842  return status;
843  assert((conn->state & eCONN_Open) && conn->meta.list);
844 
845  status = x_Flush(conn, conn->w_timeout, 1/*flush*/);
846  if (status != eIO_Success) {
847  /* this is only for the log message */
848  const STimeout* timeout = status != eIO_Timeout ? 0
849  : (conn->w_timeout == kDefaultTimeout
850  ? conn->meta.default_timeout
851  : conn->w_timeout);
852  assert(timeout != kDefaultTimeout);
853  CONN_LOG(21, Flush, status == eIO_Timeout ? eLOG_Trace : eLOG_Warning,
854  "Failed to flush");
855  }
856  return status;
857 }
858 
859 
860 /* Read or peek data from the input queue, see CONN_Read()
861  */
863 (CONN conn,
864  void* buf,
865  const size_t size,
866  size_t* n_read,
867  int/*bool*/ peek)
868 {
869  const STimeout* timeout = 0/*dummy*/;
870  EIO_Status status;
871 
872  assert(*n_read == 0);
873 
874  /* check if the read method is specified at all */
875  if (!conn->meta.read) {
876  status = eIO_NotSupported;
877  CONN_LOG(22, Read, eLOG_Critical, "Cannot read data");
878  return status;
879  }
880 
881  if (conn->state == eCONN_Cancel)
882  status = eIO_Interrupt;
883  else for (;;) {
884  size_t x_read;
885 
886  /* read data from the internal peek/pushback buffer, if any */
887  if (size) {
888  x_read = (peek
889  ? BUF_Peek(conn->buf, buf, size - *n_read)
890  : BUF_Read(conn->buf, buf, size - *n_read));
891  *n_read += x_read;
892  if (x_read && (*n_read == size || !peek)) {
893  status = eIO_Success;
894  break;
895  }
896  buf = (char*) buf + x_read;
897  }
898 
899  if ((status = x_Callback(conn, eCONN_OnRead, 0)) != eIO_Success)
900  break;
901 
902  x_read = 0;
903  /* call current connector's "READ" method */
904  timeout = (conn->r_timeout == kDefaultTimeout
905  ? conn->meta.default_timeout
906  : conn->r_timeout);
907  assert(timeout != kDefaultTimeout);
908  status = conn->meta.read(conn->meta.c_read, buf, size - *n_read,
909  &x_read, timeout);
910  assert(status != eIO_Success || x_read || !size);
911  assert(x_read <= size - *n_read);
912  conn->r_status = status;
913 
914  if (x_read) {
915  *n_read += x_read;
916  conn->r_pos += x_read;
917  /* save data in the internal peek buffer */
918  if (peek && !BUF_Write(&conn->buf, buf, x_read)) {
920  "Cannot save peek data", 0);
921  conn->state = eCONN_Corrupt;
922  status = eIO_Unknown;
923  }
924  break;
925  }
926  if (!size || *n_read || status != eIO_Timeout)
927  break;
928 
930  if (status != eIO_Success)
931  break;
932  }
933 
934  if (status != eIO_Success) {
935  if (*n_read) {
936  CONN_TRACE(Read, "Read error");
937  /*status = eIO_Success;*/
938  } else if (size && status != eIO_Closed) {
939  ELOG_Level level;
940  if (status != eIO_Timeout || conn->r_timeout == kDefaultTimeout)
941  level = eLOG_Error;
942  else if (!timeout/*impossible*/ || (timeout->sec | timeout->usec))
943  level = eLOG_Warning;
944  else
945  level = eLOG_Trace;
946  CONN_LOG(23, Read, level, "Unable to read data");
947  }
948  }
949  return status;
950 }
951 
952 
953 /* Persistently read data from the input queue, see CONN_Read()
954  */
956 (CONN conn,
957  void* buf,
958  const size_t size,
959  size_t* n_read)
960 {
961  EIO_Status status;
962 
963  assert(*n_read == 0);
964 
965  for (;;) {
966  size_t x_read = 0;
967  status = s_CONN_Read(conn, (char*) buf + *n_read,
968  size - *n_read, &x_read, 0/*no peek*/);
969  *n_read += x_read;
970  if (*n_read == size)
971  return conn->flags & fCONN_Supplement ? status : eIO_Success;
972 
973  if (status != eIO_Success)
974  break;
975 
976  /* keep flushing any pending unwritten output data */
977  if (!(conn->flags & (fCONN_Untie | fCONN_Flush)))
978  x_Flush(conn, conn->r_timeout, 0/*no-flush*/);
979  }
980  return status;
981 }
982 
983 
985 (CONN conn,
986  void* buf,
987  size_t size,
988  size_t* n_read,
989  EIO_ReadMethod how)
990 {
991  EIO_Status status;
992 
993  if (!n_read) {
994  assert(0);
995  return eIO_InvalidArg;
996  }
997  *n_read = 0;
998  if (size && !buf) {
999  assert(0);
1000  return eIO_InvalidArg;
1001  }
1002 
1003  CONN_NOT_NULL(24, Read);
1004 
1005  /* perform open, if not opened yet */
1006  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
1007  return status;
1008  assert((conn->state & eCONN_Open) && conn->meta.list);
1009 
1010  /* flush pending unwritten output data (if any) */
1011  if (!(conn->flags & (fCONN_Untie | fCONN_Flush)))
1012  x_Flush(conn, conn->r_timeout, 0/*no-flush*/);
1013 
1014  /* now do read */
1015  switch (how) {
1016  case eIO_ReadPeek:
1017  status = s_CONN_Read(conn, buf, size, n_read, 1/*i.e.peek*/);
1018  break;
1019  case eIO_ReadPlain:
1020  status = s_CONN_Read(conn, buf, size, n_read, 0/*i.e.read*/);
1021  break;
1022  case eIO_ReadPersist:
1023  return s_CONN_ReadPersist(conn, buf, size, n_read);
1024  default:
1025  assert(0);
1026  return eIO_NotSupported;
1027  }
1028 
1029  if (conn->flags & fCONN_Supplement)
1030  return status;
1031  return *n_read ? eIO_Success : status;
1032 }
1033 
1034 
1036 (CONN conn,
1037  char* line,
1038  size_t size,
1039  size_t* n_read
1040  )
1041 {
1042  EIO_Status status;
1043  int/*bool*/ done;
1044  size_t len;
1045 
1046  if (!n_read) {
1047  assert(0);
1048  return eIO_InvalidArg;
1049  }
1050  *n_read = 0;
1051  if (!size || !line) {
1052  assert(0);
1053  return eIO_InvalidArg;
1054  }
1055 
1056  CONN_NOT_NULL(25, ReadLine);
1057 
1058  /* perform open, if not opened yet */
1059  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
1060  return status;
1061  assert((conn->state & eCONN_Open) && conn->meta.list);
1062 
1063  len = 0;
1064  done = 0/*false*/;
1065  do {
1066  char w[1024];
1067  size_t i, x_size, x_read = 0;
1068  char* x_buf = size - len < sizeof(w) ? w : line + len;
1069  if (!(x_size = BUF_Size(conn->buf)) || x_size > sizeof(w))
1070  x_size = sizeof(w);
1071 
1072  /* keep flushing any pending unwritten output data then read */
1073  if (!(conn->flags & (fCONN_Untie | fCONN_Flush)))
1074  x_Flush(conn, conn->r_timeout, 0/*no-flush*/);
1075  status = s_CONN_Read(conn, x_buf, x_size, &x_read, 0);
1076  assert(x_read <= x_size);
1077 
1078  i = 0;
1079  while (i < x_read && len < size) {
1080  char c = x_buf[i++];
1081  if (c == '\n') {
1082  status = eIO_Success;
1083  done = 1/*true*/;
1084  break;
1085  }
1086  if (x_buf == w)
1087  line[len] = c;
1088  ++len;
1089  }
1090  if (len >= size) {
1091  /* out of room */
1092  assert(!done && len);
1093  done = 1/*true*/;
1094  }
1095  if (i < x_read) {
1096  /* pushback excess */
1097  assert(done);
1098  if (!BUF_Pushback(&conn->buf, x_buf + i, x_read - i)) {
1099  static const STimeout* timeout = 0/*dummy*/;
1101  "Cannot pushback extra data", 0);
1102  conn->state = eCONN_Corrupt;
1103  status = eIO_Unknown;
1104  } else
1105  status = eIO_Success;
1106  break;
1107  }
1108  } while (!done && status == eIO_Success);
1109 
1110  if (len < size)
1111  line[len] = '\0';
1112  *n_read = len;
1113 
1114  return done && !(conn->flags & fCONN_Supplement) ? eIO_Success : status;
1115 }
1116 
1117 
1119 {
1120  CONN_NOT_NULL(26, Status);
1121 
1122  if (dir != eIO_Open && (dir & ~eIO_ReadWrite))
1123  return eIO_InvalidArg;
1124 
1125  if (conn->state == eCONN_Unusable)
1126  return eIO_InvalidArg;
1127 
1128  if (conn->state == eCONN_Corrupt)
1129  return eIO_Unknown;
1130 
1131  if (conn->state == eCONN_Cancel)
1132  return eIO_Interrupt;
1133 
1134  if (conn->state != eCONN_Open)
1135  return eIO_Closed;
1136 
1137  switch (dir) {
1138  case eIO_ReadWrite:
1139  conn->r_status = eIO_Success;
1140  conn->w_status = eIO_Success;
1141  /*FALLTHRU*/
1142  case eIO_Open:
1143  return eIO_Success;
1144  case eIO_Read:
1145  if (conn->r_status != eIO_Success)
1146  return conn->r_status;
1147  break;
1148  case eIO_Write:
1149  if (conn->w_status != eIO_Success)
1150  return conn->w_status;
1151  break;
1152  default:
1153  assert(0);
1154  return eIO_NotSupported;
1155  }
1156  return conn->meta.status
1157  ? conn->meta.status(conn->meta.c_status, dir)
1158  : eIO_NotSupported;
1159 }
1160 
1161 
1163 {
1164  EIO_Status status;
1165 
1166  CONN_NOT_NULL(27, Close);
1167 
1168  status = x_ReInit(conn, 0, 1/*close*/);
1169  BUF_Destroy(conn->buf);
1170  conn->magic = 0;
1171  conn->data = 0;
1172  conn->buf = 0;
1173  free(conn);
1174  return status == eIO_Closed ? eIO_Success : status;
1175 }
1176 
1177 
1179 (CONN conn,
1181  const SCONN_Callback* newcb,
1182  SCONN_Callback* oldcb)
1183 {
1184  size_t idx;
1185 
1186  CONN_NOT_NULL(28, SetCallback);
1187 
1188  if ((idx = x_CB2IDX(type)) >= CONN_N_CALLBACKS) {
1189  static const STimeout* timeout = 0/*dummy*/;
1190  char errbuf[80];
1191  sprintf(errbuf, "Unknown callback type #%u", (unsigned int) type);
1192  CONN_LOG_EX(29, SetCallback, eLOG_Error, errbuf, eIO_InvalidArg);
1193  assert(0);
1194  return eIO_InvalidArg;
1195  }
1196 
1197  /* NB: oldcb and newcb may point to the same address */
1198  if (newcb || oldcb) {
1199  SCONN_Callback cb = conn->cb[idx];
1200  if (newcb)
1201  conn->cb[idx] = *newcb;
1202  if (oldcb)
1203  *oldcb = cb;
1204  }
1205  return eIO_Success;
1206 }
1207 
1208 
1210 {
1211  EIO_Status status;
1212  CONNECTOR x_conn;
1213 
1214  if (!sock)
1215  return eIO_InvalidArg;
1216  *sock = 0;
1217 
1218  CONN_NOT_NULL(36, GetSOCK);
1219 
1220  /* perform open, if not opened yet */
1221  if (conn->state != eCONN_Open && (status = s_Open(conn)) != eIO_Success)
1222  return status;
1223  assert((conn->state & eCONN_Open) && conn->meta.list);
1224 
1225  x_conn = conn->meta.list;
1226  if (x_conn && x_conn->meta && x_conn->meta->get_type) {
1227  const char* type = x_conn->meta->get_type(x_conn->meta->c_get_type);
1228  if (type == g_kNcbiSockNameAbbr
1229  || ((type = strrchr(type, '/')) != 0
1230  && strcmp(++type, g_kNcbiSockNameAbbr) == 0)) {
1231  /* HACK * HACK * HACK */
1232  SOCK* x_sock = (SOCK*) x_conn->handle;
1233  if (x_sock) {
1234  *sock = *x_sock;
1235  return eIO_Success;
1236  }
1237  }
1238  }
1239  return eIO_Closed;
1240 }
1241 
1242 
1244 {
1245  CONN_CALLTRACE(SetFlags);
1246 
1247  if (!conn)
1248  return eIO_InvalidArg;
1249 
1250  flags &= (TCONN_Flags)(~fCONN_Flush);
1251  flags |= conn->flags & fCONN_Flush;
1252  conn->flags = flags;
1253  return eIO_Success;
1254 }
1255 
1256 
1258 {
1259  CONN_CALLTRACE(GetFlags);
1260 
1261  return conn ? conn->flags & (TCONN_Flags)(~fCONN_Flush) : 0;
1262 }
1263 
1264 
1266 {
1267  CONN_CALLTRACE(SetUserData);
1268 
1269  if (!conn)
1270  return eIO_InvalidArg;
1271 
1272  conn->data = data;
1273  return eIO_Success;
1274 }
1275 
1276 
1278 {
1279  CONN_CALLTRACE(GetUserData);
1280 
1281  return conn ? conn->data : 0;
1282 }
static CS_CONNECTION * conn
Definition: ct_dynamic.c:25
static uch flags
int close(int fd)
Definition: connection.cpp:45
void BUF_Erase(BUF buf)
Definition: ncbi_buffer.c:461
int BUF_Write(BUF *pBuf, const void *data, size_t size)
Definition: ncbi_buffer.c:224
size_t BUF_Size(BUF buf)
Definition: ncbi_buffer.c:84
int BUF_Pushback(BUF *pBuf, const void *data, size_t size)
Definition: ncbi_buffer.c:285
size_t BUF_Read(BUF buf, void *data, size_t size)
Definition: ncbi_buffer.c:414
size_t BUF_Peek(BUF buf, void *data, size_t size)
Definition: ncbi_buffer.c:408
void BUF_Destroy(BUF buf)
Definition: ncbi_buffer.c:500
unsigned int TCONN_Flags
bitwise OR of ECONN_Flag
EIO_Status CONN_SetFlags(CONN conn, TCONN_Flags flags)
Set connection processing flags.
ECONN_Callback
Set user callback function to be invoked upon an event specified by the callback type.
EIO_Status CONN_SetUserData(CONN conn, void *data)
Associate an arbitraty user data pointer with the connection.
EIO_Status CONN_ReadLine(CONN conn, char *line, size_t size, size_t *n_read)
Read up to "size" bytes from connection into a string buffer pointed to by "line".
EIO_Status CONN_CreateEx(CONNECTOR connector, TCONN_Flags flags, CONN *connection)
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)
FConnectorGetType get_type
EIO_Status CONN_Flush(CONN conn)
Explicitly flush connection from any pending data written by CONN_Write().
void * CONN_GetUserData(CONN conn)
Get current value of the user's data pointer last associated with the connection, or NULL (if CONN is...
EIO_Status CONN_SetCallback(CONN conn, ECONN_Callback type, const SCONN_Callback *newcb, SCONN_Callback *oldcb)
unsigned int TCONN_Callback
TNCBI_BigCount CONN_GetPosition(CONN conn, EIO_Event event)
Get read ("event" == eIO_Read) or write ("event" == eIO_Write) position within the connection.
EIO_Status CONN_Write(CONN conn, const void *data, size_t size, size_t *n_written, EIO_WriteMethod how)
CONNECTOR next
linked list
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.
EIO_Status CONN_Create(CONNECTOR connector, CONN *conn)
Same as CONN_CreateEx() called with 0 in the "flags" parameter.
EIO_Status CONN_ReInit(CONN conn, CONNECTOR connector)
Reinit using new "connector".
EIO_Status(* FCONN_Callback)(CONN conn, TCONN_Callback type, void *data)
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...
EIO_Status METACONN_Remove(SMetaConnector *meta, CONNECTOR connector)
Delete given "connector" all its descendants (all connectors if "connector" is NULL) from the connect...
EIO_Status METACONN_Insert(SMetaConnector *meta, CONNECTOR connector)
Insert a connector in the beginning of the connection's list of connectors.
void * handle
data handle of the connector
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.
TCONN_Flags CONN_GetFlags(CONN conn)
Get connection processing flags currently in effect.
EIO_Status CONN_Status(CONN conn, EIO_Event dir)
Obtain status of the last I/O operation.
CONNECTOR c_get_type
EIO_Status CONN_Pushback(CONN conn, const void *data, size_t size)
Push "size" bytes from the buffer "data" back into connection.
#define CONN_N_CALLBACKS
@ eCONN_OnFlush
About to be flushed (NB: == eIO_ReadWrite)
@ eCONN_OnWrite
Write to CONNECTOR is about to occur.
@ eCONN_OnTimeout
CONNECTOR I/O has timed out.
@ eCONN_OnClose
NB: CONN has been flushed prior to the call.
@ eCONN_OnRead
Read from CONNECTOR is about to occur.
@ eCONN_OnOpen
Call prior to open (NB: "conn" still closed)
@ fCONN_Untie
do not call flush method prior to reading
@ fCONN_Supplement
supplement I/O with extended return codes
void Read(CObjectIStream &in, TObjectPtr object, const CTypeRef &type)
Definition: serial.cpp:60
void Write(CObjectOStream &out, TConstObjectPtr object, const CTypeRef &type)
Definition: serial.cpp:55
ELOG_Level
Log severity level.
Definition: ncbi_core.h:292
EIO_Status
I/O status.
Definition: ncbi_core.h:132
unsigned int usec
microseconds (modulo 1,000,000)
Definition: ncbi_types.h:78
EIO_ReadMethod
I/O read method.
Definition: ncbi_core.h:88
EIO_WriteMethod
I/O write method.
Definition: ncbi_core.h:99
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
uint64_t TNCBI_BigCount
Big unsigned integer for file size and position.
Definition: ncbi_types.h:164
@ eLOG_Critical
Definition: ncbi_core.h:298
@ eLOG_Error
Definition: ncbi_core.h:297
@ eLOG_Warning
Definition: ncbi_core.h:296
@ eLOG_Trace
Definition: ncbi_core.h:293
@ eIO_Timeout
timeout expired before any I/O succeeded
Definition: ncbi_core.h:134
@ eIO_Interrupt
signal arrival prevented any I/O to succeed
Definition: ncbi_core.h:136
@ 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_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_ReadPeek
do eIO_ReadPlain but leave data in input queue
Definition: ncbi_core.h:89
@ eIO_ReadPersist
read exactly as much as requested, w/waits
Definition: ncbi_core.h:91
@ eIO_WritePlain
write as much as possible, report back how much
Definition: ncbi_core.h:101
@ eIO_WritePersist
write exactly as much as specified, w/waits
Definition: ncbi_core.h:102
@ 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
unsigned int
A callback function used to compare two keys in a database.
Definition: types.hpp:1210
char * buf
int i
if(yy_accept[yy_current_state])
int len
const struct ncbi::grid::netcache::search::fields::SIZE size
int strcmp(const char *str1, const char *str2)
Definition: odbc_utils.hpp:160
#define CONN_NOT_NULL(s_c, f_n)
static EIO_Status s_CONN_Read(CONN conn, void *buf, const size_t size, size_t *n_read, int peek)
static EIO_Status s_Open(CONN conn)
static EIO_Status s_CONN_WritePersist(CONN conn, const void *data, const size_t size, size_t *n_written)
static size_t x_CB2IDX(ECONN_Callback type)
static EIO_Status s_CONN_Write(CONN conn, const void *data, const size_t size, size_t *n_written)
#define CONN_LOG(s_c, f_n, lvl, msg)
ECONN_State
@ eCONN_Corrupt
@ eCONN_Cancel
@ eCONN_Unusable
@ eCONN_Closed
@ eCONN_Open
@ eCONN_Bad
static EIO_Status s_CONN_ReadPersist(CONN conn, void *buf, const size_t size, size_t *n_read)
#define CONN_LOG_EX(subcode, func_name, level, message, status)
#define CONN_NOT_NULL_EX(subcode, func_name, retval)
#define CONNECTION_MAGIC
#define CONN_CALLTRACE(func_name)
#define CONN_TRACE(f_n, msg)
static EIO_Status x_Callback(CONN conn, ECONN_Callback type, unsigned int flag)
static EIO_Status x_Flush(CONN conn, const STimeout *timeout, int isflush)
ECONN_InternalFlag
@ fCONN_Flush
static EIO_Status x_ReInit(CONN conn, CONNECTOR connector, int close)
struct SConnectionTag SConnection
static size_t x_size(const char *dst, size_t len, const char *ptr)
Definition: ncbi_iprange.c:138
const char g_kNcbiSockNameAbbr[]
Definition: ncbi_socket.c:266
string ReadLine(CNcbiIstream &in)
Definition: phrap.cpp:74
#define assert(x)
Definition: srv_diag.hpp:58
TCONN_Flags flags
const STimeout * c_timeout
SCONN_Callback cb[CONN_N_CALLBACKS+1]
SMetaConnector meta
TNCBI_BigCount r_pos
EIO_Status w_status
ECONN_State state
const STimeout * o_timeout
TNCBI_BigCount w_pos
const STimeout * w_timeout
EIO_Status r_status
const STimeout * r_timeout
unsigned int magic
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
done
Definition: token1.c:1
void free(voidpf ptr)
voidp calloc(uInt items, uInt size)
Modified on Wed Dec 06 07:15:29 2023 by modify_doxy.py rev. 669887