NCBI C Toolkit Cross Reference

C/connect/ncbi_connection.c


  1 /* $Id: ncbi_connection.c,v 6.60 2009/07/28 13:04:32 kazimird Exp $
  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:  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 <connect/ncbi_buffer.h>
 36 #include <connect/ncbi_connection.h>
 37 #include <stdlib.h>
 38 #include <string.h>
 39 
 40 #define NCBI_USE_ERRCODE_X   Connect_Connection
 41 
 42 
 43 /***********************************************************************
 44  *  INTERNAL
 45  ***********************************************************************/
 46 
 47 /* Standard logging message
 48  */
 49 #define CONN_LOG_EX(subcode, func_name, level, message, status)            \
 50   {                                                                        \
 51       const char* ststr = status ? IO_StatusStr((EIO_Status) status) : ""; \
 52       char stbuf[80];                                                      \
 53       if ((EIO_Status) status == eIO_Timeout  &&  timeout) {               \
 54           sprintf(stbuf, "%s[%u.%06u]", ststr,                             \
 55                   (unsigned int)(timeout->sec + timeout->usec / 1000000),  \
 56                   (unsigned int)               (timeout->usec % 1000000)); \
 57           assert(strlen(stbuf) < sizeof(stbuf));                           \
 58           ststr = stbuf;                                                   \
 59       }                                                                    \
 60       CORE_LOGF_X(subcode, level,                                          \
 61                   ("[CONN_" #func_name "(%s)]  %s%s%s",                    \
 62                    conn->meta.get_type                                     \
 63                    ? conn->meta.get_type(conn->meta.c_get_type)            \
 64                    : "Unknown", message,                                   \
 65                    ststr  &&  *ststr ? ": "  : "",                         \
 66                    ststr             ? ststr : ""));                       \
 67   }
 68 
 69 #define CONN_LOG(s_c, f_n, lvl, msg)  CONN_LOG_EX(s_c, f_n, lvl, msg, status)
 70 
 71 /* Standard macros to verify that the passed connection handle is not NULL
 72  * NB: "retval" must be either a valid EIO_Status or 0 (no status logged)
 73  */
 74 #define CONN_NOT_NULL_EX(subcode, func_name, retval)                    \
 75   if (!conn) {                                                          \
 76       const STimeout* timeout = 0/*dummy*/;                             \
 77       CONN_LOG_EX(subcode, func_name, eLOG_Error,                       \
 78                   "NULL connection handle", retval);                    \
 79       assert(conn);                                                     \
 80       return retval;                                                    \
 81   }
 82 
 83 #define CONN_NOT_NULL(s_c, f_n)  CONN_NOT_NULL_EX(s_c, f_n, eIO_InvalidArg)
 84 
 85 #ifdef _DEBUG
 86 #  define CONN_TRACE(f_n, msg)   CONN_LOG(0, f_n, eLOG_Trace, msg)
 87 #else
 88 #  define CONN_TRACE(f_n, msg)   ((void) 0)
 89 #endif /*_DEBUG*/
 90 
 91 
 92 /* Connection state
 93  */
 94 typedef enum ECONN_StateTag {
 95     eCONN_Unusable = -1,               /* this should be iff !conn->meta.list*/
 96     eCONN_Closed   =  0,
 97     eCONN_Open     =  1
 98 } ECONN_State;
 99 
100 
101 /* Connection internal data:  meta *must* come first
102  */
103 typedef struct SConnectionTag {
104     SMetaConnector         meta;       /* VTable of operations and list      */
105 
106     BUF                    buf;        /* storage for the Peek'd data        */
107 #ifdef IMPLEMENTED__CONN_WaitAsync
108     SConnectorAsyncHandler async_data; /* info of curr. async event handler  */
109 #endif
110     ECONN_State            state;      /* connection state                   */
111 
112     /* "[c|r|w|l]_timeout" is either 0 (kInfiniteTimeout), kDefaultTimeout
113        (to use connector-specific one), or points to "[cc|rr|ww|ll]_timeout" */
114     const STimeout*        o_timeout;  /* timeout on open                    */
115     const STimeout*        r_timeout;  /* timeout on reading                 */
116     const STimeout*        w_timeout;  /* timeout on writing                 */
117     const STimeout*        c_timeout;  /* timeout on close                   */
118     STimeout               oo_timeout; /* storage for "o_timeout"            */
119     STimeout               rr_timeout; /* storage for "r_timeout"            */
120     STimeout               ww_timeout; /* storage for "w_timeout"            */
121     STimeout               cc_timeout; /* storage for "c_timeout"            */
122 
123     SCONN_Callback         cbs[CONN_N_CALLBACKS];
124 } SConnection;
125 
126 
127 
128 /***********************************************************************
129  *  EXTERNAL
130  ***********************************************************************/
131 
132 extern EIO_Status CONN_Create
133 (CONNECTOR connector,
134  CONN*     connection)
135 {
136     CONN conn = (SConnection*) calloc(1, sizeof(SConnection));
137     EIO_Status status = eIO_Unknown;
138 
139     if (conn) {
140         conn->state     = eCONN_Unusable;
141         conn->o_timeout = kDefaultTimeout;
142         conn->r_timeout = kDefaultTimeout;
143         conn->w_timeout = kDefaultTimeout;
144         conn->c_timeout = kDefaultTimeout;
145         if ((status = CONN_ReInit(conn, connector)) != eIO_Success) {
146             free(conn);
147             conn = 0;
148         }
149     }
150 
151     *connection = conn;
152     return status;
153 }
154 
155 
156 extern EIO_Status CONN_ReInit
157 (CONN      conn,
158  CONNECTOR connector)
159 {
160     const STimeout* timeout = 0/*dummy*/;
161     CONNECTOR  x_conn = 0;
162     EIO_Status status;
163 
164     CONN_NOT_NULL(1, ReInit);
165 
166     /* check arg */
167     if (!connector  &&  !conn->meta.list) {
168         assert(conn->state == eCONN_Unusable);
169         status = eIO_InvalidArg;
170         CONN_LOG(2, ReInit, eLOG_Error,
171                  "Cannot re-init empty connection with NULL");
172         return status;
173     }
174 
175     /* reset and close current connector(s), if any */
176     if (conn->meta.list) {
177 #ifdef IMPLEMENTED__CONN_WaitAsync
178         /* cancel async. i/o event handler */
179         CONN_WaitAsync(conn, eIO_ReadWrite, 0, 0, 0);
180 #endif
181         {{ /* erase unread data */
182             size_t buf_size = BUF_Size(conn->buf);
183             verify(BUF_Read(conn->buf, 0, buf_size) == buf_size);
184         }}
185         /* call current connector's "FLUSH" and "CLOSE" methods */
186         if (conn->state == eCONN_Open) {
187             if (conn->meta.flush) {
188                 conn->meta.flush(conn->meta.c_flush,
189                                  conn->c_timeout == kDefaultTimeout
190                                  ? conn->meta.default_timeout
191                                  : conn->c_timeout);
192             }
193             if (conn->meta.close) {
194                 status = conn->meta.close(conn->meta.c_close,
195                                           conn->c_timeout == kDefaultTimeout
196                                           ? conn->meta.default_timeout
197                                           : conn->c_timeout);
198                 if (status != eIO_Success) {
199                     CONN_LOG(3, ReInit, connector ? eLOG_Error : eLOG_Warning,
200                              "Cannot close current connection");
201                     if (connector)
202                         return status;
203                 }
204             }
205             conn->state = eCONN_Closed;
206         }
207 
208         for (x_conn = conn->meta.list;  x_conn;  x_conn = x_conn->next) {
209             if (x_conn == connector) {
210                 /* Reinit with the same and the only connector - allowed */
211                 if (!x_conn->next  &&  x_conn == conn->meta.list)
212                     break;
213                 status = eIO_Unknown;
214                 CONN_LOG(4, ReInit, eLOG_Error, "Partial re-init not allowed");
215                 return status;
216             }
217         }
218 
219         if (!x_conn) {
220             /* Entirely new connector - remove the old connector stack first */
221             METACONN_Remove(&conn->meta, 0);
222             assert(conn->meta.list == 0);
223             memset(&conn->meta, 0, sizeof(conn->meta));
224             conn->state = eCONN_Unusable;
225         }
226     }
227 
228     if (connector  &&  !x_conn) {
229         assert(conn->state == eCONN_Unusable);
230         /* Setup the new connector */
231         if (METACONN_Add(&conn->meta, connector) != eIO_Success)
232             return eIO_Unknown;
233         conn->state = eCONN_Closed;
234     }
235 
236     assert(conn->state != eCONN_Open);
237     return eIO_Success;
238 }
239 
240 
241 static EIO_Status s_Open
242 (CONN conn)
243 {
244     const STimeout* timeout;
245     EIO_Status status;
246 
247     assert(conn->state == eCONN_Closed  &&  conn->meta.list != 0);
248 
249     /* call current connector's "OPEN" method */
250     if (conn->meta.open) {
251         timeout = (conn->o_timeout == kDefaultTimeout
252                    ? conn->meta.default_timeout
253                    : conn->o_timeout);
254         status = conn->meta.open(conn->meta.c_open, timeout);
255     } else {
256         status = eIO_NotSupported;
257         timeout = 0/*dummy*/;
258     }
259 
260     if (status != eIO_Success) {
261         CONN_LOG(5, Open, eLOG_Error, "Failed to open connection");
262         return status;
263     }
264 
265     /* success */
266     conn->state = eCONN_Open;
267     return status;
268 }
269 
270 
271 extern const char* CONN_GetType(CONN conn)
272 {
273     CONN_NOT_NULL_EX(6, GetType, 0);
274 
275     return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||
276         !conn->meta.get_type ? 0 : conn->meta.get_type(conn->meta.c_get_type);
277 }
278 
279 
280 extern char* CONN_Description(CONN conn)
281 {
282     CONN_NOT_NULL_EX(7, Description, 0);
283 
284     return conn->state == eCONN_Unusable  ||  !conn->meta.list  ||
285         !conn->meta.descr ? 0 : conn->meta.descr(conn->meta.c_descr);
286 }
287 
288 
289 extern EIO_Status CONN_SetTimeout
290 (CONN            conn,
291  EIO_Event       event,
292  const STimeout* timeout)
293 {
294     char errbuf[80];
295 
296     CONN_NOT_NULL(8, SetTimeout);
297 
298     switch (event) {
299     case eIO_Open:
300         if (timeout  &&  timeout != kDefaultTimeout) {
301             if (&conn->oo_timeout != timeout)
302                 conn->oo_timeout = *timeout;
303             conn->o_timeout  = &conn->oo_timeout;
304         } else
305             conn->o_timeout  = timeout;
306         break;
307     case eIO_Close:
308         if (timeout  &&  timeout != kDefaultTimeout) {
309             if (&conn->cc_timeout != timeout)
310                 conn->cc_timeout = *timeout;
311             conn->c_timeout  = &conn->cc_timeout;
312         } else
313             conn->c_timeout  = timeout;
314         break;
315     case eIO_Read:
316     case eIO_ReadWrite:
317         if (timeout  &&  timeout != kDefaultTimeout) {
318             if (&conn->rr_timeout != timeout)
319                 conn->rr_timeout = *timeout;
320             conn->r_timeout  = &conn->rr_timeout;
321         } else
322             conn->r_timeout  = timeout;
323         if (event != eIO_ReadWrite)
324             break;
325         /*FALLTHRU*/
326     case eIO_Write:
327         if (timeout  &&  timeout != kDefaultTimeout) {
328             if (&conn->ww_timeout != timeout)
329                 conn->ww_timeout = *timeout;
330             conn->w_timeout  = &conn->ww_timeout;
331         } else
332             conn->w_timeout  = timeout;
333         break;
334     default:
335         sprintf(errbuf, "Unknown event #%d to set timeout for", (int) event);
336         CONN_LOG_EX(9, SetTimeout, eLOG_Error, errbuf, eIO_InvalidArg);
337         return eIO_InvalidArg;
338     }
339 
340     return eIO_Success;
341 }
342 
343 
344 extern const STimeout* CONN_GetTimeout
345 (CONN      conn,
346  EIO_Event event)
347 {
348     const STimeout* timeout;
349     char errbuf[80];
350 
351     CONN_NOT_NULL_EX(10, GetTimeout, 0);
352 
353     switch (event) {
354     case eIO_Open:
355         timeout = conn->o_timeout;
356         break;
357     case eIO_ReadWrite:
358         timeout = 0/*dummy*/;
359         CONN_LOG_EX(11, GetTimeout, eLOG_Warning,
360                     "ReadWrite timeout requested", 0);
361         /*FALLTHRU*/
362     case eIO_Read:
363         timeout = conn->r_timeout;
364         break;
365     case eIO_Write:
366         timeout = conn->w_timeout;
367         break;
368     case eIO_Close:
369         timeout = conn->c_timeout;
370         break;
371     default:
372         timeout = 0;
373         sprintf(errbuf, "Unknown event #%d to get timeout for", (int) event);
374         CONN_LOG_EX(12, GetTimeout, eLOG_Error, errbuf, 0);
375         assert(0);
376         break;
377     }
378     return timeout;
379 }
380 
381 
382 extern EIO_Status CONN_Wait
383 (CONN            conn,
384  EIO_Event       event,
385  const STimeout* timeout)
386 {
387     EIO_Status status;
388 
389     CONN_NOT_NULL(13, Wait);
390 
391     if (conn->state == eCONN_Unusable                ||
392         (event != eIO_Read  &&  event != eIO_Write)  ||
393         timeout == kDefaultTimeout) {
394         return eIO_InvalidArg;
395     }
396 
397     /* perform open, if not opened yet */
398     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
399         return status;
400     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
401 
402     /* check if there is a PEEK'ed data in the input */
403     if (event == eIO_Read  &&  BUF_Size(conn->buf))
404         return eIO_Success;
405 
406     /* call current connector's "WAIT" method */
407     status = conn->meta.wait
408         ? conn->meta.wait(conn->meta.c_wait, event, timeout)
409         : eIO_NotSupported;
410 
411     if (status != eIO_Success) {
412         static const char* kErrMsg[] = { "Read event failed",
413                                          "Write event failed" };
414         ELOG_Level level;
415         switch (status) {
416         case eIO_Timeout:
417             if (!timeout)
418                 level = eLOG_Warning;
419             else if (timeout->sec | timeout->usec)
420                 level = eLOG_Trace;
421             else
422                 return status;
423             break;
424         case eIO_Closed:
425             level = event == eIO_Read ? eLOG_Trace : eLOG_Error;
426             break;
427         case eIO_Interrupt:
428             level = eLOG_Warning;
429             break;
430         default:
431             level = eLOG_Error;
432             break;
433         }
434         CONN_LOG(14, Wait, level, kErrMsg[event != eIO_Read]);
435     }
436     return status;
437 }
438 
439 
440 static EIO_Status s_CONN_Write
441 (CONN        conn,
442  const void* buf,
443  size_t      size,
444  size_t*     n_written)
445 {
446     const STimeout* timeout;
447     EIO_Status status;
448 
449     assert(*n_written == 0);
450 
451     /* check if the write method is specified at all */
452     if (!conn->meta.write) {
453         timeout = 0/*dummy*/;
454         status = eIO_NotSupported;
455         CONN_LOG(16, Write, eLOG_Error, "Cannot write data");
456         return status;
457     }
458 
459     /* call current connector's "WRITE" method */
460     timeout = (conn->w_timeout == kDefaultTimeout
461                ? conn->meta.default_timeout
462                : conn->w_timeout);
463     status = conn->meta.write(conn->meta.c_write, buf, size,
464                               n_written, timeout);
465 
466     if (status != eIO_Success) {
467         if (*n_written) {
468             CONN_TRACE(Write, "Write error");
469             status = eIO_Success;
470         } else if (size) {
471             ELOG_Level level;
472             if (status != eIO_Timeout  ||  conn->w_timeout == kDefaultTimeout)
473                 level = eLOG_Error;
474             else if (timeout  &&  (timeout->sec | timeout->usec))
475                 level = eLOG_Warning;
476             else
477                 level = eLOG_Trace;
478             CONN_LOG(17, Write, level, "Unable to write data");
479         }
480     }
481     return status;
482 }
483 
484 
485 static EIO_Status s_CONN_WritePersist
486 (CONN        conn,
487  const void* buf,
488  size_t      size,
489  size_t*     n_written)
490 {
491     EIO_Status status;
492 
493     assert(*n_written == 0);
494 
495     do {
496         size_t x_written = 0;
497         status = s_CONN_Write(conn, (char*) buf + *n_written,
498                               size - *n_written, &x_written);
499         *n_written += x_written;
500     } while (*n_written != size  &&  status == eIO_Success);
501 
502     return status;
503 }
504 
505 
506 extern EIO_Status CONN_Write
507 (CONN            conn,
508  const void*     buf,
509  size_t          size,
510  size_t*         n_written,
511  EIO_WriteMethod how)
512 {
513     EIO_Status status;
514 
515     if (!n_written)
516         return eIO_InvalidArg;
517     *n_written = 0;
518     if (size  &&  !buf)
519         return eIO_InvalidArg;
520 
521     CONN_NOT_NULL(18, Write);
522 
523     if (conn->state == eCONN_Unusable)
524         return eIO_InvalidArg;
525 
526     /* open connection, if not yet opened */
527     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
528         return status;
529     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
530 
531     switch (how) {
532     case eIO_WritePlain:
533         return s_CONN_Write(conn, buf, size, n_written);
534     case eIO_WritePersist:
535         return s_CONN_WritePersist(conn, buf, size, n_written);
536     default:
537         break;
538     }
539     return eIO_Unknown;
540 }
541 
542 
543 extern EIO_Status CONN_PushBack
544 (CONN        conn,
545  const void* buf,
546  size_t      size)
547 {
548     CONN_NOT_NULL(19, PushBack);
549 
550     if (conn->state != eCONN_Open)
551         return eIO_Closed;
552 
553     return BUF_PushBack(&conn->buf, buf, size) ? eIO_Success : eIO_Unknown;
554 }
555 
556 
557 extern EIO_Status CONN_Flush
558 (CONN conn)
559 {
560     const STimeout* timeout;
561     EIO_Status status;
562 
563     CONN_NOT_NULL(20, Flush);
564 
565     if (conn->state == eCONN_Unusable)
566         return eIO_InvalidArg;
567 
568     /* perform open, if not opened yet */
569     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
570         return status;
571     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
572 
573     /* call current connector's "FLUSH" method */
574     if (!conn->meta.flush)
575         return eIO_Success;
576     timeout = (conn->w_timeout == kDefaultTimeout
577                ? conn->meta.default_timeout
578                : conn->w_timeout);
579     status = conn->meta.flush(conn->meta.c_flush, timeout);
580 
581     if (status != eIO_Success)
582         CONN_LOG(21, Flush, eLOG_Warning, "Failed to flush");
583     return status;
584 }
585 
586 
587 /* Read or peek data from the input queue, see CONN_Read()
588  */
589 static EIO_Status s_CONN_Read
590 (CONN        conn,
591  void*       buf,
592  size_t      size,
593  size_t*     n_read,
594  int/*bool*/ peek)
595 {
596     const STimeout* timeout;
597     EIO_Status status;
598 
599     assert(*n_read == 0);
600 
601     /* check if the read method is specified at all */
602     if (!conn->meta.read) {
603         timeout = 0/*dummy*/;
604         status = eIO_NotSupported;
605         CONN_LOG(22, Read, eLOG_Error, "Cannot read data");
606         return status;
607     }
608 
609     /* read data from the internal peek buffer, if any */
610     if (size) {
611         *n_read = (peek
612                    ? BUF_Peek(conn->buf, buf, size)
613                    : BUF_Read(conn->buf, buf, size));
614         if (*n_read == size)
615             return eIO_Success;
616         buf = (char*) buf + *n_read;
617     }
618 
619     /* read data from the connection */
620     {{
621         size_t x_read = 0;
622         timeout = (conn->r_timeout == kDefaultTimeout
623                    ? conn->meta.default_timeout
624                    : conn->r_timeout);
625         /* call current connector's "READ" method */
626         status = conn->meta.read(conn->meta.c_read, buf, size - *n_read,
627                                  &x_read, timeout);
628         *n_read += x_read;
629 
630         /* save data in the internal peek buffer */
631         if (peek  &&  !BUF_Write(&conn->buf, buf, x_read)) {
632             CONN_LOG_EX(32, Read, eLOG_Error,
633                         "Cannot save peek data", 0);
634         }
635     }}
636 
637     if (status != eIO_Success) {
638         if (*n_read) {
639             CONN_TRACE(Read, "Read error");
640             status = eIO_Success;
641         } else if (size  &&  status != eIO_Closed) {
642             ELOG_Level level;
643             if (status != eIO_Timeout  ||  conn->r_timeout == kDefaultTimeout)
644                 level = eLOG_Error;
645             else if (timeout  &&  (timeout->sec | timeout->usec))
646                 level = eLOG_Warning;
647             else
648                 level = eLOG_Trace;
649             CONN_LOG(23, Read, level, "Unable to read data");
650         }
651     }
652     return status;
653 }
654 
655 
656 /* Persistently read data from the input queue, see CONN_Read()
657  */
658 static EIO_Status s_CONN_ReadPersist
659 (CONN    conn,
660  void*   buf,
661  size_t  size,
662  size_t* n_read)
663 {
664     EIO_Status status;
665 
666     assert(*n_read == 0);
667 
668     for (;;) {
669         size_t x_read = 0;
670         status = s_CONN_Read(conn, (char*) buf + *n_read,
671                              size - *n_read, &x_read, 0/*no peek*/);
672         *n_read += x_read;
673         if (*n_read == size  ||  status != eIO_Success)
674             break;
675         /* keep flushing unwritten output data (if any) */
676         if (conn->meta.flush) {
677             conn->meta.flush(conn->meta.c_flush,
678                              conn->r_timeout == kDefaultTimeout
679                              ? conn->meta.default_timeout
680                              : conn->r_timeout);
681         }
682     }
683 
684     return status;
685 }
686 
687 
688 extern EIO_Status CONN_Read
689 (CONN           conn,
690  void*          buf,
691  size_t         size,
692  size_t*        n_read,
693  EIO_ReadMethod how)
694 {
695     EIO_Status status;
696 
697     if (!n_read)
698         return eIO_InvalidArg;
699     *n_read = 0;
700     if (size  &&  !buf)
701         return eIO_InvalidArg;
702 
703     CONN_NOT_NULL(24, Read);
704 
705     if (conn->state == eCONN_Unusable)
706         return eIO_InvalidArg;
707 
708     /* perform open, if not opened yet */
709     if (conn->state != eCONN_Open  &&  (status = s_Open(conn)) != eIO_Success)
710         return status;
711     assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
712 
713     /* flush the unwritten output data (if any) */
714     if (conn->meta.flush) {
715         conn->meta.flush(conn->meta.c_flush,
716                          conn->r_timeout == kDefaultTimeout
717                          ? conn->meta.default_timeout
718                          : conn->r_timeout);
719     }
720 
721     /* now do read */
722     switch (how) {
723     case eIO_ReadPlain:
724         return s_CONN_Read(conn, buf, size, n_read, 0/*no peek*/);
725     case eIO_ReadPeek:
726         return s_CONN_Read(conn, buf, size, n_read, 1/*peek*/);
727     case eIO_ReadPersist:
728         return s_CONN_ReadPersist(conn, buf, size, n_read);
729     default:
730         break;
731     }
732     return eIO_Unknown;
733 }
734 
735 
736 extern EIO_Status CONN_ReadLine
737 (CONN    conn,
738  char*   line,
739  size_t  size,
740  size_t* n_read
741  )
742 {
743     EIO_Status  status = eIO_Success;
744     int/*bool*/ done = 0/*false*/;
745     size_t      len;
746 
747     if (!n_read)
748         return eIO_InvalidArg;
749     *n_read = 0;
750     if (size  &&  !line)
751         return eIO_InvalidArg;
752 
753     CONN_NOT_NULL(25, ReadLine);
754 
755     /* perform open, if not opened yet */
756     if (conn->state != eCONN_Open)
757         status = s_Open(conn);
758 
759     if (status == eIO_Success) {
760         assert(conn->state == eCONN_Open  &&  conn->meta.list != 0);
761         /* flush the unwritten output data (if any) */
762         if (conn->meta.flush) {
763             conn->meta.flush(conn->meta.c_flush,
764                              conn->r_timeout == kDefaultTimeout
765                              ? conn->meta.default_timeout
766                              : conn->r_timeout);
767         }
768     }
769 
770     len = 0;
771     while (status == eIO_Success) {
772         size_t i;
773         char   w[1024];
774         size_t x_read = 0;
775         size_t x_size = BUF_Size(conn->buf);
776         char*  x_buf  = size - len < sizeof(w) ? w : line + len;
777         if (x_size == 0  ||  x_size > sizeof(w))
778             x_size = sizeof(w);
779         status = s_CONN_Read(conn, x_buf, size ? x_size : 0, &x_read, 0);
780         for (i = 0; i < x_read  &&  len < size; i++) {
781             char c = x_buf[i];
782             if (c == '\n') {
783                 done = 1/*true*/;
784                 i++;
785                 break;
786             }
787             if (x_buf == w)
788                 line[len] = c;
789             len++;
790         }
791         if (i < x_read  &&  !BUF_PushBack(&conn->buf, x_buf + i, x_read - i)) {
792             const STimeout* timeout = 0;
793             CONN_LOG_EX(15, ReadLine, eLOG_Error,
794                         "Cannot pushback extra data", 0);
795         }
796         if (done  ||  len >= size)
797             break;
798     }
799     if (len < size)
800         line[len] = '\0';
801     *n_read = len;
802 
803     return status;
804 }
805 
806 
807 extern EIO_Status CONN_Status(CONN conn, EIO_Event dir)
808 {
809     CONN_NOT_NULL(26, Status);
810 
811     if (conn->state == eCONN_Unusable  ||  !conn->meta.list)
812         return eIO_Unknown;
813 
814     if (dir != eIO_Read  &&  dir != eIO_Write)
815         return eIO_InvalidArg;
816 
817     if (conn->state == eCONN_Closed)
818         return eIO_Closed;
819 
820     if (!conn->meta.status)
821         return eIO_NotSupported;
822 
823     return conn->meta.status(conn->meta.c_status, dir);
824 }
825 
826 
827 extern EIO_Status CONN_Close(CONN conn)
828 {
829     FConnCallback func = 0;
830     void*         data = 0;
831 
832     CONN_NOT_NULL(27, Close);
833 
834     if (conn->state != eCONN_Unusable) {
835         func = conn->cbs[eCONN_OnClose].func;
836         data = conn->cbs[eCONN_OnClose].data;
837     }
838     /* allow close CB only once */
839     memset(&conn->cbs[eCONN_OnClose], 0, sizeof(conn->cbs[eCONN_OnClose]));
840     /* call it! */
841     if (func)
842         func(conn, eCONN_OnClose, data);
843     /* now close the connection - this also makes it "eCONN_Unusable" */
844     if (conn->meta.list)
845         CONN_ReInit(conn, 0);
846     BUF_Destroy(conn->buf);
847     conn->buf = 0;
848     free(conn);
849     return eIO_Success;
850 }
851 
852 
853 extern EIO_Status CONN_SetCallback
854 (CONN                  conn,
855  ECONN_Callback        type,
856  const SCONN_Callback* new_cb,
857  SCONN_Callback*       old_cb)
858 {
859     int i = (int) type;
860     if (i >= CONN_N_CALLBACKS)
861         return eIO_InvalidArg;
862 
863     CONN_NOT_NULL(28, SetCallback);
864 
865     if (old_cb)
866         *old_cb = conn->cbs[i];
867     if (new_cb)
868         conn->cbs[i] = *new_cb;
869     return eIO_Success;
870 }
871 
872 
873 #ifdef IMPLEMENTED__CONN_WaitAsync
874 /* Internal handler(wrapper for the user-provided handler) for CONN_WaitAsync()
875  */
876 static void s_ConnectorAsyncHandler
877 (SConnectorAsyncHandler* data,
878  EIO_Event               event,
879  EIO_Status              status)
880 {
881     /* handle the async. event */
882     data->handler(data->conn, event, status, data->data);
883 
884     /* reset */
885     verify(CONN_WaitAsync(data->conn, eIO_ReadWrite, 0, 0, 0) == eIO_Success);
886 }
887 
888 
889 extern EIO_Status CONN_WaitAsync
890 (CONN              conn,
891  EIO_Event         event,
892  FConnAsyncHandler handler,
893  void*             data,
894  FConnAsyncCleanup cleanup)
895 {
896     EIO_Status status;
897     const STimeout* timeout = 0/*dummy*/;
898     CONNECTOR  x_connector = conn->connector;
899     SConnectorAsyncHandler* x_data = &conn->async_data;
900 
901     CONN_NOT_NULL(29, WaitAsync);
902 
903     /* perform connect, if not connected yet */
904     if (!conn->connected  &&  (status = s_Open(conn)) != eIO_Success)
905         return status;
906 
907     /* reset previous handler, cleanup its data */
908     /* (call current connector's "WAIT_ASYNC" method with NULLs) */
909     status = (x_connector->vtable.wait_async
910               ? x_connector->vtable.wait_async(x_connector->handle, 0, 0)
911               : eIO_NotSupported);
912     if (status != eIO_Success) {
913         CONN_LOG(30, WaitAsync, eLOG_Error, "Cannot reset handler");
914         return status;
915     }
916     if (x_data->cleanup)
917         x_data->cleanup(x_data->data);
918     memset(x_data, '\0', sizeof(*x_data));
919 
920     /* set new handler, if specified */
921     /* (call current connector's "WAIT_ASYNC" method with new handler/data) */
922     if (!handler)
923         return eIO_Success;
924 
925     x_data->conn       = conn;
926     x_data->wait_event = event;
927     x_data->handler    = handler;
928     x_data->data       = data;
929     x_data->cleanup    = cleanup;
930 
931     status = x_connector->vtable.wait_async(x_connector->handle,
932                                             s_ConnectorAsyncHandler,
933                                             x_data);
934     if (status != eIO_Success)
935         CONN_LOG(31, WaitAsync, eLOG_Error, "Cannot set new handler");
936     return status;
937 }
938 #endif /* IMPLEMENTED__CONN_WaitAsync */
939 

source navigation ]   [ diff markup ]   [ identifier search ]   [ freetext search ]   [ file search ]  

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.