|
NCBI Home IEB Home C Toolkit docs C++ Toolkit source browser C Toolkit source browser (2) |
NCBI C Toolkit Cross ReferenceC/connect/ncbi_connection.c |
source navigation diff markup identifier search freetext search file search |
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 |
This page was automatically generated by the
LXR engine.
Visit the LXR main site for more information. |