1 /* $Id: ncbi_socket.c 620599 2020-11-24 19:06:50Z lavr $
2 * ===========================================================================
3 *
4 * PUBLIC DOMAIN NOTICE
5 * National Center for Biotechnology Information
6 *
7 * This software/database is a "United States Government Work" under the
8 * terms of the United States Copyright Act. It was written as part of
9 * the author's official duties as a United States Government employee and
10 * thus cannot be copyrighted. This software/database is freely available
11 * to the public for use. The National Library of Medicine and the U.S.
12 * Government have not placed any restriction on its use or reproduction.
13 *
14 * Although all reasonable efforts have been taken to ensure the accuracy
15 * and reliability of the software and data, the NLM and the U.S.
16 * Government do not and cannot warrant the performance or results that
17 * may be obtained by using this software or data. The NLM and the U.S.
18 * Government disclaim all warranties, express or implied, including
19 * warranties of performance, merchantability or fitness for any particular
20 * purpose.
21 *
22 * Please cite the author in any work or product based on this material.
23 *
24 * ===========================================================================
25 *
26 * Author: Anton Lavrentiev, Denis Vakatov
27 *
28 * File Description:
29 * Plain portable TCP/IP socket API for: UNIX, MS-Win, MacOS
30 * [UNIX ] -DNCBI_OS_UNIX -lresolv -lsocket -lnsl
31 * [MSWIN] -DNCBI_OS_MSWIN ws2_32.lib
32 *
33 */
34
35 /* Uncomment these(or specify "-DHAVE_GETADDRINFO -DHAVE_GETNAMEINFO") only if:
36 * 0) you are compiling this outside of the NCBI C or C++ Toolkits
37 * (USE_NCBICONF is not #define'd), and
38 * 1) your platform has "getaddrinfo()" and "getnameinfo()", and
39 * 2) you are going to use this API code in multi-thread application, and
40 * 3) "gethostbyname()" gets called somewhere else in your code, and
41 * 4) you are aware that GLIBC implementation is rather heavy (creates tons of
42 * test sockets on the fly), yet you prefer to use that API nonetheless
43 */
44
45 /* #define HAVE_GETADDRINFO 1 */
46 /* #define HAVE_GETNAMEINFO 1 */
47
48 /* Uncomment this (or specify "-DHAVE_GETHOSTBY***_R=") only if:
49 * 0) you are compiling this outside of the NCBI C or C++ Toolkits
50 * (USE_NCBICONF is not #define'd), and
51 * 1) your platform has "gethostbyname_r()" but not "getnameinfo()", and
52 * 2) you are going to use this API code in multi-thread application, and
53 * 3) "gethostbyname()" gets called somewhere else in your code
54 */
55
56 /* Solaris: */
57 /* #define HAVE_GETHOSTBYNAME_R 5 */
58 /* #define HAVE_GETHOSTBYADDR_R 7 */
59
60 /* Linux, IRIX: */
61 /* #define HAVE_GETHOSTBYNAME_R 6 */
62 /* #define HAVE_GETHOSTBYADDR_R 8 */
63
64 /* Uncomment this (or specify "-DHAVE_SIN_LEN") only if:
65 * 0) you are compiling this outside of the NCBI C or C++ Toolkits
66 * (USE_NCBICONF is not #define'd), and
67 * 1) on your platform, struct sockaddr_in contains a field called "sin_len"
68 * (and sockaddr_un::sun_len is then assumed to be also present).
69 */
70
71 /* #define HAVE_SIN_LEN 1 */
72
73 /* NCBI core headers
74 */
75 #include "ncbi_ansi_ext.h"
76 #include "ncbi_connssl.h"
77 #include "ncbi_once.h"
78 #include <connect/ncbi_connutil.h>
79 #include <connect/ncbi_socket_unix.h>
80
81 /* Remaining platform-specific system headers
82 */
83 #ifdef NCBI_OS_UNIX
84 # include <fcntl.h>
85 # include <netdb.h>
86 # include <netinet/in.h>
87 # include <netinet/tcp.h>
88 # ifdef NCBI_OS_LINUX
89 # ifndef IP_MTU
90 # define IP_MTU 14
91 # endif /*!IP_MTU*/
92 # endif /*NCBI_OS_LINUX*/
93 # if !defined(NCBI_OS_BEOS)
94 # include <arpa/inet.h>
95 # endif /*NCBI_OS_BEOS*/
96 # include <signal.h>
97 # include <sys/param.h>
98 # ifdef HAVE_POLL_H
99 # include <sys/poll.h>
100 # ifndef POLLRDHUP
101 # define POLLRDHUP POLLHUP
102 # endif /*!POLLRDHUP*/
103 # endif /*HAVE_POLL_H*/
104 # include <sys/stat.h>
105 # include <sys/un.h>
106 # include <unistd.h>
107 #endif /*NCBI_OS_UNIX*/
108
109 /* Portable standard C headers
110 */
111 #include <ctype.h>
112 #include <stdlib.h>
113
114 #define NCBI_USE_ERRCODE_X Connect_Socket
115
116
117 #ifndef INADDR_LOOPBACK
118 # define INADDR_LOOPBACK 0x7F000001
119 #endif /*!INADDR_LOOPBACK*/
120 #ifndef IN_LOOPBACKNET
121 # define IN_LOOPBACKNET 127
122 #endif /*!IN_LOOPBACKNET*/
123 #ifdef IN_CLASSA_MAX
124 # if IN_CLASSA_MAX <= IN_LOOPBACKNET
125 # error "IN_LOOPBACKNET is out of range"
126 # endif /*IN_CLASSA_MAX<=IN_LOOPBACKNET*/
127 #endif /*IN_CLASSA_MAX*/
128
129 #ifdef NCBI_COMPILER_MSVC
130 # define sys_gethostname(a, b) gethostname(a, (int)(b))
131 #else
132 # define sys_gethostname gethostname
133 #endif
134
135
136 #ifdef NCBI_MONKEY
137 /* A hack - we assume that SOCK variable is named "sock" in the code.
138 If the desired behavior is timeout, "sock" will be replaced with a
139 connection to a non-responsive server */
140 # define send(a,b,c,d) \
141 (g_MONKEY_Send ? g_MONKEY_Send(a,b,c,d,&sock) : send(a,b,c,d))
142 # define recv(a,b,c,d) \
143 (g_MONKEY_Recv ? g_MONKEY_Recv(a,b,c,d,&sock) : recv(a,b,c,d))
144 # define connect(a,b,c) \
145 (g_MONKEY_Connect ? g_MONKEY_Connect(a,b,c) : connect(a,b,c))
146 #endif /*NCBI_MONKEY*/
147
148
149 /******************************************************************************
150 * TYPEDEFS & MACROS
151 */
152
153
154 /* Minimal size of the data buffer chunk in the socket internal buffer(s) */
155 #define SOCK_BUF_CHUNK_SIZE 16384
156
157 /* Macros for platform-dependent constants, error codes and functions
158 */
159 #if defined(NCBI_OS_MSWIN)
160
161 # define SOCK_GHBX_MT_SAFE 1 /* for gethostby...() */
162 # define SOCK_SEND_SLICE (4 << 10) /* 4K */
163 # define SOCK_INVALID INVALID_SOCKET
164 # define SOCK_ERRNO WSAGetLastError()
165 # define SOCK_NFDS(s) 0
166 # define SOCK_CLOSE(s) closesocket(s)
167 # define SOCK_EVENTS (FD_CLOSE|FD_CONNECT|FD_OOB|FD_WRITE|FD_READ)
168 # define WIN_INT_CAST (int)
169 # ifndef WSA_INVALID_EVENT
170 # define WSA_INVALID_EVENT ((WSAEVENT) 0)
171 # endif /*!WSA_INVALID_EVENT*/
172 /* NCBI_OS_MSWIN */
173
174 #elif defined(NCBI_OS_UNIX)
175
176 # ifdef NCBI_OS_CYGWIN
177 /* These do not work correctly as of cygwin 2.11.1 */
178 # ifdef SOCK_NONBLOCK
179 # undef SOCK_NONBLOCK
180 # endif /*SOCK_NONBLOCK*/
181 # ifdef SOCK_CLOEXEC
182 # undef SOCK_CLOEXEC
183 # endif /*SOCK_CLOEXEC*/
184 # endif /*NCBI_OS_CYGWIN*/
185
186 # define SOCK_INVALID (-1)
187 # define SOCK_ERRNO errno
188 # define SOCK_NFDS(s) ((s) + 1)
189 # define WIN_INT_CAST /* no cast */
190 # ifdef NCBI_OS_BEOS
191 # define SOCK_CLOSE(s) closesocket(s)
192 # else
193 # define SOCK_CLOSE(s) close(s)
194 # endif /*NCBI_OS_BEOS*/
195 # ifndef INADDR_NONE
196 # define INADDR_NONE ((unsigned int)(~0UL))
197 # endif /*INADDR_NONE*/
198 /* NCBI_OS_UNIX */
199
200 # if defined(TCP_NOPUSH) && !defined(TCP_CORK)
201 # define TCP_CORK TCP_NOPUSH /* BSDism */
202 # endif /*TCP_NOPUSH && !TCP_CORK*/
203
204 #endif /*NCBI_OS*/
205
206 #ifdef sun
207 # undef sun
208 #endif /*sun*/
209
210 #ifndef abs
211 # define abs(a) ((a) < 0 ? -(a) : (a))
212 #endif /*!abs*/
213
214 #define MAXIDLEN 80
215
216 #define SOCK_STRERROR(error) s_StrError(0, (error))
217
218 #define SOCK_LOOPBACK (assert(INADDR_LOOPBACK), htonl(INADDR_LOOPBACK))
219
220 #define SOCK_GET_TIMEOUT(s, t) ((s)->t##_tv_set ? &(s)->t##_tv : 0)
221
222 #define SOCK_SET_TIMEOUT(s, t, v) (((s)->t##_tv_set = (v) ? 1 : 0) \
223 ? (void)((s)->t##_tv = *(v)) : (void) 0)
224
225
226 #if defined(HAVE_SOCKLEN_T) || defined(_SOCKLEN_T)
227 typedef socklen_t TSOCK_socklen_t;
228 #else
229 typedef int TSOCK_socklen_t;
230 #endif /*HAVE_SOCKLEN_T || _SOCKLEN_T*/
231
232
233
234 /******************************************************************************
235 * INTERNAL GLOBALS
236 */
237
238
239 const char g_kNcbiSockNameAbbr[] = "SOCK";
240
241
242
243 /******************************************************************************
244 * STATIC GLOBALS
245 */
246
247
248 /* Flag to indicate whether the API has been [de]initialized */
249 static volatile int/*bool*/ s_Initialized = 0/*-1=deinit;0=uninit;1=init*/;
250
251 /* Which wait API to use, UNIX only */
252 static ESOCK_IOWaitSysAPI s_IOWaitSysAPI = eSOCK_IOWaitSysAPIAuto;
253
254 /* Through ID counter */
255 static volatile unsigned int s_ID_Counter = 0;
256
257 /* Read-while-writing switch */
258 static ESwitch s_ReadOnWrite = eOff; /* no read-on-write by default */
259
260 /* Reuse address flag for newly created stream sockets */
261 static ESwitch s_ReuseAddress = eOff; /* off by default */
262
263 /* I/O restart on signals */
264 static ESwitch s_InterruptOnSignal = eOff; /* restart I/O by default */
265
266 /* Data/event logging */
267 static ESwitch s_Log = eOff; /* no logging by default */
268
269 /* Select restart timeout */
270 static const struct timeval* s_SelectTimeout = 0; /* =0 (disabled) by default*/
271
272 /* Flag to indicate whether API should mask SIGPIPE (during initialization) */
273 #ifdef NCBI_OS_UNIX
274 static int/*bool*/ s_AllowSigPipe = 0/*false - mask SIGPIPE out*/;
275 #endif /*NCBI_OS_UNIX*/
276
277 /* SSL support */
278 static SOCKSSL s_SSL;
279 static FSSLSetup volatile s_SSLSetup;
280
281 /* External error reporting */
282 static FSOCK_ErrHook volatile s_ErrHook;
283 static void* volatile s_ErrData;
284
285
286
287 /******************************************************************************
288 * ERROR REPORTING
289 */
290
291
292 #define NCBI_INCLUDE_STRERROR_C
293 #include "ncbi_strerror.c"
294
295
s_StrError(SOCK sock,int error)296 static const char* s_StrError(SOCK sock, int error)
297 {
298 if (!error)
299 return 0;
300
301 if (sock && error < 0) {
302 FSSLError sslerror = sock->sslctx && s_SSL ? s_SSL->Error : 0;
303 if (sslerror) {
304 char errbuf[256];
305 const char* strerr = sslerror(sock->sslctx->sess, error,
306 errbuf, sizeof(errbuf));
307 if (strerr && *strerr)
308 return ERR_STRDUP(strerr);
309 }
310 }
311 return s_StrErrorInternal(error);
312 }
313
314
315 #ifdef NCBI_OS_MSWIN
s_WinStrerror(DWORD error)316 static const char* s_WinStrerror(DWORD error)
317 {
318 TCHAR* str;
319 DWORD rv;
320
321 if (!error)
322 return 0;
323 str = NULL;
324 rv = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
325 FORMAT_MESSAGE_FROM_SYSTEM |
326 FORMAT_MESSAGE_MAX_WIDTH_MASK |
327 FORMAT_MESSAGE_IGNORE_INSERTS,
328 NULL, error,
329 MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
330 (LPTSTR) &str, 0, NULL);
331 if (!rv && str) {
332 LocalFree((HLOCAL) str);
333 return 0;
334 }
335 return UTIL_TcharToUtf8OnHeap(str);
336 }
337 #endif /*NCBI_OS_MSWIN*/
338
339
s_ErrorCallback(const SSOCK_ErrInfo * info)340 static void s_ErrorCallback(const SSOCK_ErrInfo* info)
341 {
342 FSOCK_ErrHook hook;
343 void* data;
344
345 CORE_LOCK_READ;
346 hook = s_ErrHook;
347 data = s_ErrData;
348 CORE_UNLOCK;
349 if (hook)
350 hook(info, data);
351 }
352
353
SOCK_SetErrHookAPI(FSOCK_ErrHook hook,void * data)354 extern void SOCK_SetErrHookAPI(FSOCK_ErrHook hook, void* data)
355 {
356 CORE_LOCK_WRITE;
357 s_ErrData = data;
358 s_ErrHook = hook;
359 CORE_UNLOCK;
360 }
361
362
363
364 /******************************************************************************
365 * DATA LOGGING
366 */
367
368
s_CP(unsigned int host,unsigned short port,const char * path,char * buf,size_t bufsize)369 static const char* s_CP(unsigned int host, unsigned short port,
370 const char* path, char* buf, size_t bufsize)
371 {
372 if (path[0])
373 return path;
374 if (!(host | port))
375 return "";
376 SOCK_HostPortToString(host, port, buf, bufsize);
377 return buf;
378 }
379
380
s_ID(const SOCK sock,char buf[MAXIDLEN])381 static const char* s_ID(const SOCK sock, char buf[MAXIDLEN])
382 {
383 const char* sname;
384 const char* cp;
385 char addr[40];
386 char fd[20];
387 size_t len;
388 int n;
389
390 if (!sock)
391 return "";
392 switch (sock->type) {
393 case eTrigger:
394 cp = "";
395 sname = "TRIGGER";
396 break;
397 case eSocket:
398 cp = s_CP(sock->host, sock->port,
399 #ifdef NCBI_OS_UNIX
400 sock->path,
401 #else
402 "",
403 #endif /*NCBI_OS_UNIX*/
404 addr, sizeof(addr));
405 #ifdef NCBI_OS_UNIX
406 if (sock->path[0])
407 sname = sock->sslctx ? "SUSOCK" : "USOCK";
408 else
409 #endif /*NCBI_OS_UNIX*/
410 sname = sock->sslctx ? "SSOCK" : g_kNcbiSockNameAbbr;
411 break;
412 case eDatagram:
413 sname = "DSOCK";
414 addr[0] = '\0';
415 n = sock->myport ? sprintf(addr, "(:%hu)", sock->myport) : 0;
416 if (sock->host || sock->port) {
417 SOCK_HostPortToString(sock->host, sock->port,
418 addr + n, sizeof(addr) - (size_t) n);
419 }
420 cp = addr;
421 break;
422 case eListening:
423 #ifdef NCBI_OS_UNIX
424 if (!sock->myport)
425 cp = ((LSOCK) sock)->path;
426 else
427 #endif /*NCBI_OS_UNIX*/
428 {
429 sprintf(addr, ":%hu", sock->myport);
430 cp = addr;
431 }
432 sname = "LSOCK";
433 break;
434 default:
435 cp = "";
436 sname = "?";
437 assert(0);
438 break;
439 }
440
441 if (sock->sock != SOCK_INVALID)
442 sprintf(fd, "%u", (unsigned int) sock->sock);
443 else
444 strcpy(fd, "?");
445 len = cp && *cp ? strlen(cp) : 0;
446 n = (int)(len > sizeof(addr) - 1 ? sizeof(addr) - 1 : len);
447 sprintf(buf, "%s#%u[%s]%s%s%.*s: ", sname, sock->id, fd,
448 &"@"[!n], (size_t) n < len ? "..." : "", n, cp + len - n);
449 return buf;
450 }
451
452
s_GetLocalPort(TSOCK_Handle fd)453 static unsigned short s_GetLocalPort(TSOCK_Handle fd)
454 {
455 struct sockaddr_in sin;
456 TSOCK_socklen_t sinlen = (TSOCK_socklen_t) sizeof(sin);
457 memset(&sin, 0, sizeof(sin));
458 #ifdef HAVE_SIN_LEN
459 sin.sin_len = sinlen;
460 #endif /*HAVE_SIN_LEN*/
461 if (getsockname(fd, (struct sockaddr*) &sin, &sinlen) == 0
462 && sin.sin_family == AF_INET) {
463 return ntohs(sin.sin_port);
464 }
465 return 0;
466 }
467
468
469 /* Put socket description to the message, then log the transferred data
470 */
s_DoLog(ELOG_Level level,const SOCK sock,EIO_Event event,const void * data,size_t size,const void * ptr)471 static void s_DoLog(ELOG_Level level, const SOCK sock, EIO_Event event,
472 const void* data, size_t size, const void* ptr)
473 {
474 const struct sockaddr_in* sin;
475 const char* what, *strerr;
476 char _id[MAXIDLEN];
477 char head[128];
478 char tail[128];
479 int n;
480
481 if (!CORE_GetLOG())
482 return;
483
484 assert(sock && (sock->type & eSocket));
485 switch (event) {
486 case eIO_Open:
487 if (sock->type != eDatagram) {
488 unsigned short port;
489 if (sock->side == eSOCK_Client) {
490 what = ptr ? (const char*) ptr : "Connecting";
491 strcpy(head, *what ? what : "Re-using");
492 port = sock->myport;
493 } else if (!ptr) {
494 strcpy(head, "Accepted");
495 port = 0;
496 } else {
497 strcpy(head, "Created");
498 port = sock->myport;
499 }
500 if (!port) {
501 #ifdef NCBI_OS_UNIX
502 if (!sock->path[0])
503 #endif /*NCBI_OS_UNIX*/
504 port = s_GetLocalPort(sock->sock);
505 }
506 if (port) {
507 sprintf(tail, " @:%hu", port);
508 if (!sock->myport) {
509 /* here: not LSOCK_Accept()'d network sockets only */
510 assert(sock->side == eSOCK_Client || ptr);
511 sock->myport = port; /*cache it*/
512 }
513 } else
514 *tail = '\0';
515 } else if (!(sin = (const struct sockaddr_in*) ptr)) {
516 strcpy(head, "Created");
517 *tail = '\0';
518 } else if (!data) {
519 strcpy(head, "Bound @");
520 sprintf(tail, "(:%hu)", ntohs(sin->sin_port));
521 } else if (sin->sin_family == AF_INET) {
522 strcpy(head, "Associated ");
523 SOCK_HostPortToString(sin->sin_addr.s_addr,
524 ntohs(sin->sin_port),
525 tail, sizeof(tail));
526 } else {
527 strcpy(head, "Disassociated");
528 *tail = '\0';
529 }
530 CORE_LOGF_X(112, level,
531 ("%s%s%s", s_ID(sock, _id), head, tail));
532 break;
533
534 case eIO_Read:
535 case eIO_Write:
536 strerr = 0;
537 what = (event == eIO_Read
538 ? (sock->type == eDatagram || size ||
539 (data && !(strerr = s_StrError(sock, *((int*) data))))
540 ? "Read"
541 : data ? strerr : "EOF hit")
542 : (sock->type == eDatagram || size ||
543 !(strerr = s_StrError(sock, *((int*) data)))
544 ? "Written"
545 : strerr));
546
547 n = (int) strlen(what);
548 while (n && isspace((unsigned char) what[n - 1]))
549 --n;
550 if (n > 1 && what[n - 1] == '.')
551 --n;
552 if (sock->type == eDatagram) {
553 sin = (const struct sockaddr_in*) ptr;
554 assert(sin && sin->sin_family == AF_INET);
555 SOCK_HostPortToString(sin->sin_addr.s_addr,
556 ntohs(sin->sin_port),
557 head, sizeof(head));
558 sprintf(tail, ", msg# %" NCBI_BIGCOUNT_FORMAT_SPEC,
559 event == eIO_Read ? sock->n_in : sock->n_out);
560 } else if (!ptr || !*((char*) ptr)) {
561 sprintf(head, " at offset %" NCBI_BIGCOUNT_FORMAT_SPEC,
562 event == eIO_Read ? sock->n_read : sock->n_written);
563 strcpy(tail, ptr ? " [OOB]" : "");
564 } else {
565 strncpy0(head, (const char*) ptr, sizeof(head));
566 *tail = '\0';
567 }
568
569 CORE_DATAF_X(109, level, data, size,
570 ("%s%.*s%s%s%s", s_ID(sock, _id), n, what,
571 sock->type == eDatagram
572 ? (event == eIO_Read ? " from " : " to ")
573 : size || !data ? "" : strerr
574 ? (event == eIO_Read
575 ? " while reading" : " while writing")
576 : " 0 bytes",
577 head, tail));
578
579 UTIL_ReleaseBuffer(strerr);
580 break;
581
582 case eIO_Close:
583 n = sprintf(head, "%" NCBI_BIGCOUNT_FORMAT_SPEC " byte%s",
584 sock->n_written, &"s"[sock->n_written == 1]);
585 if (sock->type == eDatagram ||
586 sock->n_out != sock->n_written) {
587 sprintf(head + n, "/%" NCBI_BIGCOUNT_FORMAT_SPEC " %s%s",
588 sock->n_out,
589 sock->type == eDatagram ? "msg" : "total byte",
590 &"s"[sock->n_out == 1]);
591 }
592 n = sprintf(tail, "%" NCBI_BIGCOUNT_FORMAT_SPEC " byte%s",
593 sock->n_read, &"s"[sock->n_read == 1]);
594 if (sock->type == eDatagram ||
595 sock->n_in != sock->n_read) {
596 sprintf(tail + n, "/%" NCBI_BIGCOUNT_FORMAT_SPEC " %s%s",
597 sock->n_in,
598 sock->type == eDatagram ? "msg" : "total byte",
599 &"s"[sock->n_in == 1]);
600 }
601 CORE_LOGF_X(113, level,
602 ("%s%s (out: %s, in: %s)", s_ID(sock, _id),
603 ptr ? (const char*) ptr :
604 sock->keep ? "Leaving" : "Closing",
605 head, tail));
606 break;
607
608 default:
609 CORE_LOGF_X(1, eLOG_Error,
610 ("%s[SOCK::DoLog] "
611 " Invalid event #%u",
612 s_ID(sock, _id), (unsigned int) event));
613 assert(0);
614 break;
615 }
616 }
617
618
619
620 /******************************************************************************
621 * STimeout <--> struct timeval CONVERSIONS
622 */
623
624
625 #ifdef __GNUC__
626 inline
627 #endif /*__GNUC__*/
s_tv2to(const struct timeval * tv,STimeout * to)628 static STimeout* s_tv2to(const struct timeval* tv, STimeout* to)
629 {
630 assert(tv);
631
632 /* NB: internally tv always kept normalized */
633 to->sec = (unsigned int) tv->tv_sec;
634 to->usec = (unsigned int) tv->tv_usec;
635 return to;
636 }
637
638 #ifdef __GNUC__
639 inline
640 #endif /*__GNUC__*/
s_to2tv(const STimeout * to,struct timeval * tv)641 static struct timeval* s_to2tv(const STimeout* to, struct timeval* tv)
642 {
643 if (!to)
644 return 0;
645
646 tv->tv_sec = to->usec / 1000000 + to->sec;
647 tv->tv_usec = to->usec % 1000000;
648 return tv;
649 }
650
651
652
653 /******************************************************************************
654 * API INITIALIZATION, SHUTDOWN/CLEANUP, and UTILITY
655 */
656
657
658 #if defined(_DEBUG) && !defined(NDEBUG)
659 # if !defined(__GNUC__) && !defined(offsetof)
660 # define offsetof(T, F) ((size_t)((char*) &(((T*) 0)->F) - (char*) 0))
661 # endif
662 #endif /*_DEBUG && !NDEBUG*/
663
664 #if defined(_DEBUG) && !defined(NDEBUG)
665
666 # ifndef SOCK_HAVE_SHOWDATALAYOUT
667 # define SOCK_HAVE_SHOWDATALAYOUT 1
668 # endif /* SOCK_HAVE_SHOWDATALAYOUT */
669
670 #endif /*__GNUC__ && _DEBUG && !NDEBUG*/
671
672 #ifdef SOCK_HAVE_SHOWDATALAYOUT
673
674 # define extentof(T, F) (sizeof(((T*) 0)->F))
675
676 # define infof(T, F) (unsigned int) offsetof(T, F), \
677 (unsigned int) extentof(T, F)
678
x_ShowDataLayout(void)679 static void x_ShowDataLayout(void)
680 {
681 static const char kLayoutFormat[] = {
682 "SOCK data layout:\n"
683 " Sizeof(TRIGGER_struct) = %u\n"
684 " Sizeof(LSOCK_struct) = %u\n"
685 " Sizeof(SOCK_struct) = %u, offsets (sizes) follow\n"
686 "\tsock: %3u (%u)\n"
687 "\tid: %3u (%u)\n"
688 "\tisset: %3u (%u)\n"
689 "\thost: %3u (%u)\n"
690 "\tport: %3u (%u)\n"
691 "\tmyport: %3u (%u)\n"
692 "\terr: %3u (%u)\n"
693 "\tbitfield: (4)\n"
694 # ifdef NCBI_OS_MSWIN
695 "\tevent: %3u (%u)\n"
696 # endif /*NCBI_OS_MSWIN*/
697 "\tsslctx: %3u (%u)\n"
698 "\tr_tv: %3u (%u)\n"
699 "\tw_tv: %3u (%u)\n"
700 "\tc_tv: %3u (%u)\n"
701 "\tr_to: %3u (%u)\n"
702 "\tw_to: %3u (%u)\n"
703 "\tc_to: %3u (%u)\n"
704 "\tr_buf: %3u (%u)\n"
705 "\tw_buf: %3u (%u)\n"
706 "\tr_len: %3u (%u)\n"
707 "\tw_len: %3u (%u)\n"
708 "\tn_read: %3u (%u)\n"
709 "\tn_written: %3u (%u)\n"
710 "\tn_in: %3u (%u)\n"
711 "\tn_out: %3u (%u)"
712 # ifdef NCBI_OS_UNIX
713 "\n\tpath: %3u (%u)"
714 # endif /*NCBI_OS_UNIX*/
715 };
716 # ifdef NCBI_OS_MSWIN
717 # define SOCK_SHOWDATALAYOUT_PARAMS \
718 infof(SOCK_struct, sock), \
719 infof(SOCK_struct, id), \
720 infof(TRIGGER_struct, isset), \
721 infof(SOCK_struct, host), \
722 infof(SOCK_struct, port), \
723 infof(SOCK_struct, myport), \
724 infof(SOCK_struct, err), \
725 infof(SOCK_struct, event), \
726 infof(SOCK_struct, sslctx), \
727 infof(SOCK_struct, r_tv), \
728 infof(SOCK_struct, w_tv), \
729 infof(SOCK_struct, c_tv), \
730 infof(SOCK_struct, r_to), \
731 infof(SOCK_struct, w_to), \
732 infof(SOCK_struct, c_to), \
733 infof(SOCK_struct, r_buf), \
734 infof(SOCK_struct, w_buf), \
735 infof(SOCK_struct, r_len), \
736 infof(SOCK_struct, w_len), \
737 infof(SOCK_struct, n_read), \
738 infof(SOCK_struct, n_written), \
739 infof(SOCK_struct, n_in), \
740 infof(SOCK_struct, n_out)
741 # else
742 # define SOCK_SHOWDATALAYOUT_PARAMS \
743 infof(SOCK_struct, sock), \
744 infof(SOCK_struct, id), \
745 infof(TRIGGER_struct, isset), \
746 infof(SOCK_struct, host), \
747 infof(SOCK_struct, port), \
748 infof(SOCK_struct, myport), \
749 infof(SOCK_struct, err), \
750 infof(SOCK_struct, sslctx), \
751 infof(SOCK_struct, r_tv), \
752 infof(SOCK_struct, w_tv), \
753 infof(SOCK_struct, c_tv), \
754 infof(SOCK_struct, r_to), \
755 infof(SOCK_struct, w_to), \
756 infof(SOCK_struct, c_to), \
757 infof(SOCK_struct, r_buf), \
758 infof(SOCK_struct, w_buf), \
759 infof(SOCK_struct, r_len), \
760 infof(SOCK_struct, w_len), \
761 infof(SOCK_struct, n_read), \
762 infof(SOCK_struct, n_written), \
763 infof(SOCK_struct, n_in), \
764 infof(SOCK_struct, n_out), \
765 infof(SOCK_struct, path)
766 # endif /*NCBI_OS_MSWIN*/
767 CORE_LOGF_X(2, eLOG_Trace,
768 (kLayoutFormat,
769 (unsigned int) sizeof(TRIGGER_struct),
770 (unsigned int) sizeof(LSOCK_struct),
771 (unsigned int) sizeof(SOCK_struct),
772 SOCK_SHOWDATALAYOUT_PARAMS));
773 # undef SOCK_SHOWDATALAYOUT_PARAMS
774 }
775
776 #endif /*SOCK_HAVE_SHOWDATALAYOUT*/
777
778
s_Init(void)779 static EIO_Status s_Init(void)
780 {
781 CORE_TRACE("[SOCK::InitializeAPI] Begin");
782
783 CORE_LOCK_WRITE;
784
785 if (s_Initialized) {
786 CORE_UNLOCK;
787 CORE_TRACE("[SOCK::InitializeAPI] Noop");
788 return s_Initialized < 0 ? eIO_NotSupported : eIO_Success;
789 }
790
791 #ifdef SOCK_HAVE_SHOWDATALAYOUT
792 if (s_Log == eOn)
793 x_ShowDataLayout();
794 #endif /*SOCK_HAVE_SHOWDATALAYOUT*/
795
796 #if defined(_DEBUG) && !defined(NDEBUG)
797 /* Layout / alignment sanity check */
798 assert(sizeof(TRIGGER_Handle) == sizeof(TSOCK_Handle));
799 assert(offsetof(TRIGGER_struct, err) == offsetof(SOCK_struct, err));
800 assert(offsetof(TRIGGER_struct, err) == offsetof(LSOCK_struct, err));
801 assert(offsetof(SOCK_struct, sslctx) == offsetof(LSOCK_struct, context));
802 # ifdef NCBI_OS_MSWIN
803 assert(offsetof(LSOCK_struct, event) == offsetof(SOCK_struct, event));
804 assert(WSA_INVALID_EVENT == 0);
805 # endif /*NCBI_OS_MSWIN*/
806 #endif /*_DEBUG && !NDEBUG*/
807
808 #if defined(NCBI_OS_MSWIN)
809 {{
810 WSADATA wsadata;
811 int error = WSAStartup(MAKEWORD(1,1), &wsadata);
812 if (error) {
813 const char* strerr;
814
815 CORE_UNLOCK;
816 strerr = SOCK_STRERROR(error);
817 CORE_LOG_ERRNO_EXX(3, eLOG_Error,
818 error, strerr ? strerr : "",
819 "[SOCK::InitializeAPI] "
820 " Failed WSAStartup()");
821 UTIL_ReleaseBuffer(strerr);
822 return eIO_NotSupported;
823 }
824 }}
825 #elif defined(NCBI_OS_UNIX)
826 if (!s_AllowSigPipe) {
827 struct sigaction sa;
828 if (sigaction(SIGPIPE, 0, &sa) != 0 || sa.sa_handler == SIG_DFL) {
829 memset(&sa, 0, sizeof(sa));
830 sa.sa_handler = SIG_IGN;
831 sigaction(SIGPIPE, &sa, 0);
832 }
833 }
834 #endif /*NCBI_OS*/
835
836 #ifndef NCBI_OS_MSWIN
837 {{
838 static void* /*bool*/ s_AtExitSet = 0/*false*/;
839 if (CORE_Once(&s_AtExitSet))
840 atexit((void (*)(void)) SOCK_ShutdownAPI);
841 }}
842 #endif /*NCBI_OS_MSWIN*/
843
844 s_Initialized = 1/*inited*/;
845
846 CORE_UNLOCK;
847 CORE_TRACE("[SOCK::InitializeAPI] End");
848 return eIO_Success;
849 }
850
851
852 #ifdef __cplusplus
853 extern "C" {
854 #endif /*__cplusplus*/
855 static EIO_Status s_Recv(SOCK, void*, size_t, size_t*, int);
856 static EIO_Status s_Send(SOCK, const void*, size_t, size_t*, int);
857 #ifdef __cplusplus
858 }
859 #endif /*__cplusplus*/
860
861
s_InitAPI_(int secure)862 static EIO_Status s_InitAPI_(int secure)
863 {
864 static const struct SOCKSSL_struct kNoSSL = { "", 0 };
865 EIO_Status status;
866
867 if (!s_Initialized && (status = s_Init()) != eIO_Success)
868 return status;
869
870 assert(s_Initialized);
871
872 if (s_Initialized < 0)
873 return eIO_NotSupported;
874
875 if (!secure)
876 return eIO_Success;
877
878 if (s_SSL)
879 return s_SSL == &kNoSSL ? eIO_NotSupported : eIO_Success;
880
881 if (s_SSLSetup) {
882 const char* what = 0;
883 CORE_LOCK_WRITE;
884 if (!s_SSL) {
885 SOCKSSL ssl;
886 if (!s_SSLSetup || !(ssl = s_SSLSetup())) {
887 what = (const char*)(-1L);
888 s_SSL = &kNoSSL;
889 status = eIO_NotSupported;
890 } else {
891 what = ssl->Name;
892 s_SSL = ((status = ssl->Init(s_Recv, s_Send)) == eIO_Success
893 ? ssl : &kNoSSL);
894 }
895 } else
896 status = s_SSL == &kNoSSL ? eIO_NotSupported : eIO_Success;
897 CORE_UNLOCK;
898 if (status != eIO_Success && what) {
899 const char* provider;
900 char buf[40];
901 if (what == (const char*)(-1L)) {
902 sprintf(buf, "%p()", s_SSLSetup);
903 provider = buf;
904 } else
905 provider = *what ? what : "???";
906 CORE_LOGF(eLOG_Critical,
907 ("Failed to %s SSL provider %s: %s",
908 what == (const char*)(-1L) ? "setup" : "initialize",
909 provider, IO_StatusStr(status)));
910 }
911 } else {
912 static void* /*bool*/ s_Once = 0/*false*/;
913 if (CORE_Once(&s_Once)) {
914 CORE_LOG(eLOG_Critical, "Secure Socket Layer (SSL) has not"
915 " been properly initialized in the NCBI Toolkit. "
916 " Have you forgotten to call SOCK_SetupSSL[Ex]()?");
917 }
918 status = eIO_NotSupported;
919 }
920
921 return status;
922 }
923
924
925 #ifdef __GNUC__
926 inline
927 #endif /*__GNUC__*/
s_InitAPI(int secure)928 static EIO_Status s_InitAPI(int secure)
929 {
930 EIO_Status status = s_InitAPI_(secure);
931 if (s_ErrHook && status != eIO_Success) {
932 SSOCK_ErrInfo info;
933 memset(&info, 0, sizeof(info));
934 info.type = eSOCK_ErrInit;
935 info.status = status;
936 s_ErrorCallback(&info);
937 }
938 return status;
939 }
940
941
SOCK_InitializeAPI(void)942 extern EIO_Status SOCK_InitializeAPI(void)
943 {
944 EIO_Status status = s_Init();
945 if (s_ErrHook && status != eIO_Success) {
946 SSOCK_ErrInfo info;
947 memset(&info, 0, sizeof(info));
948 info.type = eSOCK_ErrInit;
949 info.status = status;
950 s_ErrorCallback(&info);
951 }
952 return status;
953 }
954
955
956 /* Must be called under a lock */
957 #ifdef __GNUC__
958 inline
959 #endif /*__GNUC__*/
x_ShutdownSSL(void)960 static void x_ShutdownSSL(void)
961 {
962 if (s_Initialized > 0) {
963 FSSLExit sslexit = s_SSLSetup && s_SSL ? s_SSL->Exit : 0;
964 s_SSLSetup = 0;
965 s_SSL = 0;
966 if (sslexit)
967 sslexit();
968 }
969 }
970
971
SOCK_ShutdownAPI(void)972 extern EIO_Status SOCK_ShutdownAPI(void)
973 {
974 if (s_Initialized < 0)
975 return eIO_Success;
976
977 CORE_TRACE("[SOCK::ShutdownAPI] Begin");
978
979 CORE_LOCK_WRITE;
980
981 if (s_Initialized <= 0) {
982 CORE_UNLOCK;
983 return eIO_Success;
984 }
985 s_Initialized = -1/*deinited*/;
986
987 x_ShutdownSSL();
988
989 #ifdef NCBI_OS_MSWIN
990 {{
991 int error = WSACleanup() ? SOCK_ERRNO : 0;
992 CORE_UNLOCK;
993 if (error) {
994 const char* strerr = SOCK_STRERROR(error);
995 CORE_LOG_ERRNO_EXX(4, eLOG_Warning,
996 error, strerr ? strerr : "",
997 "[SOCK::ShutdownAPI] "
998 " Failed WSACleanup()");
999 UTIL_ReleaseBuffer(strerr);
1000 return eIO_NotSupported;
1001 }
1002 }}
1003 #else
1004 CORE_UNLOCK;
1005 #endif /*NCBI_OS_MSWIN*/
1006
1007 CORE_TRACE("[SOCK::ShutdownAPI] End");
1008 return eIO_Success;
1009 }
1010
1011
SOCK_AllowSigPipeAPI(void)1012 extern void SOCK_AllowSigPipeAPI(void)
1013 {
1014 #ifdef NCBI_OS_UNIX
1015 s_AllowSigPipe = 1/*true - API will not mask SIGPIPE out at init*/;
1016 #endif /*NCBI_OS_UNIX*/
1017 return;
1018 }
1019
1020
SOCK_OSHandleSize(void)1021 extern size_t SOCK_OSHandleSize(void)
1022 {
1023 return sizeof(TSOCK_Handle);
1024 }
1025
1026
SOCK_SetSelectInternalRestartTimeout(const STimeout * t)1027 extern const STimeout* SOCK_SetSelectInternalRestartTimeout(const STimeout* t)
1028 {
1029 static struct timeval s_New;
1030 static STimeout s_Old;
1031 const STimeout* retval;
1032 retval = s_SelectTimeout ? s_tv2to(s_SelectTimeout, &s_Old) : 0;
1033 s_SelectTimeout = s_to2tv(t, &s_New);
1034 return retval;
1035 }
1036
1037
SOCK_SetIOWaitSysAPI(ESOCK_IOWaitSysAPI api)1038 extern ESOCK_IOWaitSysAPI SOCK_SetIOWaitSysAPI(ESOCK_IOWaitSysAPI api)
1039 {
1040 ESOCK_IOWaitSysAPI retval = s_IOWaitSysAPI;
1041 #if !defined(NCBI_OS_UNIX) || !defined(HAVE_POLL_H)
1042 if (api == eSOCK_IOWaitSysAPIPoll) {
1043 CORE_LOG_X(149, eLOG_Critical, "[SOCK::SetIOWaitSysAPI] "
1044 " Poll API requested but not supported on this platform");
1045 } else
1046 #endif /*!NCBI_OS_UNIX || !HAVE_POLL_H*/
1047 s_IOWaitSysAPI = api;
1048 return retval;
1049 }
1050
1051
1052
1053 /******************************************************************************
1054 * gethost[by]...() WRAPPERS
1055 */
1056
1057
s_gethostname(char * name,size_t namesize,ESwitch log)1058 static int s_gethostname(char* name, size_t namesize, ESwitch log)
1059 {
1060 int/*bool*/ failed;
1061
1062 CORE_TRACE("[SOCK::gethostname]");
1063
1064 name[0] = name[namesize - 1] = '\0';
1065 if (sys_gethostname(name, namesize) != 0) {
1066 if (log) {
1067 int error = SOCK_ERRNO;
1068 const char* strerr = SOCK_STRERROR(error);
1069 CORE_LOG_ERRNO_EXX(103, eLOG_Error,
1070 error, strerr ? strerr : "",
1071 "[SOCK_gethostname] "
1072 " Failed gethostname()");
1073 UTIL_ReleaseBuffer(strerr);
1074 }
1075 failed = 1/*true*/;
1076 } else if (name[namesize - 1]) {
1077 if (log) {
1078 CORE_LOGF_X(104, eLOG_Error,
1079 ("[SOCK_gethostname] "
1080 " Buffer too small (%lu)", (unsigned long) namesize));
1081 }
1082 failed = 1/*true*/;
1083 } else
1084 failed = 0/*false*/;
1085
1086 CORE_TRACEF(("[SOCK::gethostname] "
1087 " \"%.*s\"%s", (int) namesize, name,
1088 failed ? " (failed)" : ""));
1089 if (failed)
1090 *name = '\0';
1091 return *name ? 0/*success*/ : -1/*failure*/;
1092 }
1093
1094
1095 #ifdef __GNUC__
1096 inline
1097 #endif /*__GNUC__*/
x_IsAPIPA(unsigned int addr)1098 static int/*bool*/ x_IsAPIPA(unsigned int addr)
1099 {
1100 return !((addr & 0xFFFF0000) ^ 0xA9FE0000); /* 169.254/16 per IANA */
1101 }
1102
1103
x_ChooseIP(char ** addrs)1104 static const char* x_ChooseIP(char** addrs)
1105 {
1106 int n;
1107 for (n = 0; addrs[n]; ++n) {
1108 unsigned int ip;
1109 memcpy(&ip, addrs[n], sizeof(ip));
1110 if (!SOCK_IsLoopbackAddress(ip) && !x_IsAPIPA(ntohl(ip)))
1111 return addrs[n];
1112 }
1113 return addrs[0];
1114 }
1115
1116
s_gethostbyname_(const char * hostname,int not_ip,int self,ESwitch log)1117 static unsigned int s_gethostbyname_(const char* hostname,
1118 int/*bool*/ not_ip,
1119 int/*bool*/ self,
1120 ESwitch log)
1121 {
1122 char buf[CONN_HOST_LEN + 1];
1123 unsigned int host;
1124
1125 assert(!hostname || *hostname);
1126 if (!hostname) {
1127 if (s_gethostname(buf, sizeof(buf), log) != 0)
1128 return 0;
1129 #if 0/*def NCBI_OS_DARWIN*/
1130 {{
1131 char* p;
1132 if ((p = strchr(buf, '.')) != 0)
1133 *p = '\0';
1134 }}
1135 #endif /*NCBI_OS_DARWIN*/
1136 not_ip = 1/*true*/;
1137 hostname = buf;
1138 assert(*buf);
1139 }
1140
1141 CORE_TRACEF(("[SOCK::gethostbyname] \"%s\"", hostname));
1142
1143 #ifdef NCBI_OS_DARWIN
1144 if (strspn(hostname, ".0123456789") == strlen(hostname)) {
1145 /* Darwin's inet_addr() does not care for integer overflows :-/ */
1146 if (!SOCK_isip(hostname)) {
1147 host = 0;
1148 goto out;
1149 }
1150 }
1151 #endif /*NCBI_OS_DARWIN*/
1152
1153 if (not_ip || (host = inet_addr(hostname)) == htonl(INADDR_NONE)) {
1154 int error;
1155 #if defined(HAVE_GETADDRINFO) && !defined(__GLIBC__)
1156 struct addrinfo hints, *out = 0;
1157 memset(&hints, 0, sizeof(hints));
1158 hints.ai_family = AF_INET; /* currently, we only handle IPv4 */
1159 if ((error = getaddrinfo(hostname, 0, &hints, &out)) == 0 && out) {
1160 if (self && out->ai_next) {
1161 struct addrinfo* tmp = out;
1162 char* addrs[128];
1163 size_t n;
1164 for (n = 0; n < sizeof(addrs) / sizeof(addrs[0]) - 1; ++n) {
1165 struct sockaddr_in* sin
1166 = (struct sockaddr_in*) tmp->ai_addr;
1167 assert(sin->sin_family == AF_INET);
1168 addrs[n] = (char*) &sin->sin_addr;
1169 if (!(tmp = tmp->ai_next))
1170 break;
1171 }
1172 addrs[n] = 0;
1173 memcpy(&host, x_ChooseIP(addrs), sizeof(host));
1174 } else {
1175 struct sockaddr_in* sin = (struct sockaddr_in*) out->ai_addr;
1176 assert(sin->sin_family == AF_INET);
1177 host = sin->sin_addr.s_addr;
1178 }
1179 } else {
1180 if (log) {
1181 const char* strerr;
1182 if (error == EAI_SYSTEM)
1183 error = SOCK_ERRNO;
1184 else if (error)
1185 error += EAI_BASE;
1186 else
1187 error = EFAULT;
1188 strerr = SOCK_STRERROR(error);
1189 CORE_LOGF_ERRNO_EXX(105, eLOG_Warning,
1190 error, strerr ? strerr : "",
1191 ("[SOCK_gethostbyname] "
1192 " Failed getaddrinfo(\"%.*s\")",
1193 CONN_HOST_LEN, hostname));
1194 UTIL_ReleaseBuffer(strerr);
1195 }
1196 host = 0;
1197 }
1198 if (out)
1199 freeaddrinfo(out);
1200 #else /* use some variant of gethostbyname */
1201 struct hostent* he;
1202 # ifdef HAVE_GETHOSTBYNAME_R
1203 static const char suffix[] = "_r";
1204 struct hostent x_he;
1205 char x_buf[1024];
1206
1207 error = 0;
1208 # if HAVE_GETHOSTBYNAME_R == 5
1209 he = gethostbyname_r(hostname, &x_he, x_buf, sizeof(x_buf), &error);
1210 # elif HAVE_GETHOSTBYNAME_R == 6
1211 if (gethostbyname_r(hostname, &x_he, x_buf, sizeof(x_buf),
1212 &he, &error) != 0) {
1213 /*NB: retval == errno on error*/
1214 assert(he == 0);
1215 he = 0;
1216 }
1217 # else
1218 # error "Unknown HAVE_GETHOSTBYNAME_R value"
1219 # endif /*HAVE_GETHOSTNBYNAME_R == N*/
1220 if (!he) {
1221 if (!error)
1222 error = SOCK_ERRNO;
1223 else
1224 error += DNS_BASE;
1225 }
1226 # else
1227 static const char suffix[] = "";
1228
1229 # ifndef SOCK_GHBX_MT_SAFE
1230 CORE_LOCK_WRITE;
1231 # endif /*!SOCK_GHBX_MT_SAFE*/
1232
1233 he = gethostbyname(hostname);
1234 error = he ? 0 : h_errno + DNS_BASE;
1235 # endif /*HAVE_GETHOSTBYNAME_R*/
1236
1237 if (!he || he->h_addrtype != AF_INET || he->h_length != sizeof(host)) {
1238 if (he)
1239 error = EINVAL;
1240 host = 0;
1241 } else
1242 memcpy(&host, self ? x_ChooseIP(he->h_addr_list) : he->h_addr, sizeof(host));
1243
1244 # ifndef HAVE_GETHOSTBYNAME_R
1245 # ifndef SOCK_GHBX_MT_SAFE
1246 CORE_UNLOCK;
1247 # endif /*!SOCK_GHBX_MT_SAFE*/
1248 # endif /*HAVE_GETHOSTBYNAME_R*/
1249
1250 if (!host) {
1251 # ifdef NETDB_INTERNAL
1252 if (error == NETDB_INTERNAL + DNS_BASE)
1253 error = SOCK_ERRNO;
1254 # endif /*NETDB_INTERNAL*/
1255 if (error == ERANGE)
1256 log = eOn;
1257 if (log) {
1258 const char* strerr = SOCK_STRERROR(error);
1259 CORE_LOGF_ERRNO_EXX(106, eLOG_Warning,
1260 error, strerr ? strerr : "",
1261 ("[SOCK_gethostbyname] "
1262 " Failed gethostbyname%s(\"%.*s\")",
1263 suffix, CONN_HOST_LEN, hostname));
1264 UTIL_ReleaseBuffer(strerr);
1265 }
1266 }
1267 #endif /*HAVE_GETADDRINFO && !__GLIBC__*/
1268 }
1269
1270 #ifdef NCBI_OS_DARWIN
1271 out:
1272 #endif /*NCBI_OS_DARWIN*/
1273 #if defined(_DEBUG) && !defined(NDEBUG)
1274 if (!SOCK_isipEx(hostname, 1/*full-quad*/) || !host) {
1275 char addr[40];
1276 CORE_TRACEF(("[SOCK::gethostbyname] \"%s\" @ %s", hostname,
1277 SOCK_ntoa(host, addr, sizeof(addr)) == 0
1278 ? addr : sprintf(addr, "0x%08X",
1279 (unsigned int) ntohl(host))
1280 ? addr : "(unknown)"));
1281 }
1282 #endif /*_DEBUG && !NDEBUG*/
1283 return host;
1284 }
1285
1286
1287 /* a non-standard helper */
s_getlocalhostaddress(ESwitch reget,ESwitch log)1288 static unsigned int s_getlocalhostaddress(ESwitch reget, ESwitch log)
1289 {
1290 static void* /*bool*/ s_Once = 0/*false*/;
1291 /* cached IP address of the local host */
1292 static unsigned int s_LocalHostAddress = 0;
1293 if (reget == eOn || (!s_LocalHostAddress && reget != eOff))
1294 s_LocalHostAddress = s_gethostbyname_(0, 0, 1/*self*/, log);
1295 if (s_LocalHostAddress)
1296 return s_LocalHostAddress;
1297 if (reget != eOff && CORE_Once(&s_Once)) {
1298 CORE_LOGF_X(9, reget == eDefault ? eLOG_Warning : eLOG_Error,
1299 ("[SOCK::GetLocalHostAddress] "
1300 " Cannot obtain local host address%s",
1301 reget == eDefault ? ", using loopback instead" : ""));
1302 }
1303 return reget == eDefault ? SOCK_LOOPBACK : 0;
1304 }
1305
1306
s_gethostbyname(const char * hostname,int not_ip,ESwitch log)1307 static unsigned int s_gethostbyname(const char* hostname,
1308 int/*bool*/ not_ip,
1309 ESwitch log)
1310 {
1311 static void* /*bool*/ s_Once = 0/*false*/;
1312 unsigned int retval;
1313
1314 if (hostname && !*hostname)
1315 hostname = 0;
1316 if (!(retval = s_gethostbyname_(hostname, not_ip, 0, log))) {
1317 if (s_ErrHook) {
1318 SSOCK_ErrInfo info;
1319 memset(&info, 0, sizeof(info));
1320 info.type = eSOCK_ErrDns;
1321 info.host = hostname;
1322 s_ErrorCallback(&info);
1323 }
1324 } else if (!s_Once && !hostname
1325 && SOCK_IsLoopbackAddress(retval) && CORE_Once(&s_Once)) {
1326 char addr[40 + 1];
1327 *addr = " "[SOCK_ntoa(retval, addr + 1, sizeof(addr) - 1) ? 1 : 0];
1328 CORE_LOGF_X(155, eLOG_Warning,
1329 ("[SOCK::gethostbyname] "
1330 " Got loopback address%s for local host name", addr));
1331 }
1332
1333 return retval;
1334 }
1335
1336
s_gethostbyaddr_(unsigned int host,char * name,size_t namesize,ESwitch log)1337 static char* s_gethostbyaddr_(unsigned int host, char* name,
1338 size_t namesize, ESwitch log)
1339 {
1340 char addr[40];
1341
1342 if (!host)
1343 host = s_getlocalhostaddress(eDefault, log);
1344
1345 CORE_TRACEF(("[SOCK::gethostbyaddr] %s",
1346 SOCK_ntoa(host, addr, sizeof(addr)) == 0
1347 ? addr : sprintf(addr, "0x%08X", (unsigned int) ntohl(host))
1348 ? addr : "(unknown)"));
1349
1350 if (host) {
1351 int error;
1352 #if defined(HAVE_GETNAMEINFO) && !defined(__GLIBC__)
1353 struct sockaddr_in sin;
1354
1355 memset(&sin, 0, sizeof(sin));
1356 # ifdef HAVE_SIN_LEN
1357 sin.sin_len = (TSOCK_socklen_t) sizeof(sin);
1358 # endif /*HAVE_SIN_LEN*/
1359 sin.sin_family = AF_INET; /* we only handle IPv4 currently */
1360 sin.sin_addr.s_addr = host;
1361 if ((error = getnameinfo((struct sockaddr*) &sin, sizeof(sin),
1362 name, namesize, 0, 0, 0)) != 0 || !*name) {
1363 if (SOCK_ntoa(host, name, namesize) != 0) {
1364 if (error == EAI_SYSTEM)
1365 error = SOCK_ERRNO;
1366 else if (error)
1367 error += EAI_BASE;
1368 else {
1369 # ifdef ENOSPC
1370 error = ENOSPC;
1371 # else
1372 error = ERANGE;
1373 # endif /*ENOSPC*/
1374 log = eOn;
1375 }
1376 name[0] = '\0';
1377 name = 0;
1378 }
1379 if (!name && log) {
1380 const char* strerr = SOCK_STRERROR(error);
1381 if (SOCK_ntoa(host, addr, sizeof(addr)) != 0)
1382 sprintf(addr, "0x%08X", (unsigned int) ntohl(host));
1383 CORE_LOGF_ERRNO_EXX(107, eLOG_Warning,
1384 error, strerr ? strerr : "",
1385 ("[SOCK_gethostbyaddr] "
1386 " Failed getnameinfo(%s)",
1387 addr));
1388 UTIL_ReleaseBuffer(strerr);
1389 }
1390 }
1391 #else /* use some variant of gethostbyaddr */
1392 struct hostent* he;
1393 # ifdef HAVE_GETHOSTBYADDR_R
1394 static const char suffix[] = "_r";
1395 struct hostent x_he;
1396 char x_buf[1024];
1397
1398 error = 0;
1399 # if HAVE_GETHOSTBYADDR_R == 7
1400 he = gethostbyaddr_r((char*) &host, sizeof(host), AF_INET, &x_he,
1401 x_buf, sizeof(x_buf), &error);
1402 # elif HAVE_GETHOSTBYADDR_R == 8
1403 if (gethostbyaddr_r((char*) &host, sizeof(host), AF_INET, &x_he,
1404 x_buf, sizeof(x_buf), &he, &error) != 0) {
1405 /*NB: retval == errno on error*/
1406 assert(he == 0);
1407 he = 0;
1408 }
1409 # else
1410 # error "Unknown HAVE_GETHOSTBYADDR_R value"
1411 # endif /*HAVE_GETHOSTBYADDR_R == N*/
1412 if (!he) {
1413 if (!error)
1414 error = SOCK_ERRNO;
1415 else
1416 error += DNS_BASE;
1417 }
1418 # else /*HAVE_GETHOSTBYADDR_R*/
1419 static const char suffix[] = "";
1420
1421 # ifndef SOCK_GHBX_MT_SAFE
1422 CORE_LOCK_WRITE;
1423 # endif /*!SOCK_GHBX_MT_SAFE*/
1424
1425 he = gethostbyaddr((char*) &host, sizeof(host), AF_INET);
1426 error = he ? 0 : h_errno + DNS_BASE;
1427 # endif /*HAVE_GETHOSTBYADDR_R*/
1428
1429 if (!he || strlen(he->h_name) >= namesize) {
1430 if (he || SOCK_ntoa(host, name, namesize) != 0) {
1431 #ifdef ENOSPC
1432 error = ENOSPC;
1433 #else
1434 error = ERANGE;
1435 #endif /*ENOSPC*/
1436 log = eOn;
1437 name[0] = '\0';
1438 name = 0;
1439 }
1440 } else
1441 strcpy(name, he->h_name);
1442
1443 # ifndef HAVE_GETHOSTBYADDR_R
1444 # ifndef SOCK_GHBX_MT_SAFE
1445 CORE_UNLOCK;
1446 # endif /*!SOCK_GHBX_MT_SAFE*/
1447 # endif /*HAVE_GETHOSTBYADDR_R*/
1448
1449 if (!name) {
1450 # ifdef NETDB_INTERNAL
1451 if (error == NETDB_INTERNAL + DNS_BASE)
1452 error = SOCK_ERRNO;
1453 # endif /*NETDB_INTERNAL*/
1454 if (error == ERANGE)
1455 log = eOn;
1456 if (log) {
1457 const char* strerr = SOCK_STRERROR(error);
1458 if (SOCK_ntoa(host, addr, sizeof(addr)) != 0)
1459 sprintf(addr, "0x%08X", (unsigned int) ntohl(host));
1460 CORE_LOGF_ERRNO_EXX(108, eLOG_Warning,
1461 error, strerr ? strerr : "",
1462 ("[SOCK_gethostbyaddr] "
1463 " Failed gethostbyaddr%s(%s)",
1464 suffix, addr));
1465 UTIL_ReleaseBuffer(strerr);
1466 }
1467 }
1468 #endif /*HAVE_GETNAMEINFO && !__GLIBC__*/
1469 } else {
1470 name[0] = '\0';
1471 name = 0;
1472 }
1473
1474 CORE_TRACEF(("[SOCK::gethostbyaddr] %s @ %s%s%s",
1475 SOCK_ntoa(host, addr, sizeof(addr)) == 0
1476 ? addr : sprintf(addr, "0x%08X", (unsigned int) ntohl(host))
1477 ? addr : "(unknown)",
1478 &"\""[!name], name ? name : "(unknown)", &"\""[!name]));
1479 return name;
1480 }
1481
1482
s_gethostbyaddr(unsigned int host,char * name,size_t namesize,ESwitch log)1483 static const char* s_gethostbyaddr(unsigned int host, char* name,
1484 size_t namesize, ESwitch log)
1485 {
1486 static void* /*bool*/ s_Once = 0/*false*/;
1487 const char* retval = s_gethostbyaddr_(host, name, namesize, log);
1488 if (!s_Once && retval
1489 && ((SOCK_IsLoopbackAddress(host)
1490 && strncasecmp(retval, "localhost", 9) != 0) ||
1491 (!host
1492 && strncasecmp(retval, "localhost", 9) == 0))
1493 && CORE_Once(&s_Once)) {
1494 CORE_LOGF_X(10, eLOG_Warning,
1495 ("[SOCK::gethostbyaddr] "
1496 " Got \"%.*s\" for %s address", CONN_HOST_LEN,
1497 retval, host ? "loopback" : "local host"));
1498 }
1499 return retval;
1500 }
1501
1502
1503
1504 /******************************************************************************
1505 * STATIC SOCKET HELPERS
1506 */
1507
1508
1509 /* Switch the specified socket I/O between blocking and non-blocking mode
1510 */
1511 #ifdef __GNUC__
1512 inline
1513 #endif /*__GNUC__*/
s_SetNonblock(TSOCK_Handle sock,int nonblock)1514 static int/*bool*/ s_SetNonblock(TSOCK_Handle sock, int/*bool*/ nonblock)
1515 {
1516 #if defined(NCBI_OS_MSWIN)
1517 unsigned long arg = nonblock ? 1 : 0;
1518 return ioctlsocket(sock, FIONBIO, &arg) == 0;
1519 #elif defined(NCBI_OS_UNIX)
1520 int flags = fcntl(sock, F_GETFL, 0);
1521 if (flags == -1)
1522 return 0/*false*/;
1523 if (!nonblock == !(flags & O_NONBLOCK))
1524 return 1/*true*/;
1525 return fcntl(sock, F_SETFL, nonblock
1526 ? flags | O_NONBLOCK
1527 : flags & (int) ~O_NONBLOCK) == 0;
1528 #else
1529 # error "Unsupported platform"
1530 #endif /*NCBI_OS*/
1531 }
1532
1533
1534 /* Set close-on-exec flag
1535 */
1536 #ifdef __GNUC__
1537 inline
1538 #endif /*__GNUC__*/
s_SetCloexec(TSOCK_Handle x_sock,int cloexec)1539 static int/*bool*/ s_SetCloexec(TSOCK_Handle x_sock, int/*bool*/ cloexec)
1540 {
1541 #if defined(NCBI_OS_UNIX)
1542 int flags = fcntl(x_sock, F_GETFD, 0);
1543 if (flags == -1)
1544 return 0/*false*/;
1545 if (!cloexec == !(flags & FD_CLOEXEC))
1546 return 1/*true*/;
1547 return fcntl(x_sock, F_SETFD, cloexec
1548 ? flags | FD_CLOEXEC
1549 : flags & (int) ~FD_CLOEXEC) == 0;
1550 #elif defined(NCBI_OS_MSWIN)
1551 return SetHandleInformation((HANDLE)x_sock, HANDLE_FLAG_INHERIT, !cloexec);
1552 #else
1553 # error "Unsupported platform"
1554 #endif /*NCBI_OS*/
1555 }
1556
1557
1558 /*ARGSUSED*/
1559 #ifdef __GNUC__
1560 inline
1561 #endif /*__GNUC__*/
s_SetReuseAddress(TSOCK_Handle x_sock,int on_off)1562 static int/*bool*/ s_SetReuseAddress(TSOCK_Handle x_sock, int/*bool*/ on_off)
1563 {
1564 #if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN)
1565 # ifdef NCBI_OS_MSWIN
1566 BOOL reuse_addr = on_off ? TRUE : FALSE;
1567 # else
1568 int reuse_addr = on_off ? 1 : 0;
1569 # endif /*NCBI_OS_MSWIN*/
1570 return setsockopt(x_sock, SOL_SOCKET, SO_REUSEADDR,
1571 (char*) &reuse_addr, sizeof(reuse_addr)) == 0;
1572 #else
1573 /* setsockopt() is not implemented for MAC (in MIT socket emulation lib) */
1574 return 1;
1575 #endif /*NCBI_OS_UNIX || NCBI_OS_MSWIN*/
1576 }
1577
1578
1579 #ifdef SO_KEEPALIVE
1580 #ifdef __GNUC__
1581 inline
1582 #endif /*__GNUC__*/
s_SetKeepAlive(TSOCK_Handle x_sock,int on_off)1583 static int/*bool*/ s_SetKeepAlive(TSOCK_Handle x_sock, int/*bool*/ on_off)
1584 {
1585 # ifdef NCBI_OS_MSWIN
1586 BOOL oobinline = on_off ? TRUE : FALSE;
1587 # else
1588 int oobinline = on_off ? 1/*true*/ : 0/*false*/;
1589 # endif /*NCBI_OS_MSWIN*/
1590 return setsockopt(x_sock, SOL_SOCKET, SO_KEEPALIVE,
1591 (char*) &oobinline, sizeof(oobinline)) == 0;
1592 }
1593 #endif /*SO_KEEPALIVE*/
1594
1595
1596 #ifdef SO_OOBINLINE
1597 #ifdef __GNUC__
1598 inline
1599 #endif /*__GNUC__*/
s_SetOobInline(TSOCK_Handle x_sock,int on_off)1600 static int/*bool*/ s_SetOobInline(TSOCK_Handle x_sock, int/*bool*/ on_off)
1601 {
1602 # ifdef NCBI_OS_MSWIN
1603 BOOL oobinline = on_off ? TRUE : FALSE;
1604 # else
1605 int oobinline = on_off ? 1/*true*/ : 0/*false*/;
1606 # endif /*NCBI_OS_MSWIN*/
1607 return setsockopt(x_sock, SOL_SOCKET, SO_OOBINLINE,
1608 (char*) &oobinline, sizeof(oobinline)) == 0;
1609 }
1610 #endif /*SO_OOBINLINE*/
1611
1612
1613 #if !defined(NCBI_OS_MSWIN) && defined(FD_SETSIZE)
x_TryLowerSockFileno(SOCK sock)1614 static int/*bool*/ x_TryLowerSockFileno(SOCK sock)
1615 {
1616 # ifdef STDERR_FILENO
1617 # define SOCK_DUPOVER STDERR_FILENO
1618 # else
1619 # define SOCK_DUPOVER 2
1620 # endif /*STDERR_FILENO*/
1621 int fd = fcntl(sock->sock, F_DUPFD, SOCK_DUPOVER + 1);
1622 if (fd >= 0) {
1623 if (fd < FD_SETSIZE) {
1624 char _id[MAXIDLEN];
1625 int cloexec = fcntl(sock->sock, F_GETFD, 0);
1626 if (cloexec > 0 && (cloexec & FD_CLOEXEC))
1627 fcntl(fd, F_SETFD, cloexec);
1628 CORE_LOGF_X(111, eLOG_Trace,
1629 ("%s[SOCK::Select] "
1630 " File descriptor has been lowered to %d",
1631 s_ID(sock, _id), fd));
1632 close(sock->sock);
1633 sock->sock = fd;
1634 return 1/*success*/;
1635 }
1636 close(fd);
1637 errno = 0;
1638 }
1639 return 0/*failure*/;
1640 }
1641 #endif /*!NCBI_MSWIN && FD_SETSIZE*/
1642
1643
1644 #ifdef __GNUC__
1645 inline
1646 #endif /*__GNUC__*/
1647 /* compare 2 normalized timeval timeouts: "whether *v1 is less than *v2" */
s_IsSmallerTimeout(const struct timeval * v1,const struct timeval * v2)1648 static int/*bool*/ s_IsSmallerTimeout(const struct timeval* v1,
1649 const struct timeval* v2)
1650 {
1651 if (!v1/*inf*/)
1652 return 0;
1653 if (!v2/*inf*/)
1654 return 1;
1655 if (v1->tv_sec > v2->tv_sec)
1656 return 0;
1657 if (v1->tv_sec < v2->tv_sec)
1658 return 1;
1659 return v1->tv_usec < v2->tv_usec;
1660 }
1661
1662
1663 #if !defined(NCBI_OS_MSWIN) || !defined(NCBI_CXX_TOOLKIT)
1664
1665
s_Select_(size_t n,SSOCK_Poll polls[],const struct timeval * tv,int asis)1666 static EIO_Status s_Select_(size_t n,
1667 SSOCK_Poll polls[],
1668 const struct timeval* tv,
1669 int/*bool*/ asis)
1670 {
1671 char _id[MAXIDLEN];
1672 int/*bool*/ write_only;
1673 int/*bool*/ read_only;
1674 int ready;
1675 fd_set rfds;
1676 fd_set wfds;
1677 fd_set efds;
1678 int nfds;
1679 struct timeval x_tv;
1680 size_t i;
1681
1682 # ifdef NCBI_OS_MSWIN
1683 if (!n) {
1684 DWORD ms =
1685 tv ? tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000 : INFINITE;
1686 Sleep(ms);
1687 return eIO_Timeout;
1688 }
1689 # endif /*NCBI_OS_MSWIN*/
1690
1691 if (tv)
1692 x_tv = *tv;
1693 else /* won't be used but keeps compilers happy */
1694 memset(&x_tv, 0, sizeof(x_tv));
1695
1696 for (;;) { /* optionally auto-resume if interrupted / sliced */
1697 int/*bool*/ bad = 0/*false*/;
1698 # ifdef NCBI_OS_MSWIN
1699 unsigned int count = 0;
1700 # endif /*NCBI_OS_MSWIN*/
1701 struct timeval xx_tv;
1702
1703 write_only = 1/*true*/;
1704 read_only = 1/*true*/;
1705 ready = 0/*false*/;
1706 FD_ZERO(&efds);
1707 nfds = 0;
1708
1709 for (i = 0; i < n; ++i) {
1710 EIO_Event event;
1711 SOCK sock;
1712 ESOCK_Type type;
1713 TSOCK_Handle fd;
1714
1715 if (!(sock = polls[i].sock)) {
1716 assert(!polls[i].revent/*eIO_Open*/);
1717 continue;
1718 }
1719
1720 event = polls[i].event;
1721 if ((event | eIO_ReadWrite) != eIO_ReadWrite) {
1722 polls[i].revent = eIO_Close;
1723 if (!bad) {
1724 ready = 0/*false*/;
1725 bad = 1/*true*/;
1726 }
1727 continue;
1728 }
1729 if (!event) {
1730 assert(!polls[i].revent/*eIO_Open*/);
1731 continue;
1732 }
1733 if (bad)
1734 continue;
1735
1736 if ((fd = sock->sock) == SOCK_INVALID) {
1737 polls[i].revent = eIO_Close;
1738 ready = 1/*true*/;
1739 continue;
1740 }
1741 if (polls[i].revent) {
1742 ready = 1/*true*/;
1743 if (polls[i].revent == eIO_Close)
1744 continue;
1745 assert((polls[i].revent | eIO_ReadWrite) == eIO_ReadWrite);
1746 event = (EIO_Event)(event & ~polls[i].revent);
1747 }
1748
1749 # if !defined(NCBI_OS_MSWIN) && defined(FD_SETSIZE)
1750 if (fd >= FD_SETSIZE) {
1751 if (!x_TryLowerSockFileno(sock)) {
1752 /* NB: only once here, as this sets "bad" to "1" */
1753 CORE_LOGF_ERRNO_X(145, eLOG_Error, errno,
1754 ("%s[SOCK::Select] "
1755 " Socket file descriptor must "
1756 " be less than %d",
1757 s_ID(sock, _id), FD_SETSIZE));
1758 polls[i].revent = eIO_Close;
1759 ready = bad = 1/*true*/;
1760 continue;
1761 }
1762 fd = sock->sock;
1763 assert(fd < FD_SETSIZE);
1764 }
1765 # endif /*!NCBI_OS_MSWIN && FD_SETSIZE*/
1766
1767 type = (ESOCK_Type) sock->type;
1768 switch (type & eSocket ? event : event & eIO_Read) {
1769 case eIO_Write:
1770 case eIO_ReadWrite:
1771 assert(type & eSocket);
1772 if (type == eDatagram || sock->w_status != eIO_Closed) {
1773 if (read_only) {
1774 FD_ZERO(&wfds);
1775 read_only = 0/*false*/;
1776 }
1777 FD_SET(fd, &wfds);
1778 }
1779 if (event == eIO_Write &&
1780 (type == eDatagram || asis
1781 || (sock->r_on_w == eOff
1782 || (sock->r_on_w == eDefault
1783 && s_ReadOnWrite != eOn)))) {
1784 break;
1785 }
1786 /*FALLTHRU*/
1787
1788 case eIO_Read:
1789 if (type != eSocket
1790 || (sock->r_status != eIO_Closed && !sock->eof)) {
1791 if (write_only) {
1792 FD_ZERO(&rfds);
1793 write_only = 0/*false*/;
1794 }
1795 FD_SET(fd, &rfds);
1796 }
1797 if (type != eSocket || asis || event != eIO_Read
1798 || sock->w_status == eIO_Closed
1799 || !(sock->pending | sock->w_len)) {
1800 break;
1801 }
1802 if (read_only) {
1803 FD_ZERO(&wfds);
1804 read_only = 0/*false*/;
1805 }
1806 FD_SET(fd, &wfds);
1807 break;
1808
1809 default:
1810 /*fully pre-ready*/
1811 break;
1812 }
1813
1814 FD_SET(fd, &efds);
1815 if (nfds < (int) fd)
1816 nfds = (int) fd;
1817
1818 # ifdef NCBI_OS_MSWIN
1819 /* check whether FD_SETSIZE has been exceeded */
1820 if (!FD_ISSET(fd, &efds)) {
1821 /* NB: only once here, as this sets "bad" to "1" */
1822 CORE_LOGF_X(145, eLOG_Error,
1823 ("[SOCK::Select] "
1824 " Too many sockets in select(),"
1825 " must be fewer than %u", count));
1826 polls[i].revent = eIO_Close;
1827 ready = bad = 1/*true*/;
1828 continue;
1829 }
1830 ++count;
1831 # endif /*NCBI_OS_MSWIN*/
1832 }
1833 assert(i >= n);
1834
1835 if (bad) {
1836 if (ready) {
1837 errno = SOCK_ETOOMANY;
1838 return eIO_Unknown;
1839 } else {
1840 errno = EINVAL;
1841 return eIO_InvalidArg;
1842 }
1843 }
1844
1845 if (ready)
1846 memset(&xx_tv, 0, sizeof(xx_tv));
1847 else if (tv && s_IsSmallerTimeout(&x_tv, s_SelectTimeout))
1848 xx_tv = x_tv;
1849 else if (s_SelectTimeout)
1850 xx_tv = *s_SelectTimeout;
1851 /* else infinite (0) timeout will be used */
1852
1853 nfds = select(SOCK_NFDS((TSOCK_Handle) nfds),
1854 write_only ? 0 : &rfds,
1855 read_only ? 0 : &wfds, &efds,
1856 ready || tv || s_SelectTimeout ? &xx_tv : 0);
1857
1858 if (nfds > 0)
1859 break;
1860
1861 if (!nfds) {
1862 /* timeout has expired */
1863 if (!ready) {
1864 if (!tv)
1865 continue;
1866 if (s_IsSmallerTimeout(s_SelectTimeout, &x_tv)) {
1867 x_tv.tv_sec -= s_SelectTimeout->tv_sec;
1868 if (x_tv.tv_usec < s_SelectTimeout->tv_usec) {
1869 x_tv.tv_sec--;
1870 x_tv.tv_usec += 1000000;
1871 }
1872 x_tv.tv_usec -= s_SelectTimeout->tv_usec;
1873 continue;
1874 }
1875 return eIO_Timeout;
1876 }
1877 /* NB: ready */
1878 } else { /* nfds < 0 */
1879 int error = SOCK_ERRNO;
1880 if (error != SOCK_EINTR) {
1881 const char* strerr = SOCK_STRERROR(error);
1882 CORE_LOGF_ERRNO_EXX(5, eLOG_Warning,
1883 error, strerr ? strerr : "",
1884 ("%s[SOCK::Select] "
1885 " Failed select()",
1886 n == 1 ? s_ID(polls[0].sock, _id) : ""));
1887 UTIL_ReleaseBuffer(strerr);
1888 if (!ready)
1889 return eIO_Unknown;
1890 } else if ((n != 1 && s_InterruptOnSignal == eOn) ||
1891 (n == 1 && (polls[0].sock->i_on_sig == eOn
1892 || (polls[0].sock->i_on_sig == eDefault
1893 && s_InterruptOnSignal == eOn)))) {
1894 return eIO_Interrupt;
1895 } else
1896 continue;
1897 assert(error != SOCK_EINTR && ready);
1898 }
1899 break;
1900 }
1901
1902 if (nfds > 0) {
1903 /* NB: some fd bits could have been counted multiple times if reside
1904 in different fd_set's (such as ready for both R and W), recount. */
1905 for (ready = 0, i = 0; i < n; ++i) {
1906 SOCK sock = polls[i].sock;
1907 if (sock && polls[i].event) {
1908 TSOCK_Handle fd;
1909 if (polls[i].revent == eIO_Close) {
1910 ++ready;
1911 continue;
1912 }
1913 if ((fd = sock->sock) == SOCK_INVALID) {
1914 polls[i].revent = eIO_Close;
1915 ++ready;
1916 continue;
1917 }
1918 # if !defined(NCBI_OS_MSWIN) && defined(FD_SETSIZE)
1919 assert(fd < FD_SETSIZE);
1920 # endif /*!NCBI_OS_MSWIN && FD_SETSIZE*/
1921 if (!write_only && FD_ISSET(fd, &rfds)) {
1922 polls[i].revent = (EIO_Event)(polls[i].revent | eIO_Read);
1923 # ifdef NCBI_OS_MSWIN
1924 sock->readable = 1/*true*/;
1925 # endif /*NCBI_OS_MSWIN*/
1926 }
1927 if (!read_only && FD_ISSET(fd, &wfds)) {
1928 polls[i].revent = (EIO_Event)(polls[i].revent | eIO_Write);
1929 # ifdef NCBI_OS_MSWIN
1930 sock->writable = 1/*true*/;
1931 # endif /*NCBI_OS_MSWIN*/
1932 }
1933 assert((polls[i].revent | eIO_ReadWrite) == eIO_ReadWrite);
1934 if (polls[i].revent == eIO_Open) {
1935 if (!FD_ISSET(fd, &efds))
1936 continue;
1937 polls[i].revent = eIO_Close;
1938 } else if (sock->type == eTrigger)
1939 polls[i].revent = polls[i].event;
1940 assert(polls[i].revent != eIO_Open);
1941 ++ready;
1942 } else
1943 assert(polls[i].revent == eIO_Open);
1944 }
1945 }
1946
1947 assert(ready);
1948 /* can do I/O now */
1949 return eIO_Success;
1950 }
1951
1952
1953 # if defined(NCBI_OS_UNIX) && !defined(NCBI_OS_DARWIN) && defined(HAVE_POLL_H)
1954
1955
1956 # define NPOLLS ((3 * sizeof(fd_set)) / sizeof(struct pollfd))
1957
1958
x_CountPolls(size_t n,SSOCK_Poll polls[])1959 static size_t x_CountPolls(size_t n, SSOCK_Poll polls[])
1960 {
1961 int/*bool*/ bigfd = 0/*false*/;
1962 int/*bool*/ good = 1/*true*/;
1963 size_t count = 0;
1964 size_t i;
1965
1966 for (i = 0; i < n; ++i) {
1967 if (!polls[i].sock) {
1968 assert(!polls[i].revent/*eIO_Open*/);
1969 continue;
1970 }
1971 if ((polls[i].event | eIO_ReadWrite) != eIO_ReadWrite) {
1972 good = 0/*false*/;
1973 continue;
1974 }
1975 if (!polls[i].event) {
1976 assert(!polls[i].revent/*eIO_Open*/);
1977 continue;
1978 }
1979 if (polls[i].sock->sock == SOCK_INVALID
1980 || polls[i].revent == eIO_Close) {
1981 /* pre-ready */
1982 continue;
1983 }
1984 # ifdef FD_SETSIZE
1985 if (polls[i].sock->sock >= FD_SETSIZE
1986 && (s_IOWaitSysAPI == eSOCK_IOWaitSysAPIPoll
1987 || !x_TryLowerSockFileno(polls[i].sock))) {
1988 bigfd = 1/*true*/;
1989 }
1990 # endif /*FD_SETSIZE*/
1991 ++count;
1992 }
1993 return good && (s_IOWaitSysAPI != eSOCK_IOWaitSysAPIAuto
1994 || count <= NPOLLS || bigfd) ? count : 0;
1995 }
1996
1997
s_Poll_(size_t n,SSOCK_Poll polls[],const struct timeval * tv,int asis)1998 static EIO_Status s_Poll_(size_t n,
1999 SSOCK_Poll polls[],
2000 const struct timeval* tv,
2001 int/*bool*/ asis)
2002 {
2003 struct pollfd xx_polls[NPOLLS];
2004 char _id[MAXIDLEN];
2005 struct pollfd* x_polls;
2006 EIO_Status status;
2007 nfds_t ready;
2008 nfds_t count;
2009 int wait;
2010 size_t m, i;
2011
2012 if (s_IOWaitSysAPI != eSOCK_IOWaitSysAPIAuto)
2013 m = n;
2014 else
2015 # ifdef FD_SETSIZE
2016 if (n > FD_SETSIZE)
2017 m = n;
2018 else
2019 # endif /*FD_SETSIZE*/
2020 if (!(m = x_CountPolls(n, polls)))
2021 return s_Select_(n, polls, tv, asis);
2022
2023 if (m <= NPOLLS)
2024 x_polls = xx_polls;
2025 else if (!(x_polls = (struct pollfd*) malloc(m * sizeof(*x_polls)))) {
2026 CORE_LOGF_ERRNO_X(146, eLOG_Critical, errno,
2027 ("%s[SOCK::Select] "
2028 " Cannot allocate poll vector(%lu)",
2029 n == 1 ? s_ID(polls[0].sock, _id) : "",
2030 (unsigned long) m));
2031 return eIO_Unknown;
2032 }
2033
2034 status = eIO_Success;
2035 wait = tv ? (int)(tv->tv_sec * 1000 + (tv->tv_usec + 500) / 1000) : -1;
2036 for (;;) { /* optionally auto-resume if interrupted / sliced */
2037 int/*bool*/ bad = 0/*false*/;
2038 int x_ready;
2039 int slice;
2040
2041 ready = count = 0;
2042 for (i = 0; i < n; ++i) {
2043 short bitset;
2044 EIO_Event event;
2045 SOCK sock;
2046 ESOCK_Type type;
2047 TSOCK_Handle fd;
2048
2049 if (!(sock = polls[i].sock)) {
2050 assert(!polls[i].revent/*eIO_Open*/);
2051 continue;
2052 }
2053
2054 event = polls[i].event;
2055 if ((event | eIO_ReadWrite) != eIO_ReadWrite) {
2056 polls[i].revent = eIO_Close;
2057 bad = 1/*true*/;
2058 continue;
2059 }
2060 if (!event) {
2061 assert(!polls[i].revent/*eIO_Open*/);
2062 continue;
2063 }
2064 if (bad)
2065 continue;
2066
2067 if ((fd = sock->sock) == SOCK_INVALID) {
2068 polls[i].revent = eIO_Close;
2069 ++ready;
2070 continue;
2071 }
2072 if (polls[i].revent) {
2073 ++ready;
2074 if (polls[i].revent == eIO_Close)
2075 continue;
2076 assert((polls[i].revent | eIO_ReadWrite) == eIO_ReadWrite);
2077 event = (EIO_Event)(event & ~polls[i].revent);
2078 }
2079
2080 bitset = 0;
2081 type = (ESOCK_Type) sock->type;
2082 switch (type & eSocket ? event : event & eIO_Read) {
2083 case eIO_Write:
2084 case eIO_ReadWrite:
2085 assert(type & eSocket);
2086 if (type == eDatagram || sock->w_status != eIO_Closed)
2087 bitset |= POLLOUT;
2088 if (event == eIO_Write &&
2089 (type == eDatagram || asis
2090 || (sock->r_on_w == eOff
2091 || (sock->r_on_w == eDefault
2092 && s_ReadOnWrite != eOn)))) {
2093 break;
2094 }
2095 /*FALLTHRU*/
2096
2097 case eIO_Read:
2098 if (type != eSocket
2099 || (sock->r_status != eIO_Closed && !sock->eof))
2100 bitset |= POLLIN;
2101 if (type != eSocket || asis || event != eIO_Read
2102 || sock->w_status == eIO_Closed
2103 || !(sock->pending | sock->w_len)) {
2104 break;
2105 }
2106 bitset |= POLLOUT;
2107 break;
2108
2109 default:
2110 /*fully pre-ready*/
2111 continue;
2112 }
2113
2114 if (!bitset)
2115 continue;
2116 assert(count < (nfds_t) m);
2117 x_polls[count].fd = fd;
2118 x_polls[count].events = bitset;
2119 x_polls[count].revents = 0;
2120 ++count;
2121 }
2122 assert(i >= n);
2123
2124 if (bad) {
2125 status = eIO_InvalidArg;
2126 errno = EINVAL;
2127 break;
2128 }
2129
2130 if (s_SelectTimeout) {
2131 slice = (int)((s_SelectTimeout->tv_sec * 1000 +
2132 (s_SelectTimeout->tv_usec + 500) / 1000));
2133 if (wait != -1 && wait < slice)
2134 slice = wait;
2135 } else
2136 slice = wait;
2137
2138 if (count || !ready) {
2139 x_ready = poll(x_polls, count, !ready ? slice : 0);
2140
2141 if (x_ready > 0) {
2142 # ifdef NCBI_OS_DARWIN
2143 /* Mac OS X sometimes misreports, weird! */
2144 if (x_ready > (int) count)
2145 x_ready = (int) count; /* this is *not* a workaround!!! */
2146 # endif /*NCBI_OS_DARWIN*/
2147 assert(status == eIO_Success);
2148 ready = (nfds_t) x_ready;
2149 assert(ready <= count);
2150 break;
2151 }
2152 } else
2153 x_ready = 0;
2154
2155 if (!x_ready) {
2156 /* timeout has expired */
2157 if (!ready) {
2158 if (!tv)
2159 continue;
2160 if (wait > slice) {
2161 wait -= slice;
2162 continue;
2163 }
2164 status = eIO_Timeout;
2165 break;
2166 }
2167 /* NB: ready */
2168 } else { /* x_ready < 0 */
2169 if ((x_ready = SOCK_ERRNO) != SOCK_EINTR) {
2170 const char* strerr = SOCK_STRERROR(x_ready);
2171 CORE_LOGF_ERRNO_EXX(147, ready ? eLOG_Warning : eLOG_Error,
2172 x_ready, strerr ? strerr : "",
2173 ("%s[SOCK::Select] "
2174 " Failed poll()",
2175 n == 1 ? s_ID(polls[0].sock, _id) : ""));
2176 UTIL_ReleaseBuffer(strerr);
2177 if (!ready) {
2178 status = eIO_Unknown;
2179 break;
2180 }
2181 } else if ((n != 1 && s_InterruptOnSignal == eOn) ||
2182 (n == 1 && (polls[0].sock->i_on_sig == eOn
2183 || (polls[0].sock->i_on_sig == eDefault
2184 && s_InterruptOnSignal == eOn)))) {
2185 status = eIO_Interrupt;
2186 break;
2187 } else
2188 continue;
2189 assert(x_ready != SOCK_EINTR && ready);
2190 }
2191
2192 assert(status == eIO_Success && ready);
2193 n = 0/*no post processing*/;
2194 break;
2195 }
2196
2197 assert(status != eIO_Success || ready > 0);
2198 if (status == eIO_Success && n) {
2199 nfds_t x_ready = 0;
2200 nfds_t scanned = 0;
2201 for (m = 0, i = 0; i < n; ++i) {
2202 SOCK sock = polls[i].sock;
2203 if (sock && polls[i].event) {
2204 TSOCK_Handle fd;
2205 short events, revents;
2206 if (polls[i].revent == eIO_Close) {
2207 ++x_ready;
2208 continue;
2209 }
2210 if ((fd = sock->sock) == SOCK_INVALID) {
2211 polls[i].revent = eIO_Close;
2212 ++x_ready;
2213 continue;
2214 }
2215 events = revents = 0;
2216 if (scanned < ready) {
2217 nfds_t x_scanned = 0;
2218 nfds_t j;
2219 assert((nfds_t) m < count);
2220 for (j = (nfds_t) m; j < count; ++j) {
2221 if (x_polls[j].revents)
2222 ++x_scanned;
2223 if (x_polls[j].fd == fd) {
2224 events = x_polls[j].events;
2225 revents = x_polls[j].revents;
2226 scanned += x_scanned;
2227 m = (size_t) ++j;
2228 break;
2229 }
2230 }
2231 assert(events || ((nfds_t) m < count && count <= j));
2232 }
2233 if ((events & POLLIN)
2234 && (revents & (POLLIN | POLLRDHUP | POLLPRI))) {
2235 polls[i].revent = (EIO_Event)(polls[i].revent | eIO_Read);
2236 }
2237 if ((events & POLLOUT)
2238 && (revents & (POLLOUT | POLLHUP))) {
2239 polls[i].revent = (EIO_Event)(polls[i].revent | eIO_Write);
2240 }
2241 assert((polls[i].revent | eIO_ReadWrite) == eIO_ReadWrite);
2242 if (polls[i].revent == eIO_Open) {
2243 if (!(revents & (POLLERR | POLLNVAL)))
2244 continue;
2245 polls[i].revent = eIO_Close;
2246 } else if (sock->type == eTrigger)
2247 polls[i].revent = polls[i].event;
2248 assert(polls[i].revent != eIO_Open);
2249 ++x_ready;
2250 } else
2251 assert(polls[i].revent == eIO_Open);
2252 }
2253 assert(scanned <= ready);
2254 assert(x_ready >= ready);
2255 }
2256
2257 if (x_polls != xx_polls)
2258 free(x_polls);
2259 return status;
2260 }
2261
2262
2263 # endif /*NCBI_OS_UNIX && !NCBI_OS_DARWIN && HAVE_POLL_H*/
2264
2265
2266 #endif /*!NCBI_OS_MSWIN || !NCBI_CXX_TOOLKIT*/
2267
2268
2269 /* Select on the socket I/O (multiple sockets).
2270 *
2271 * "Event" field is not considered for entries, whose "sock" field is 0,
2272 * "revent" for those entries is always set "eIO_Open". For all other entries
2273 * "revent" will be checked, and if set, it will be "subtracted" from the
2274 * requested "event" (or the entry won't be considered at all if "revent" is
2275 * already set to "eIO_Close"). If at least one non-"eIO_Open" status found
2276 * in "revent", the call terminates with "eIO_Success" (after, however, having
2277 * checked all other entries for validity, and) after having polled
2278 * (with timeout 0) on all remaining entries and events.
2279 *
2280 * This function always checks datagram and listening sockets, and triggers
2281 * exactly as they are requested (according to "event"). For stream sockets,
2282 * the call behaves differently only if the last parameter is passed as zero:
2283 *
2284 * If "eIO_Write" event is inquired on a stream socket, and the socket is
2285 * marked for upread, then returned "revent" may also include "eIO_Read" to
2286 * indicate that some input is available on that socket.
2287 *
2288 * If "eIO_Read" event is inquired on a stream socket, and the socket still
2289 * has its connection/data pending, the "revent" field may then include
2290 * "eIO_Write" to indicate that connection can be completed/data sent.
2291 *
2292 * Return "eIO_Success" when at least one socket is found either ready
2293 * (including "eIO_Read" event on "eIO_Write" for upreadable sockets, and/or
2294 * "eIO_Write" on "eIO_Read" for sockets in pending state when "asis!=0")
2295 * or failing ("revent" contains "eIO_Close").
2296 *
2297 * Return "eIO_Timeout", if timeout expired before any socket was capable
2298 * of doing any IO. Any other return code indicates some usage failure.
2299 */
s_Select(size_t n,SSOCK_Poll polls[],const struct timeval * tv,int asis)2300 static EIO_Status s_Select(size_t n,
2301 SSOCK_Poll polls[],
2302 const struct timeval* tv,
2303 int/*bool*/ asis)
2304 {
2305 #if defined(NCBI_OS_MSWIN) && defined(NCBI_CXX_TOOLKIT)
2306 DWORD wait = tv ? tv->tv_sec * 1000 + (tv->tv_usec + 500)/1000 : INFINITE;
2307 HANDLE what[MAXIMUM_WAIT_OBJECTS];
2308 long want[MAXIMUM_WAIT_OBJECTS];
2309 char _id[MAXIDLEN];
2310
2311 for (;;) { /* timeslice loop */
2312 int/*bool*/ done = 0/*false*/;
2313 int/*bool*/ ready = 0/*false*/;
2314 DWORD count = 0;
2315 DWORD slice;
2316 size_t i;
2317
2318 for (i = 0; i < n; ++i) {
2319 long bitset;
2320 EIO_Event event;
2321 SOCK sock;
2322 HANDLE ev;
2323
2324 if (!(sock = polls[i].sock)) {
2325 assert(!polls[i].revent/*eIO_Open*/);
2326 continue;
2327 }
2328
2329 event = polls[i].event;
2330 if ((event | eIO_ReadWrite) != eIO_ReadWrite) {
2331 polls[i].revent = eIO_Close;
2332 if (!done) {
2333 ready = 0/*false*/;
2334 done = 1/*true*/;
2335 }
2336 continue;
2337 }
2338 if (!event) {
2339 assert(!polls[i].revent/*eIO_Open*/);
2340 continue;
2341 }
2342 if (done)
2343 continue;
2344
2345 if (sock->sock == SOCK_INVALID) {
2346 polls[i].revent = eIO_Close;
2347 ready = 1/*true*/;
2348 continue;
2349 }
2350 if (polls[i].revent) {
2351 ready = 1/*true*/;
2352 if (polls[i].revent == eIO_Close)
2353 continue;
2354 assert((polls[i].revent | eIO_ReadWrite) == eIO_ReadWrite);
2355 event = (EIO_Event)(event & ~polls[i].revent);
2356 }
2357
2358 bitset = 0;
2359 if (sock->type != eTrigger) {
2360 ESOCK_Type type = (ESOCK_Type) sock->type;
2361 EIO_Event readable = sock->readable ? eIO_Read : eIO_Open;
2362 EIO_Event writable = sock->writable ? eIO_Write : eIO_Open;
2363 switch (type & eSocket ? event : event & eIO_Read) {
2364 case eIO_Write:
2365 case eIO_ReadWrite:
2366 if (type == eDatagram || sock->w_status != eIO_Closed) {
2367 if (writable) {
2368 polls[i].revent |= eIO_Write;
2369 ready = 1/*true*/;
2370 }
2371 if (!sock->connected)
2372 bitset |= FD_CONNECT/*C*/;
2373 bitset |= FD_WRITE/*W*/;
2374 }
2375 if (event == eIO_Write &&
2376 (type == eDatagram || asis
2377 || (sock->r_on_w == eOff
2378 || (sock->r_on_w == eDefault
2379 && s_ReadOnWrite != eOn)))) {
2380 break;
2381 }
2382 /*FALLTHRU*/
2383
2384 case eIO_Read:
2385 if (type != eSocket
2386 || (sock->r_status != eIO_Closed && !sock->eof)) {
2387 if (readable) {
2388 polls[i].revent |= eIO_Read;
2389 ready = 1/*true*/;
2390 }
2391 if (type & eSocket) {
2392 if (type == eSocket)
2393 bitset |= FD_OOB/*O*/;
2394 bitset |= FD_READ/*R*/;
2395 } else
2396 bitset |= FD_ACCEPT/*A*/;
2397 }
2398 if (type != eSocket || asis || event != eIO_Read
2399 || sock->w_status == eIO_Closed
2400 || !(sock->pending | sock->w_len)) {
2401 break;
2402 }
2403 if (writable) {
2404 polls[i].revent |= eIO_Write;
2405 ready = 1/*true*/;
2406 }
2407 bitset |= FD_WRITE/*W*/;
2408 break;
2409
2410 default:
2411 /*fully pre-ready*/
2412 continue;
2413 }
2414
2415 if (!bitset)
2416 continue;
2417 ev = sock->event;
2418 } else
2419 ev = ((TRIGGER) sock)->fd;
2420
2421 if (count >= sizeof(what) / sizeof(what[0])) {
2422 /* NB: only once here, as this sets "done" to "1" */
2423 CORE_LOGF_X(145, eLOG_Error,
2424 ("[SOCK::Select] "
2425 " Too many objects, must be fewer than %u",
2426 (unsigned int) count));
2427 polls[i].revent = eIO_Close;
2428 ready = done = 1/*true*/;
2429 continue;
2430 }
2431 want[count] = bitset;
2432 what[count] = ev;
2433 ++count;
2434 }
2435 assert(i >= n);
2436
2437 if (done) {
2438 if (ready) {
2439 errno = SOCK_ETOOMANY;
2440 return eIO_Unknown;
2441 } else {
2442 errno = EINVAL;
2443 return eIO_InvalidArg;
2444 }
2445 }
2446
2447 if (s_SelectTimeout) {
2448 slice = (s_SelectTimeout->tv_sec * 1000 +
2449 (s_SelectTimeout->tv_usec + 500) / 1000);
2450 if (wait != INFINITE && wait < slice)
2451 slice = wait;
2452 } else
2453 slice = wait;
2454
2455 if (count) {
2456 DWORD m = 0, r;
2457 i = 0;
2458 do {
2459 size_t j;
2460 DWORD c = count - m;
2461 r = WaitForMultipleObjects(c,
2462 what + m,
2463 FALSE/*any*/,
2464 ready ? 0 : slice);
2465 if (r == WAIT_FAILED) {
2466 DWORD err = GetLastError();
2467 const char* strerr = s_WinStrerror(err);
2468 CORE_LOGF_ERRNO_EXX(133, eLOG_Error,
2469 err, strerr ? strerr : "",
2470 ("[SOCK::Select] "
2471 " Failed WaitForMultipleObjects(%u)",
2472 (unsigned int) c));
2473 UTIL_ReleaseBufferOnHeap(strerr);
2474 break;
2475 }
2476 if (r == WAIT_TIMEOUT)
2477 break;
2478 if (r < WAIT_OBJECT_0 || WAIT_OBJECT_0 + c <= r) {
2479 CORE_LOGF_X(134, !ready ? eLOG_Error : eLOG_Warning,
2480 ("[SOCK::Select] "
2481 " WaitForMultipleObjects(%u) returned %d",
2482 (unsigned int) c, (int)(r - WAIT_OBJECT_0)));
2483 r = WAIT_FAILED;
2484 break;
2485 }
2486 m += r - WAIT_OBJECT_0;
2487 assert(!done);
2488
2489 /* something must be ready */
2490 for (j = i; j < n; ++j) {
2491 SOCK sock = polls[j].sock;
2492 WSANETWORKEVENTS e;
2493 long bitset;
2494 if (!sock || !polls[j].event)
2495 continue;
2496 if (polls[j].revent == eIO_Close) {
2497 ready = 1/*true*/;
2498 continue;
2499 }
2500 if (sock->type == eTrigger) {
2501 if (what[m] != ((TRIGGER) sock)->fd)
2502 continue;
2503 polls[j].revent = polls[j].event;
2504 assert(polls[j].revent != eIO_Open);
2505 done = 1/*true*/;
2506 break;
2507 }
2508 if (sock->sock == SOCK_INVALID) {
2509 polls[j].revent = eIO_Close;
2510 ready = 1/*true*/;
2511 continue;
2512 }
2513 if (what[m] != sock->event)
2514 continue;
2515 /* reset well before a re-enabling WSA API call occurs */
2516 if (!WSAResetEvent(what[m])) {
2517 sock->r_status = sock->w_status = eIO_Closed;
2518 polls[j].revent = eIO_Close;
2519 done = 1/*true*/;
2520 break;
2521 }
2522 if (WSAEnumNetworkEvents(sock->sock, what[m], &e) != 0) {
2523 int error = SOCK_ERRNO;
2524 const char* strerr = SOCK_STRERROR(error);
2525 CORE_LOGF_ERRNO_EXX(136, eLOG_Error,
2526 error, strerr ? strerr : "",
2527 ("%s[SOCK::Select] "
2528 " Failed WSAEnumNetworkEvents",
2529 s_ID(sock, _id)));
2530 UTIL_ReleaseBuffer(strerr);
2531 polls[j].revent = eIO_Close;
2532 done = 1/*true*/;
2533 break;
2534 }
2535 /* NB: the bits are XCAOWR */
2536 if (!(bitset = e.lNetworkEvents)) {
2537 if (ready || !slice) {
2538 m = count - 1;
2539 assert(!done);
2540 break;
2541 }
2542 if (sock->type == eListening
2543 && (sock->log == eOn ||
2544 (sock->log == eDefault && s_Log == eOn))) {
2545 LSOCK lsock = (LSOCK) sock;
2546 ELOG_Level level;
2547 if (lsock->away < 10) {
2548 lsock->away++;
2549 level = eLOG_Warning;
2550 } else
2551 level = eLOG_Trace;
2552 CORE_LOGF_X(141, level,
2553 ("%s[SOCK::Select] "
2554 " Run-away connection detected",
2555 s_ID(sock, _id)));
2556 }
2557 break;
2558 }
2559 if (bitset & FD_CLOSE/*X*/) {
2560 if (sock->type != eSocket) {
2561 polls[j].revent = eIO_Close;
2562 done = 1/*true*/;
2563 break;
2564 }
2565 bitset |= FD_READ/*at least SHUT_WR @ remote end*/;
2566 sock->readable = sock->closing = 1/*true*/;
2567 } else {
2568 if (bitset & (FD_CONNECT | FD_WRITE)) {
2569 assert(sock->type & eSocket);
2570 sock->writable = 1/*true*/;
2571 }
2572 if (bitset & (FD_ACCEPT | FD_OOB | FD_READ))
2573 sock->readable = 1/*true*/;
2574 }
2575 bitset &= want[m];
2576 if ((bitset & (FD_CONNECT | FD_WRITE))
2577 && sock->writable) {
2578 assert(sock->type & eSocket);
2579 polls[j].revent=(EIO_Event)(polls[j].revent|eIO_Write);
2580 done = 1/*true*/;
2581 }
2582 if ((bitset & (FD_ACCEPT | FD_OOB | FD_READ))
2583 && sock->readable) {
2584 polls[j].revent=(EIO_Event)(polls[j].revent|eIO_Read);
2585 done = 1/*true*/;
2586 }
2587 assert((polls[j].revent | eIO_ReadWrite) == eIO_ReadWrite);
2588 if (!polls[j].revent) {
2589 int k;
2590 if ((e.lNetworkEvents & FD_CLOSE)
2591 && !e.iErrorCode[FD_CLOSE_BIT]) {
2592 polls[j].revent = polls[j].event;
2593 done = 1/*true*/;
2594 } else for (k = 0; k < FD_MAX_EVENTS; ++k) {
2595 if (!(e.lNetworkEvents & (1 << k)))
2596 continue;
2597 if (e.iErrorCode[k]) {
2598 polls[j].revent = eIO_Close;
2599 errno = e.iErrorCode[k];
2600 done = 1/*true*/;
2601 break;
2602 }
2603 }
2604 } else
2605 done = 1/*true*/;
2606 break;
2607 }
2608 if (done) {
2609 ready = 1/*true*/;
2610 done = 0/*false*/;
2611 i = ++j;
2612 }
2613 if (ready || !slice)
2614 ++m;
2615 } while (m < count);
2616
2617 if (ready)
2618 break;
2619
2620 if (r == WAIT_FAILED)
2621 return eIO_Unknown;
2622 /* treat this as a timed out slice */
2623 } else if (ready) {
2624 break;
2625 } else
2626 Sleep(slice);
2627
2628 if (wait != INFINITE) {
2629 if (wait > slice) {
2630 wait -= slice;
2631 continue;
2632 }
2633 return eIO_Timeout;
2634 }
2635 }
2636
2637 /* can do I/O now */
2638 return eIO_Success;
2639
2640 #else /*!NCBI_OS_MSWIN || !NCBI_CXX_TOOLKIT*/
2641
2642 # if defined(NCBI_OS_UNIX) && !defined(NCBI_OS_DARWIN) && defined(HAVE_POLL_H)
2643 if (s_IOWaitSysAPI != eSOCK_IOWaitSysAPISelect)
2644 return s_Poll_(n, polls, tv, asis);
2645 # endif /*NCBI_OS_UNIX && !NCBI_OS_DARWIN && HAVE_POLL_H*/
2646
2647 return s_Select_(n, polls, tv, asis);
2648
2649 #endif /*NCBI_OS_MSWIN && NCBI_CXX_TOOLKIT*/
2650 }
2651
2652
2653 #if defined(NCBI_COMPILER_GCC) || defined(NCBI_COMPILER_ANY_CLANG)
2654 # pragma GCC diagnostic push /* NCBI_FAKE_WARNING */
2655 # pragma GCC diagnostic ignored "-Wuninitialized" /* NCBI_FAKE_WARNING */
x_tvcpy(struct timeval * dst,struct timeval * src)2656 static inline void x_tvcpy(struct timeval* dst, struct timeval* src)
2657 {
2658 memcpy(dst, src, sizeof(*dst));
2659 }
2660 # pragma GCC diagnostic warning "-Wuninitialized" /* NCBI_FAKE_WARNING */
2661 # pragma GCC diagnostic pop /* NCBI_FAKE_WARNING */
2662 #else
2663 # define x_tvcpy(d, s) (void) memcpy((d), (s), sizeof(*(d)))
2664 #endif /*NCBI_COMPILER_GCC*/
2665
2666
2667 /* connect() could be async/interrupted by a signal or just cannot establish
2668 * the connection immediately; yet, it must have been in progress
2669 * (asynchronous), so wait here for it to succeed (become writeable).
2670 */
s_IsConnected_(SOCK sock,const struct timeval * tv,const char ** what,int * error,int writeable)2671 static EIO_Status s_IsConnected_(SOCK sock,
2672 const struct timeval* tv,
2673 const char** what,
2674 int* error,
2675 int/*bool*/ writeable)
2676 {
2677 char _id[MAXIDLEN];
2678 EIO_Status status;
2679 SSOCK_Poll poll;
2680
2681 *what = 0;
2682 *error = 0;
2683 if (sock->w_status == eIO_Closed)
2684 return eIO_Closed;
2685
2686 errno = 0;
2687 if (!writeable) {
2688 poll.sock = sock;
2689 poll.event = eIO_Write;
2690 poll.revent = eIO_Open;
2691 status = s_Select(1, &poll, tv, 1/*asis*/);
2692 assert(poll.event == eIO_Write);
2693 if (status == eIO_Timeout)
2694 return status;
2695 } else {
2696 status = eIO_Success;
2697 poll.revent = eIO_Write;
2698 }
2699
2700 #if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN)
2701 if (!sock->connected && status == eIO_Success) {
2702 TSOCK_socklen_t len = (TSOCK_socklen_t) sizeof(*error);
2703 /* Note WSA resets SOCK_ERROR to 0 after this call, if successful */
2704 if (getsockopt(sock->sock, SOL_SOCKET, SO_ERROR, (void*) error, &len)
2705 != 0 || *error != 0) {
2706 status = eIO_Unknown;
2707 /* if left zero, *error will be assigned errno just a bit later */
2708 }
2709 }
2710 #endif /*NCBI_OS_UNIX || NCBI_OS_MSWIN*/
2711
2712 if (status != eIO_Success || poll.revent != eIO_Write) {
2713 if (!*error) {
2714 *error = SOCK_ERRNO;
2715 # ifdef NCBI_OS_MSWIN
2716 if (!*error)
2717 *error = errno;
2718 # endif /*NCBI_OS_MSWIN*/
2719 }
2720 if (*error == SOCK_ECONNREFUSED || *error == SOCK_ETIMEDOUT)
2721 sock->r_status = sock->w_status = status = eIO_Closed;
2722 else if (status == eIO_Success)
2723 status = eIO_Unknown;
2724 return status;
2725 }
2726
2727 if (!sock->connected) {
2728 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn)) {
2729 #if defined(_DEBUG) && !defined(NDEBUG)
2730 char mtu[128];
2731 # if defined(SOL_IP) && defined(IP_MTU)
2732 if (sock->port) {
2733 int m = 0;
2734 TSOCK_socklen_t mlen = (TSOCK_socklen_t) sizeof(m);
2735 if (getsockopt(sock->sock, SOL_IP, IP_MTU, &m, &mlen) != 0) {
2736 const char* strerr = SOCK_STRERROR(SOCK_ERRNO);
2737 sprintf(mtu, ", MTU ?? (%.80s)", strerr ? strerr : "??");
2738 UTIL_ReleaseBuffer(strerr);
2739 } else
2740 sprintf(mtu, ", MTU = %d", m);
2741 } else
2742 # endif /*SOL_IP && IP_MTU*/
2743 *mtu = '\0';
2744 #else
2745 static const char* mtu = "";
2746 #endif /*_DEBUG && !NDEBUG*/
2747 CORE_LOGF(eLOG_Trace,
2748 ("%sConnection established%s", s_ID(sock, _id), mtu));
2749 }
2750 if (s_ReuseAddress == eOn
2751 #ifdef NCBI_OS_UNIX
2752 && !sock->path[0]
2753 #endif /*NCBI_OS_UNIX*/
2754 && !s_SetReuseAddress(sock->sock, 1/*true*/)) {
2755 int x_error = SOCK_ERRNO;
2756 const char* strerr = SOCK_STRERROR(x_error);
2757 CORE_LOGF_ERRNO_EXX(6, eLOG_Trace,
2758 x_error, strerr ? strerr : "",
2759 ("%s[SOCK::IsConnected] "
2760 " Failed setsockopt(REUSEADDR)",
2761 s_ID(sock, _id)));
2762 UTIL_ReleaseBuffer(strerr);
2763 }
2764 sock->connected = 1/*true*/;
2765 }
2766
2767 if (sock->pending) {
2768 if (sock->sslctx) {
2769 FSSLOpen sslopen = s_SSL ? s_SSL->Open : 0;
2770 if (sslopen) {
2771 int/*bool*/ want_desc
2772 = (sock->log == eOn
2773 || (sock->log == eDefault && s_Log == eOn)
2774 ? 1/*true*/ : 0/*false*/);
2775 const unsigned int rtv_set = sock->r_tv_set;
2776 const unsigned int wtv_set = sock->w_tv_set;
2777 struct timeval rtv;
2778 struct timeval wtv;
2779 char* desc;
2780 if (rtv_set)
2781 rtv = sock->r_tv;
2782 if (wtv_set)
2783 wtv = sock->w_tv;
2784 SOCK_SET_TIMEOUT(sock, r, tv);
2785 SOCK_SET_TIMEOUT(sock, w, tv);
2786 status = sslopen(sock->sslctx->sess, error,
2787 want_desc ? &desc : 0);
2788 if ((sock->w_tv_set = wtv_set & 1) != 0)
2789 x_tvcpy(&sock->w_tv, &wtv);
2790 if ((sock->r_tv_set = rtv_set & 1) != 0)
2791 x_tvcpy(&sock->r_tv, &rtv);
2792 if (status == eIO_Success) {
2793 sock->pending = 0/*false*/;
2794 if (want_desc) {
2795 CORE_LOGF(eLOG_Trace,
2796 ("%sSSL session created%s%s%s%s%s",
2797 s_ID(sock, _id),
2798 sock->sslctx->host? " \"" : "",
2799 sock->sslctx->host? sock->sslctx->host : "",
2800 &"\""[!sock->sslctx->host],
2801 &" "[!desc], desc ? desc : ""));
2802 if (desc)
2803 free(desc);
2804 }
2805 } else
2806 *what = "SSL hello";
2807 } else
2808 status = eIO_NotSupported;
2809 } else
2810 sock->pending = 0/*false*/;
2811 }
2812
2813 return status;
2814 }
2815
2816
s_WaitConnected(SOCK sock,const struct timeval * tv)2817 static EIO_Status s_WaitConnected(SOCK sock, const struct timeval* tv)
2818 {
2819 const char* what;
2820 int unused;
2821 EIO_Status status = s_IsConnected_(sock, tv, &what, &unused, 0);
2822 if (s_ErrHook && status != eIO_Success && status != eIO_Timeout) {
2823 SSOCK_ErrInfo info;
2824 char addr[40];
2825 memset(&info, 0, sizeof(info));
2826 info.type = eSOCK_ErrIO;
2827 info.sock = sock;
2828 if (sock->port) {
2829 SOCK_ntoa(sock->host, addr, sizeof(addr));
2830 info.host = addr;
2831 info.port = sock->port;
2832 }
2833 #ifdef NCBI_OS_UNIX
2834 else
2835 info.host = sock->path;
2836 #endif /*NCBI_OS_UNIX*/
2837 info.event = eIO_Open;
2838 info.status = status;
2839 s_ErrorCallback(&info);
2840 }
2841 return status;
2842 }
2843
2844
2845 /* Read as many as "size" bytes of data from the socket. Return eIO_Success
2846 * if at least one byte has been read or EOF has been reached (0 bytes read).
2847 * Otherwise (nothing read), return an error code to indicate the problem.
2848 * NOTE: This call is for stream sockets only. Also, it can return the
2849 * above mentioned EOF indicator only once, with all successive calls to
2850 * return an error (usually, eIO_Closed).
2851 */
s_Recv(SOCK sock,void * buf,size_t size,size_t * n_read,int flag)2852 static EIO_Status s_Recv(SOCK sock,
2853 void* buf,
2854 size_t size,
2855 size_t* n_read,
2856 int flag)
2857 {
2858 int/*bool*/ readable;
2859 char _id[MAXIDLEN];
2860
2861 assert(sock->type == eSocket && buf && size > 0 && !*n_read);
2862
2863 if (sock->r_status == eIO_Closed)
2864 return eIO_Unknown;
2865 if (sock->eof)
2866 return eIO_Closed;
2867
2868 /* read from the socket */
2869 readable = 0/*false*/;
2870 for (;;) { /* optionally auto-resume if interrupted */
2871 int error;
2872 ssize_t x_read = recv(sock->sock, buf, WIN_INT_CAST size, 0/*flags*/);
2873 #ifdef NCBI_OS_MSWIN
2874 /* recv() resets IO event recording */
2875 sock->readable = sock->closing;
2876 #endif /*NCBI_OS_MSWIN*/
2877
2878 /* success/EOF? */
2879 if (x_read >= 0 ||
2880 (x_read < 0 && ((error = SOCK_ERRNO) == SOCK_ENOTCONN || /*NCBI_FAKE_WARNING*/
2881 error == SOCK_ETIMEDOUT ||
2882 error == SOCK_ENETRESET ||
2883 error == SOCK_ECONNRESET ||
2884 error == SOCK_ECONNABORTED))) {
2885 /* statistics & logging */
2886 if ((x_read < 0 && sock->log != eOff) ||
2887 ((sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
2888 && (!sock->sslctx || flag > 0))) {
2889 s_DoLog(x_read < 0
2890 ? (sock->n_read && sock->n_written
2891 ? eLOG_Error : eLOG_Trace)
2892 : eLOG_Note, sock, eIO_Read,
2893 x_read < 0 ? (void*) &error :
2894 x_read > 0 ? buf : 0,
2895 (size_t)(x_read < 0 ? 0 : x_read), 0);
2896 }
2897
2898 if (x_read > 0) {
2899 assert((size_t) x_read <= size);
2900 sock->n_read += (TNCBI_BigCount) x_read;
2901 *n_read = (size_t) x_read;
2902 } else {
2903 /* catch EOF/failure */
2904 sock->eof = 1/*true*/;
2905 if (x_read) {
2906 sock->r_status = sock->w_status = eIO_Closed;
2907 return eIO_Unknown/*error*/;
2908 }
2909 #ifdef NCBI_OS_MSWIN
2910 sock->closing = 1/*true*/;
2911 #endif /*NCBI_OS_MSWIN*/
2912 }
2913 sock->r_status = eIO_Success;
2914 break/*success*/;
2915 }
2916
2917 if (error == SOCK_EWOULDBLOCK || error == SOCK_EAGAIN) {
2918 /* blocked -- wait for data to come; return if timeout/error */
2919 EIO_Status status;
2920 SSOCK_Poll poll;
2921
2922 if (sock->r_tv_set && !(sock->r_tv.tv_sec | sock->r_tv.tv_usec)){
2923 sock->r_status = eIO_Timeout;
2924 break/*timeout*/;
2925 }
2926 if (readable) {
2927 CORE_TRACEF(("%s[SOCK::Recv] "
2928 " Spurious false indication of data ready",
2929 s_ID(sock, _id)));
2930 }
2931 poll.sock = sock;
2932 poll.event = eIO_Read;
2933 poll.revent = eIO_Open;
2934 status = s_Select(1, &poll, SOCK_GET_TIMEOUT(sock, r), 1/*asis*/);
2935 assert(poll.event == eIO_Read);
2936 if (status == eIO_Timeout) {
2937 sock->r_status = eIO_Timeout;
2938 break/*timeout*/;
2939 }
2940 if (status != eIO_Success)
2941 return status;
2942 if (poll.revent == eIO_Close)
2943 return eIO_Unknown;
2944 assert(poll.revent == eIO_Read);
2945 readable = 1/*true*/;
2946 continue/*read again*/;
2947 }
2948
2949 if (error != SOCK_EINTR) {
2950 const char* strerr = SOCK_STRERROR(error);
2951 CORE_LOGF_ERRNO_EXX(7, eLOG_Trace,
2952 error, strerr ? strerr : "",
2953 ("%s[SOCK::Recv] "
2954 " Failed recv()",
2955 s_ID(sock, _id)));
2956 UTIL_ReleaseBuffer(strerr);
2957 /* don't want to handle all possible errors...
2958 let them be "unknown" */
2959 sock->r_status = eIO_Unknown;
2960 break/*unknown*/;
2961 }
2962
2963 if (sock->i_on_sig == eOn
2964 || (sock->i_on_sig == eDefault && s_InterruptOnSignal == eOn)) {
2965 sock->r_status = eIO_Interrupt;
2966 break/*interrupt*/;
2967 }
2968 }
2969
2970 return (EIO_Status) sock->r_status;
2971 }
2972
2973
2974 /*fwdecl*/
2975 static EIO_Status s_WritePending(SOCK, const struct timeval*, int, int);
2976
2977
2978 /* Read/Peek data from the socket. Return eIO_Success iff some data have been
2979 * read. Return other (error) code if an error/EOF occurred (zero bytes read).
2980 * (MSG_PEEK is not implemented on Mac, and it is poorly implemented
2981 * on Win32, so we had to implement this feature by ourselves.)
2982 * NB: peek = {-1=upread(!buf && !size), 0=read, 1=peek}
2983 */
s_Read_(SOCK sock,void * buf,size_t size,size_t * n_read,int peek)2984 static EIO_Status s_Read_(SOCK sock,
2985 void* buf,
2986 size_t size,
2987 size_t* n_read,
2988 int peek)
2989 {
2990 unsigned int rtv_set;
2991 struct timeval rtv;
2992 char _id[MAXIDLEN];
2993 EIO_Status status;
2994 int/*bool*/ done;
2995
2996 assert(sock->type & eSocket);
2997
2998 if (sock->type != eDatagram && peek >= 0) {
2999 *n_read = 0;
3000 status = s_WritePending(sock, SOCK_GET_TIMEOUT(sock, r), 0, 0);
3001 if (sock->pending) {
3002 assert(status != eIO_Success);
3003 return status == eIO_Closed ? eIO_Unknown : status;
3004 }
3005 if (!size && peek >= 0) {
3006 status = (EIO_Status) sock->r_status;
3007 if (status == eIO_Closed)
3008 status = eIO_Unknown;
3009 else if (sock->eof)
3010 status = eIO_Closed;
3011 return status;
3012 }
3013 }
3014
3015 if (sock->type == eDatagram || peek >= 0) {
3016 *n_read = (peek
3017 ? BUF_Peek(sock->r_buf, buf, size)
3018 : BUF_Read(sock->r_buf, buf, size));
3019 if (sock->type == eDatagram) {
3020 if (size && !*n_read) {
3021 sock->r_status = eIO_Closed;
3022 return eIO_Closed;
3023 }
3024 return !size ? (EIO_Status) sock->r_status : eIO_Success;
3025 }
3026 if (*n_read && (*n_read == size || !peek))
3027 return eIO_Success;
3028 } else
3029 *n_read = 0;
3030
3031 if ((status = (EIO_Status) sock->r_status) == eIO_Closed || sock->eof) {
3032 if (*n_read)
3033 return eIO_Success;
3034 if (status == eIO_Closed) {
3035 CORE_TRACEF(("%s[SOCK::Read] "
3036 " Socket already shut down for reading",
3037 s_ID(sock, _id)));
3038 return eIO_Unknown;
3039 }
3040 return eIO_Closed/*EOF*/;
3041 }
3042
3043 done = 0/*false*/;
3044 if ((rtv_set = sock->r_tv_set) != 0)
3045 rtv = sock->r_tv;
3046 assert(!*n_read || peek > 0);
3047 assert((peek >= 0 && size) || (peek < 0 && !buf && !size));
3048 do {
3049 char xx_buf[SOCK_BUF_CHUNK_SIZE / 4], *x_buf, *p_buf;
3050 size_t x_todo, x_read, x_save;
3051
3052 if (buf && (x_todo = size - *n_read) >= SOCK_BUF_CHUNK_SIZE) {
3053 x_buf = (char*) buf + *n_read;
3054 p_buf = 0;
3055 } else if (!(p_buf = (char*) malloc(SOCK_BUF_CHUNK_SIZE))) {
3056 x_todo = sizeof(xx_buf);
3057 x_buf = xx_buf;
3058 } else {
3059 x_todo = SOCK_BUF_CHUNK_SIZE;
3060 x_buf = p_buf;
3061 }
3062 if (sock->sslctx) {
3063 int error;
3064 FSSLRead sslread = s_SSL ? s_SSL->Read : 0;
3065 if (!sslread) {
3066 if (p_buf)
3067 free(p_buf);
3068 status = eIO_NotSupported;
3069 break/*error*/;
3070 }
3071 status = sslread(sock->sslctx->sess,
3072 x_buf, x_todo, &x_read, &error);
3073 assert(status == eIO_Success || !x_read);
3074 assert(status == eIO_Success || error);
3075 assert(x_read <= x_todo);
3076
3077 /* statistics & logging */
3078 if ((status != eIO_Success && sock->log != eOff) ||
3079 sock->log == eOn || (sock->log == eDefault && s_Log == eOn)){
3080 s_DoLog(x_read ? eLOG_Note : eLOG_Trace, sock, eIO_Read,
3081 x_read ? x_buf :
3082 status != eIO_Closed || !sock->eof ?
3083 (void*) &error : 0,
3084 status != eIO_Success ? 0 : x_read,
3085 x_read ? " [decrypt]" : 0);
3086 }
3087
3088 if (status == eIO_Closed && !sock->eof)
3089 sock->r_status = eIO_Closed;
3090 } else {
3091 x_read = 0;
3092 status = s_Recv(sock, x_buf, x_todo, &x_read, 0);
3093 assert(status == eIO_Success || !x_read);
3094 assert(x_read <= x_todo);
3095 }
3096 if (status != eIO_Success || !x_read) {
3097 if (p_buf)
3098 free(p_buf);
3099 if (status == eIO_Success)
3100 status = eIO_Closed/*EOF*/;
3101 break;
3102 }
3103 assert(status == eIO_Success && 0 < x_read && x_read <= x_todo);
3104
3105 if (x_read < x_todo)
3106 done = 1/*true*/;
3107
3108 if (peek >= 0) {
3109 assert(size > *n_read); /* NB: subsumes size > 0 */
3110 x_todo = size - *n_read;
3111 if (x_todo > x_read)
3112 x_todo = x_read;
3113 if (buf && (p_buf || x_buf == xx_buf))
3114 memcpy((char*) buf + *n_read, x_buf, x_todo);
3115 x_save = peek ? x_read : x_read - x_todo;
3116 } else
3117 x_save = x_read;
3118 if (x_save) {
3119 /* store the newly read/excess data in the internal input buffer */
3120 if (!p_buf || x_save < SOCK_BUF_CHUNK_SIZE / 2) {
3121 sock->eof = !BUF_Write(&sock->r_buf,
3122 peek ? x_buf : x_buf + x_todo,
3123 x_save);
3124 if (p_buf)
3125 free(p_buf);
3126 } else {
3127 sock->eof = !BUF_AppendEx(&sock->r_buf, p_buf, peek
3128 ? SOCK_BUF_CHUNK_SIZE
3129 : SOCK_BUF_CHUNK_SIZE - x_todo,
3130 peek ? p_buf : p_buf + x_todo,
3131 x_save);
3132 if (sock->eof)
3133 free(p_buf);
3134 }
3135 if (sock->eof) {
3136 CORE_LOGF_ERRNO_X(8, eLOG_Error, errno,
3137 ("%s[SOCK::Read] "
3138 " Cannot save %lu byte%s of unread data",
3139 s_ID(sock, _id), (unsigned long) x_save,
3140 &"s"[x_save == 1]));
3141 sock->r_status = eIO_Closed/*failure*/;
3142 x_read = peek >= 0 ? x_todo : 0;
3143 status = eIO_Unknown;
3144 } else if (peek >= 0)
3145 x_read = x_todo;
3146 } else if (p_buf)
3147 free(p_buf);
3148 *n_read += x_read;
3149
3150 if (status != eIO_Success || done)
3151 break;
3152 /*zero timeout*/
3153 sock->r_tv_set = 1;
3154 memset(&sock->r_tv, 0, sizeof(sock->r_tv));
3155 } while (peek < 0 || (!buf && *n_read < size));
3156 if ((sock->r_tv_set = rtv_set & 1) != 0)
3157 x_tvcpy(&sock->r_tv, &rtv);
3158
3159 return *n_read ? eIO_Success : status;
3160 }
3161
3162
s_Read(SOCK sock,void * buf,size_t size,size_t * n_read,int peek)3163 static EIO_Status s_Read(SOCK sock,
3164 void* buf,
3165 size_t size,
3166 size_t* n_read,
3167 int peek)
3168 {
3169 EIO_Status status = s_Read_(sock, buf, size, n_read, peek);
3170 if (s_ErrHook && status != eIO_Success
3171 && (status != eIO_Closed
3172 || !(sock->r_status == eIO_Success && sock->eof))) {
3173 SSOCK_ErrInfo info;
3174 char addr[40];
3175 memset(&info, 0, sizeof(info));
3176 info.type = eSOCK_ErrIO;
3177 info.sock = sock;
3178 if (sock->port) {
3179 SOCK_ntoa(sock->host, addr, sizeof(addr));
3180 info.host = addr;
3181 info.port = sock->port;
3182 }
3183 #ifdef NCBI_OS_UNIX
3184 else
3185 info.host = sock->path;
3186 #endif /*NCBI_OS_UNIX*/
3187 info.event = eIO_Read;
3188 info.status = status;
3189 s_ErrorCallback(&info);
3190 }
3191 assert(*n_read <= size);
3192 return status;
3193 }
3194
3195
3196 /* s_Select() with stall protection: try pull incoming data from sockets.
3197 * This method returns array of polls, "revent"s of which are always
3198 * compatible with requested "event"s. That is, it always strips additional
3199 * events that s_Select() may have set to indicate additional I/O events
3200 * some sockets are ready for. Return eIO_Timeout if no compatible events
3201 * were found (all sockets are not ready for inquired respective I/O) within
3202 * the specified timeout (and no other socket error was flagged).
3203 * Return eIO_Success if at least one socket is ready. Return the number
3204 * of sockets that are ready via pointer argument "n_ready" (may be NULL).
3205 * Return other error code to indicate an error condition.
3206 */
s_SelectStallsafe(size_t n,SSOCK_Poll polls[],const struct timeval * tv,size_t * n_ready)3207 static EIO_Status s_SelectStallsafe(size_t n,
3208 SSOCK_Poll polls[],
3209 const struct timeval* tv,
3210 size_t* n_ready)
3211 {
3212 size_t i, k;
3213
3214 assert(!n || polls);
3215
3216 for (;;) { /* until one full "tv" term expires or an error occurs */
3217 int/*bool*/ pending;
3218 EIO_Status status;
3219
3220 status = s_Select(n, polls, tv, 0);
3221 if (status != eIO_Success) {
3222 if (n_ready)
3223 *n_ready = 0;
3224 return status;
3225 }
3226
3227 k = 0;
3228 pending = 0;
3229 for (i = 0; i < n; ++i) {
3230 if (polls[i].revent == eIO_Close)
3231 break;
3232 if (polls[i].revent & polls[i].event)
3233 break;
3234 if (polls[i].revent != eIO_Open && !pending) {
3235 pending = 1;
3236 k = i;
3237 }
3238 }
3239 if (i < n/*ready*/)
3240 break;
3241
3242 /* all sockets are not ready for the requested events */
3243 assert(pending);
3244 for (i = k; i < n; ++i) {
3245 static const struct timeval zero = { 0 };
3246 SOCK sock = polls[i].sock;
3247 /* try to push pending writes */
3248 if (polls[i].event == eIO_Read && polls[i].revent == eIO_Write) {
3249 assert(sock &&
3250 sock->sock != SOCK_INVALID &&
3251 sock->type == eSocket &&
3252 sock->w_status != eIO_Closed &&
3253 (sock->pending | sock->w_len));
3254 s_WritePending(sock, &zero, 1/*writeable*/, 0);
3255 if (sock->r_status == eIO_Closed || sock->eof) {
3256 polls[i].revent = eIO_Read;
3257 pending = 0;
3258 } else
3259 polls[i].revent = eIO_Open;
3260 continue;
3261 }
3262 /* try to upread immediately readable sockets */
3263 if (polls[i].event == eIO_Write && polls[i].revent == eIO_Read) {
3264 size_t dummy;
3265 assert(sock &&
3266 sock->sock != SOCK_INVALID &&
3267 sock->type == eSocket &&
3268 sock->w_status != eIO_Closed &&
3269 sock->r_status != eIO_Closed &&
3270 !sock->eof && !sock->pending &&
3271 (sock->r_on_w == eOn
3272 || (sock->r_on_w == eDefault
3273 && s_ReadOnWrite == eOn)));
3274 s_Read_(sock, 0, 0, &dummy, -1/*upread*/);
3275 if (sock->w_status == eIO_Closed) {
3276 polls[i].revent = eIO_Write;
3277 pending = 0;
3278 } else
3279 polls[i].revent = eIO_Open;
3280 }
3281 }
3282 if (!pending)
3283 break;
3284 }
3285
3286 k = 0;
3287 for (i = 0; i < n; ++i) {
3288 if (polls[i].revent != eIO_Close) {
3289 polls[i].revent = (EIO_Event)(polls[i].revent & polls[i].event);
3290 if (!polls[i].revent)
3291 continue;
3292 }
3293 ++k;
3294 }
3295
3296 if (n_ready)
3297 *n_ready = k;
3298
3299 return k ? eIO_Success : eIO_Timeout;
3300 }
3301
3302
s_Wait(SOCK sock,EIO_Event event,const STimeout * timeout)3303 static EIO_Status s_Wait(SOCK sock, EIO_Event event, const STimeout* timeout)
3304 {
3305 struct timeval tv;
3306 SSOCK_Poll poll;
3307 EIO_Status status;
3308
3309 poll.sock = sock;
3310 poll.event = event;
3311 poll.revent = eIO_Open;
3312 status = s_SelectStallsafe(1, &poll, s_to2tv(timeout, &tv), 0);
3313 assert(poll.event == event);
3314 if (status != eIO_Success)
3315 return status;
3316 if (poll.revent == eIO_Close)
3317 return eIO_Unknown;
3318 assert(!(poll.revent ^ (poll.revent & event)));
3319 return status/*success*/;
3320 }
3321
3322
3323 #ifdef NCBI_OS_MSWIN
s_AddTimeout(struct timeval * tv,int ms_addend)3324 static void s_AddTimeout(struct timeval* tv, int ms_addend)
3325 {
3326 tv->tv_usec += (ms_addend % 1000) * 1000;
3327 tv->tv_sec += ms_addend / 1000;
3328 if (tv->tv_usec >= 10000000) {
3329 tv->tv_sec += tv->tv_usec / 10000000;
3330 tv->tv_usec %= 10000000;
3331 }
3332 }
3333 #endif /*NCBI_OS_MSWIN*/
3334
3335
3336 #ifdef SOCK_SEND_SLICE
3337 # define s_Send s_Send_
3338 #endif /*SOCK_SEND_SLICE*/
3339
3340
3341 /* Write data to the socket "as is" (as many bytes at once as possible).
3342 * Return eIO_Success iff at least some bytes have been written successfully.
3343 * Otherwise (nothing written), return an error code to indicate the problem.
3344 * NOTE: This call is for stream sockets only.
3345 */
s_Send(SOCK sock,const void * data,size_t size,size_t * n_written,int flag)3346 static EIO_Status s_Send(SOCK sock,
3347 const void* data,
3348 size_t size,
3349 size_t* n_written,
3350 int flag)
3351 {
3352 #ifdef NCBI_OS_MSWIN
3353 int wait_buf_ms = 0;
3354 struct timeval waited;
3355 memset(&waited, 0, sizeof(waited));
3356 #endif /*NCBI_OS_MSWIN*/
3357
3358 assert(sock->type == eSocket && data && size > 0 && !*n_written);
3359
3360 if (sock->w_status == eIO_Closed)
3361 return eIO_Closed;
3362
3363 for (;;) { /* optionally auto-resume if interrupted */
3364 int error = 0;
3365
3366 ssize_t x_written = send(sock->sock, (void*) data, WIN_INT_CAST size,
3367 flag < 0 ? MSG_OOB : 0);
3368
3369 if (x_written >= 0 ||
3370 (x_written < 0 && ((error = SOCK_ERRNO) == SOCK_EPIPE ||
3371 error == SOCK_ENOTCONN ||
3372 error == SOCK_ETIMEDOUT ||
3373 error == SOCK_ENETRESET ||
3374 error == SOCK_ECONNRESET ||
3375 error == SOCK_ECONNABORTED))) {
3376 /* statistics & logging */
3377 if ((x_written <= 0 && sock->log != eOff) ||
3378 ((sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
3379 && (!sock->sslctx || flag > 0))) {
3380 s_DoLog(x_written <= 0
3381 ? (sock->n_read && sock->n_written
3382 ? eLOG_Error : eLOG_Trace)
3383 : eLOG_Note, sock, eIO_Write,
3384 x_written <= 0 ? (void*) &error : data,
3385 (size_t)(x_written <= 0 ? 0 : x_written),
3386 flag < 0 ? "" : 0);
3387 }
3388
3389 if (x_written > 0) {
3390 sock->n_written += (TNCBI_BigCount) x_written;
3391 *n_written = (size_t) x_written;
3392 sock->w_status = eIO_Success;
3393 break/*success*/;
3394 }
3395 if (x_written < 0) {
3396 if (error != SOCK_EPIPE)
3397 sock->r_status = eIO_Closed;
3398 sock->w_status = eIO_Closed;
3399 break/*closed*/;
3400 }
3401 }
3402
3403 if (flag < 0/*OOB*/ || !x_written)
3404 return eIO_Unknown;
3405
3406 /* blocked -- retry if unblocked before the timeout expires
3407 * (use stall protection if specified) */
3408 if (error == SOCK_EWOULDBLOCK || error == SOCK_EAGAIN
3409 #ifdef NCBI_OS_MSWIN
3410 || error == WSAENOBUFS
3411 #endif /*NCBI_OS_MSWIN*/
3412 ) {
3413 SSOCK_Poll poll;
3414 EIO_Status status;
3415 const struct timeval* timeout;
3416
3417 #ifdef NCBI_OS_MSWIN
3418 struct timeval slice;
3419 unsigned int writable = sock->writable;
3420
3421 /* special send()'s semantics of IO event recording reset */
3422 sock->writable = 0/*false*/;
3423 if (error == WSAENOBUFS) {
3424 if (size < SOCK_BUF_CHUNK_SIZE / 4) {
3425 s_AddTimeout(&waited, wait_buf_ms);
3426 if (s_IsSmallerTimeout(SOCK_GET_TIMEOUT(sock, w),&waited)){
3427 sock->w_status = eIO_Timeout;
3428 return eIO_Timeout;
3429 }
3430 if (wait_buf_ms == 0)
3431 wait_buf_ms = 10;
3432 else if (wait_buf_ms < 500/*640*/)
3433 wait_buf_ms <<= 1;
3434 slice.tv_sec = 0;
3435 slice.tv_usec = wait_buf_ms * 1000;
3436 } else {
3437 size >>= 1;
3438 memset(&slice, 0, sizeof(slice));
3439 }
3440 timeout = &slice;
3441 } else {
3442 if (wait_buf_ms) {
3443 wait_buf_ms = 0;
3444 memset(&waited, 0, sizeof(waited));
3445 }
3446 timeout = SOCK_GET_TIMEOUT(sock, w);
3447 }
3448 #else
3449 {
3450 if (sock->w_tv_set && !(sock->w_tv.tv_sec|sock->w_tv.tv_usec)){
3451 sock->w_status = eIO_Timeout;
3452 break/*timeout*/;
3453 }
3454 timeout = SOCK_GET_TIMEOUT(sock, w);
3455 }
3456 #endif /*NCBI_OS_MSWIN*/
3457
3458 poll.sock = sock;
3459 poll.event = eIO_Write;
3460 poll.revent = eIO_Open;
3461 /* stall protection: try pulling incoming data from the socket */
3462 status = s_SelectStallsafe(1, &poll, timeout, 0);
3463 assert(poll.event == eIO_Write);
3464 #ifdef NCBI_OS_MSWIN
3465 if (error == WSAENOBUFS) {
3466 assert(timeout == &slice);
3467 sock->writable = writable/*restore*/;
3468 if (status == eIO_Timeout)
3469 continue/*try to write again*/;
3470 } else
3471 #endif /*NCBI_OS_MSWIN*/
3472 if (status == eIO_Timeout) {
3473 sock->w_status = eIO_Timeout;
3474 break/*timeout*/;
3475 }
3476 if (status != eIO_Success)
3477 return status;
3478 if (poll.revent == eIO_Close)
3479 return eIO_Unknown;
3480 assert(poll.event == eIO_Write);
3481 continue/*write again*/;
3482 }
3483
3484 if (error != SOCK_EINTR) {
3485 char _id[MAXIDLEN];
3486 const char* strerr = SOCK_STRERROR(error);
3487 CORE_LOGF_ERRNO_EXX(11, eLOG_Trace,
3488 error, strerr ? strerr : "",
3489 ("%s[SOCK::Send] "
3490 " Failed send()",
3491 s_ID(sock, _id)));
3492 UTIL_ReleaseBuffer(strerr);
3493 /* don't want to handle all possible errors...
3494 let them be "unknown" */
3495 sock->w_status = eIO_Unknown;
3496 break/*unknown*/;
3497 }
3498
3499 if (sock->i_on_sig == eOn
3500 || (sock->i_on_sig == eDefault && s_InterruptOnSignal == eOn)) {
3501 sock->w_status = eIO_Interrupt;
3502 break/*interrupt*/;
3503 }
3504 }
3505
3506 return (EIO_Status) sock->w_status;
3507 }
3508
3509
3510 /* Wrapper for s_Send() that slices the output buffer for some brain-dead
3511 * systems (e.g. old Macs) that cannot handle large data chunks in "send()".
3512 * Return eIO_Success only if some data have been successfully sent;
3513 * otherwise, an error code if nothing at all has been sent.
3514 */
3515 #ifdef SOCK_SEND_SLICE
3516 # undef s_Send
s_Send(SOCK sock,const void * data,size_t size,size_t * n_written,int flag)3517 static EIO_Status s_Send(SOCK sock,
3518 const void* data,
3519 size_t size,
3520 size_t* n_written,
3521 int flag)
3522 {
3523 /* split output buffer in slices (of size <= SOCK_SEND_SLICE) */
3524 EIO_Status status;
3525
3526 assert(!*n_written);
3527
3528 do {
3529 size_t n_todo = size > SOCK_SEND_SLICE ? SOCK_SEND_SLICE : size;
3530 size_t n_done = 0;
3531 status = s_Send_(sock, data, n_todo, &n_done, flag);
3532 assert((status == eIO_Success) == (n_done > 0));
3533 if (status != eIO_Success)
3534 break;
3535 *n_written += n_done;
3536 if (n_todo != n_done)
3537 break;
3538 size -= n_done;
3539 data = (const char*) data + n_done;
3540 } while (size);
3541
3542 return *n_written ? eIO_Success : status;
3543 }
3544 #endif /*SOCK_SEND_SLICE*/
3545
3546
3547 /* Return eIO_Success iff some data have been written; error code otherwise */
s_WriteData(SOCK sock,const void * data,size_t size,size_t * n_written,int oob)3548 static EIO_Status s_WriteData(SOCK sock,
3549 const void* data,
3550 size_t size,
3551 size_t* n_written,
3552 int/*bool*/ oob)
3553 {
3554 assert(sock->type == eSocket && !sock->pending && size);
3555
3556 if (sock->sslctx) {
3557 int error;
3558 EIO_Status status;
3559 FSSLWrite sslwrite = s_SSL ? s_SSL->Write : 0;
3560 if (!sslwrite || oob) {
3561 *n_written = 0;
3562 return eIO_NotSupported;
3563 }
3564 status = sslwrite(sock->sslctx->sess, data, size, n_written, &error);
3565 assert((status == eIO_Success) == (*n_written > 0));
3566 assert(status == eIO_Success || error);
3567 assert(*n_written <= size);
3568
3569 /* statistics & logging */
3570 if ((status != eIO_Success && sock->log != eOff) ||
3571 sock->log == eOn || (sock->log == eDefault && s_Log == eOn)) {
3572 s_DoLog(*n_written > 0 ? eLOG_Note : eLOG_Trace, sock, eIO_Write,
3573 status == eIO_Success ? data : (void*) &error,
3574 status != eIO_Success ? 0 : *n_written,
3575 n_written > 0 ? " [encrypt]" : 0);
3576 }
3577
3578 if (status == eIO_Closed)
3579 sock->w_status = eIO_Closed;
3580 return status;
3581 }
3582
3583 *n_written = 0;
3584 return s_Send(sock, data, size, n_written, oob ? -1 : 0);
3585 }
3586
3587
3588 struct XWriteBufCtx {
3589 SOCK sock;
3590 EIO_Status status;
3591 };
3592
3593
x_WriteBuf(void * data,const void * buf,size_t size)3594 static size_t x_WriteBuf(void* data, const void* buf, size_t size)
3595 {
3596 struct XWriteBufCtx* ctx = (struct XWriteBufCtx*) data;
3597 size_t n_written = 0;
3598
3599 assert(buf && size && ctx->status == eIO_Success);
3600
3601 do {
3602 size_t x_written;
3603 ctx->status = s_WriteData(ctx->sock, buf, size, &x_written, 0);
3604 assert((ctx->status == eIO_Success) == (x_written > 0));
3605 assert(x_written <= size);
3606 if (ctx->status != eIO_Success)
3607 break;
3608 n_written += x_written;
3609 size -= x_written;
3610 buf = (const char*) buf + x_written;
3611 } while (size);
3612
3613 assert(!size/*n_written == initial size*/ || ctx->status != eIO_Success);
3614
3615 return n_written;
3616 }
3617
3618
s_WritePending(SOCK sock,const struct timeval * tv,int writeable,int oob)3619 static EIO_Status s_WritePending(SOCK sock,
3620 const struct timeval* tv,
3621 int/*bool*/ writeable,
3622 int/*bool*/ oob)
3623 {
3624 struct XWriteBufCtx ctx;
3625 unsigned int restore;
3626 unsigned int wtv_set;
3627 struct timeval wtv;
3628
3629 assert(sock->type == eSocket && sock->sock != SOCK_INVALID);
3630
3631 if (sock->pending) {
3632 const char* what;
3633 int error;
3634 EIO_Status status = s_IsConnected_(sock, tv, &what, &error, writeable);
3635 if (status != eIO_Success) {
3636 if (status != eIO_Timeout) {
3637 char _id[MAXIDLEN];
3638 const char* strerr = s_StrError(sock, error);
3639 CORE_LOGF_ERRNO_EXX(12, sock->log != eOff
3640 ? eLOG_Error : eLOG_Trace,
3641 error, strerr ? strerr : "",
3642 ("%s[SOCK::WritePending] "
3643 " Failed %s: %s",
3644 s_ID(sock, _id),
3645 what ? what : "pending connect()",
3646 IO_StatusStr(status)));
3647 UTIL_ReleaseBuffer(strerr);
3648 sock->w_status = status;
3649 }
3650 return status;
3651 }
3652 assert(sock->connected && !sock->pending);
3653 }
3654 if ((!sock->sslctx && oob) || !sock->w_len)
3655 return eIO_Success;
3656 if (sock->w_status == eIO_Closed)
3657 return eIO_Closed;
3658 assert(sock->w_len == BUF_Size(sock->w_buf));
3659
3660 if (tv != &sock->w_tv) {
3661 if ((wtv_set = sock->w_tv_set) != 0)
3662 wtv = sock->w_tv;
3663 SOCK_SET_TIMEOUT(sock, w, tv);
3664 restore = 1;
3665 } else
3666 restore = wtv_set/*to silence compiler warning*/ = 0;
3667
3668 ctx.sock = sock;
3669 ctx.status = eIO_Success;
3670 sock->w_len -= BUF_PeekAtCB(sock->w_buf,
3671 BUF_Size(sock->w_buf) - sock->w_len,
3672 x_WriteBuf, &ctx, sock->w_len);
3673 assert((sock->w_len != 0) == (ctx.status != eIO_Success));
3674
3675 if (restore && (sock->w_tv_set = wtv_set & 1) != 0)
3676 x_tvcpy(&sock->w_tv, &wtv);
3677 return ctx.status;
3678 }
3679
3680
3681 /* Write to the socket. Return eIO_Success if some data have been written.
3682 * Return other (error) code only if nothing at all can be written.
3683 */
s_Write_(SOCK sock,const void * data,size_t size,size_t * n_written,int oob)3684 static EIO_Status s_Write_(SOCK sock,
3685 const void* data,
3686 size_t size,
3687 size_t* n_written,
3688 int/*bool*/ oob)
3689 {
3690 EIO_Status status;
3691
3692 assert(sock->type & eSocket);
3693
3694 if (sock->type == eDatagram) {
3695 sock->w_len = 0;
3696 if (sock->eof) {
3697 BUF_Erase(sock->w_buf);
3698 sock->eof = 0;
3699 }
3700 if (BUF_Write(&sock->w_buf, data, size)) {
3701 *n_written = size;
3702 sock->w_status = eIO_Success;
3703 } else {
3704 *n_written = 0;
3705 sock->w_status = eIO_Unknown;
3706 }
3707 return (EIO_Status) sock->w_status;
3708 }
3709
3710 if (sock->w_status == eIO_Closed) {
3711 if (size) {
3712 CORE_DEBUG_ARG(char _id[MAXIDLEN];)
3713 CORE_TRACEF(("%s[SOCK::Write] "
3714 " Socket already shut down for writing",
3715 s_ID(sock, _id)));
3716 }
3717 *n_written = 0;
3718 return eIO_Closed;
3719 }
3720
3721 status = s_WritePending(sock, SOCK_GET_TIMEOUT(sock, w), 0, oob);
3722 if (status != eIO_Success || !size) {
3723 *n_written = 0;
3724 if (status == eIO_Timeout || status == eIO_Closed)
3725 return status;
3726 return size ? status : eIO_Success;
3727 }
3728
3729 assert(size && sock->w_len == 0);
3730 return s_WriteData(sock, data, size, n_written, oob);
3731 }
3732
3733
s_Write(SOCK sock,const void * data,size_t size,size_t * n_written,int oob)3734 static EIO_Status s_Write(SOCK sock,
3735 const void* data,
3736 size_t size,
3737 size_t* n_written,
3738 int/*bool*/ oob)
3739 {
3740 EIO_Status status = s_Write_(sock, data, size, n_written, oob);
3741 if (s_ErrHook && status != eIO_Success) {
3742 SSOCK_ErrInfo info;
3743 char addr[40];
3744 memset(&info, 0, sizeof(info));
3745 info.type = eSOCK_ErrIO;
3746 info.sock = sock;
3747 if (sock->port) {
3748 SOCK_ntoa(sock->host, addr, sizeof(addr));
3749 info.host = addr;
3750 info.port = sock->port;
3751 }
3752 #ifdef NCBI_OS_UNIX
3753 else
3754 info.host = sock->path;
3755 #endif /*NCBI_OS_UNIX*/
3756 info.event = eIO_Write;
3757 info.status = status;
3758 s_ErrorCallback(&info);
3759 }
3760 assert(*n_written <= size);
3761 return status;
3762 }
3763
3764
3765 /* For non-datagram sockets only */
s_Shutdown(SOCK sock,EIO_Event dir,const struct timeval * tv)3766 static EIO_Status s_Shutdown(SOCK sock,
3767 EIO_Event dir,
3768 const struct timeval* tv)
3769 {
3770 int error;
3771 char _id[MAXIDLEN];
3772 EIO_Status status = eIO_Success;
3773 int how = SOCK_SHUTDOWN_WR;
3774
3775 assert(sock->type == eSocket);
3776
3777 switch (dir) {
3778 case eIO_Read:
3779 if (sock->eof) {
3780 /* hit EOF (and may be not yet shut down) -- so, flag it as been
3781 * shut down, but do not perform the actual system call,
3782 * as it can cause smart OS'es like Linux to complain.
3783 */
3784 sock->eof = 0/*false*/;
3785 sock->r_status = eIO_Closed;
3786 }
3787 if (sock->r_status == eIO_Closed)
3788 return eIO_Success; /* has been shut down already */
3789 sock->r_status = eIO_Closed;
3790 how = SOCK_SHUTDOWN_RD;
3791 break;
3792
3793 case eIO_ReadWrite:
3794 if (sock->eof) {
3795 sock->eof = 0/*false*/;
3796 sock->r_status = eIO_Closed;
3797 } else
3798 how = SOCK_SHUTDOWN_RDWR;
3799 if (sock->w_status == eIO_Closed && sock->r_status == eIO_Closed)
3800 return eIO_Success; /* has been shut down already */
3801 /*FALLTHRU*/
3802
3803 case eIO_Write:
3804 if (sock->w_status == eIO_Closed && dir == eIO_Write)
3805 return eIO_Success; /* has been shut down already */
3806 /*FALLTHRU*/
3807
3808 case eIO_Open:
3809 case eIO_Close:
3810 if (sock->w_status != eIO_Closed) {
3811 if ((status = s_WritePending(sock, tv, 0, 0)) != eIO_Success) {
3812 if (!sock->pending && sock->w_len) {
3813 CORE_LOGF_X(13, !tv || (tv->tv_sec | tv->tv_usec)
3814 ? eLOG_Warning : eLOG_Trace,
3815 ("%s[SOCK::%s] "
3816 " %s with output (%lu byte%s) still pending"
3817 " (%s)", s_ID(sock, _id),
3818 dir & eIO_ReadWrite ? "Shutdown" : "Close",
3819 !dir ? "Leaving " : dir == eIO_Close
3820 ? "Closing" : dir == eIO_Write
3821 ? "Shutting down for write"
3822 : "Shutting down for read/write",
3823 (unsigned long) sock->w_len,
3824 &"s"[sock->w_len == 1],
3825 IO_StatusStr(status)));
3826 } else if (!(dir & eIO_ReadWrite) && !sock->w_len)
3827 status = eIO_Success;
3828 }
3829 if (!sock->pending && sock->sslctx) {
3830 FSSLClose sslclose = s_SSL ? s_SSL->Close : 0;
3831 if (sslclose) {
3832 const unsigned int rtv_set = sock->r_tv_set;
3833 const unsigned int wtv_set = sock->w_tv_set;
3834 struct timeval rtv;
3835 struct timeval wtv;
3836 if (rtv_set)
3837 rtv = sock->r_tv;
3838 if (wtv_set)
3839 wtv = sock->w_tv;
3840 SOCK_SET_TIMEOUT(sock, r, tv);
3841 SOCK_SET_TIMEOUT(sock, w, tv);
3842 status = sslclose(sock->sslctx->sess, how, &error);
3843 if ((sock->w_tv_set = wtv_set & 1) != 0)
3844 x_tvcpy(&sock->w_tv, &wtv);
3845 if ((sock->r_tv_set = rtv_set & 1) != 0)
3846 x_tvcpy(&sock->r_tv, &rtv);
3847 if (status != eIO_Success) {
3848 const char* strerr = s_StrError(sock, error);
3849 CORE_LOGF_ERRNO_EXX(127, eLOG_Trace,
3850 error, strerr ? strerr : "",
3851 ("%s[SOCK::%s] "
3852 " Failed SSL bye",
3853 s_ID(sock, _id),
3854 dir & eIO_ReadWrite
3855 ? "Shutdown" : "Close"));
3856 UTIL_ReleaseBuffer(strerr);
3857 }
3858 }
3859 }
3860 sock->w_status = eIO_Closed;
3861 }
3862
3863 sock->w_len = 0;
3864 BUF_Erase(sock->w_buf);
3865 if (dir != eIO_Write) {
3866 sock->eof = 0/*false*/;
3867 sock->r_status = eIO_Closed;
3868 if (!(dir & eIO_ReadWrite))
3869 return status;
3870 }
3871 break;
3872
3873 default:
3874 assert(0);
3875 return eIO_InvalidArg;
3876 }
3877 assert((EIO_Event)(dir | eIO_ReadWrite) == eIO_ReadWrite);
3878
3879 #ifdef NCBI_OS_BSD
3880 /* at least on FreeBSD: shutting down a socket for write (i.e. forcing to
3881 * send a FIN) for a socket that has been already closed by another end
3882 * (e.g. when peer has done writing, so this end has done reading and is
3883 * about to close) seems to cause ECONNRESET in the coming close()...
3884 * see kern/146845 @ http://www.freebsd.org/cgi/query-pr.cgi?pr=146845 */
3885 if (dir == eIO_ReadWrite && how != SOCK_SHUTDOWN_RDWR)
3886 return status;
3887 #endif /*NCBI_OS_BSD*/
3888
3889 #ifdef NCBI_OS_UNIX
3890 if (sock->path[0])
3891 return status;
3892 #endif /*NCBI_OS_UNIX*/
3893
3894 #ifndef NCBI_OS_MSWIN
3895 /* on MS-Win, socket shutdown for write apparently messes up (?!)
3896 * with later reading, especially when reading a lot of data... */
3897
3898 if (s_Initialized > 0 && shutdown(sock->sock, how) != 0) {
3899 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
3900 CORE_LOGF_ERRNO_EXX(16, eLOG_Trace,
3901 error, strerr ? strerr : "",
3902 ("%s[SOCK::Shutdown] "
3903 " Failed shutdown(%s)",
3904 s_ID(sock, _id), dir == eIO_Read ? "R" :
3905 dir == eIO_Write ? "W" : "RW"));
3906 UTIL_ReleaseBuffer(strerr);
3907 status = eIO_Unknown;
3908 }
3909 #endif /*!NCBI_OS_MSWIN*/
3910
3911 return status;
3912 }
3913
3914
3915 enum {
3916 fSOCK_KeepNone = 0,
3917 fSOCK_KeepEvent = 1,
3918 fSOCK_KeepSession = 2,
3919 fSOCK_KeepPending = 4
3920 } ESOCK_Keep;
3921 typedef unsigned int TSOCK_Keep; /* Bitwise-OR of ESOCK_Keep */
3922
3923
3924 /* Close the socket either orderly (abort==0) or abnormally (abort!=0):
3925 * abort == -2 to abort the socket silently;
3926 * abort == -1 to abort the socket internally;
3927 * abort == 1 to abort the socket from SOCK_Abort();
3928 * abort == 2 to re-close the socket when SOCK_CreateOnTop*(sock) failed.
3929 */
s_Close_(SOCK sock,int abort,TSOCK_Keep keep)3930 static EIO_Status s_Close_(SOCK sock, int abort, TSOCK_Keep keep)
3931 {
3932 int/*bool*/ linger = 0/*false*/;
3933 char _id[MAXIDLEN];
3934 EIO_Status status;
3935 int error;
3936
3937 assert(abs(abort) <= 2);
3938 assert(sock->sock != SOCK_INVALID);
3939 if (sock->type == eDatagram) {
3940 assert(!abort);
3941 sock->r_len = 0;
3942 status = eIO_Success;
3943 BUF_Erase(sock->r_buf);
3944 BUF_Erase(sock->w_buf);
3945 keep = fSOCK_KeepNone;
3946 } else if ((abort && abort < 2) || !sock->keep) {
3947 keep = fSOCK_KeepNone;
3948 #if (defined(NCBI_OS_UNIX) && !defined(NCBI_OS_BEOS)) || defined(NCBI_OS_MSWIN)
3949 /* setsockopt() is not implemented for MAC (MIT socket emulation lib)*/
3950 if (sock->w_status != eIO_Closed
3951 # ifdef NCBI_OS_UNIX
3952 && !sock->path[0]
3953 # endif /*NCBI_OS_UNIX*/
3954 ) {
3955 /* set the close()'s linger period be equal to the close timeout */
3956 struct linger lgr;
3957
3958 if (abort) {
3959 lgr.l_linger = 0; /* RFC 793, Abort */
3960 lgr.l_onoff = 1;
3961 } else if (!sock->c_tv_set) {
3962 linger = 1/*true*/;
3963 lgr.l_linger = 120; /* this is standard TCP TTL, 2 minutes */
3964 lgr.l_onoff = 1;
3965 } else if (sock->c_tv.tv_sec | sock->c_tv.tv_usec) {
3966 int seconds = (int)(sock->c_tv.tv_sec +
3967 (sock->c_tv.tv_usec + 500000) / 1000000);
3968 if (seconds) {
3969 linger = 1/*true*/;
3970 lgr.l_linger = seconds;
3971 lgr.l_onoff = 1;
3972 } else
3973 lgr.l_onoff = 0;
3974 } else
3975 lgr.l_onoff = 0;
3976 if (lgr.l_onoff
3977 && setsockopt(sock->sock, SOL_SOCKET, SO_LINGER,
3978 (char*) &lgr, sizeof(lgr)) != 0
3979 && abort >= 0 && sock->connected) {
3980 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
3981 CORE_LOGF_ERRNO_EXX(17, eLOG_Trace,
3982 error, strerr ? strerr : "",
3983 ("%s[SOCK::%s] "
3984 " Failed setsockopt(SO_LINGER)",
3985 s_ID(sock, _id),
3986 abort ? "Abort" : "Close"));
3987 UTIL_ReleaseBuffer(strerr);
3988 }
3989 # ifdef TCP_LINGER2
3990 if (abort ||
3991 (sock->c_tv_set && !(sock->c_tv.tv_sec | sock->c_tv.tv_usec))){
3992 int no = -1;
3993 if (setsockopt(sock->sock, IPPROTO_TCP, TCP_LINGER2,
3994 (char*) &no, sizeof(no)) != 0
3995 && !abort && sock->connected) {
3996 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
3997 CORE_LOGF_ERRNO_EXX(18, eLOG_Trace,
3998 error, strerr ? strerr : "",
3999 ("%s[SOCK::Close] "
4000 " Failed setsockopt(TCP_LINGER2)",
4001 s_ID(sock, _id)));
4002 UTIL_ReleaseBuffer(strerr);
4003 }
4004 }
4005 # endif /*TCP_LINGER2*/
4006 }
4007 #endif /*(NCBI_OS_UNIX && !NCBI_OS_BEOS) || NCBI_OS_MSWIN*/
4008
4009 if (abort) {
4010 sock->eof = 0;
4011 sock->w_len = 0;
4012 sock->pending = 0;
4013 status = eIO_Success;
4014 BUF_Erase(sock->r_buf);
4015 BUF_Erase(sock->w_buf);
4016 sock->r_status = sock->w_status = eIO_Closed;
4017 } else {
4018 /* orderly shutdown in both directions */
4019 status = s_Shutdown(sock, eIO_Close, SOCK_GET_TIMEOUT(sock, c));
4020 assert(sock->r_status == eIO_Closed &&
4021 sock->w_status == eIO_Closed);
4022 assert(sock->w_len == 0);
4023 }
4024 } else if (!(keep & fSOCK_KeepPending)) {
4025 /* flush everything out */
4026 status = s_Shutdown(sock, eIO_Open, SOCK_GET_TIMEOUT(sock, c));
4027 assert(sock->w_len == 0);
4028 } else
4029 status = eIO_Success;
4030
4031 if (!(keep & fSOCK_KeepSession) && sock->sslctx && sock->sslctx->sess){
4032 FSSLDelete ssldelete = s_SSL ? s_SSL->Delete : 0;
4033 if (ssldelete)
4034 ssldelete(sock->sslctx->sess);
4035 sock->sslctx->sess = 0;
4036 sock->sslctx->sock = 0;
4037 }
4038
4039 if (abs(abort) <= 1) {
4040 /* statistics & logging */
4041 if (sock->type != eDatagram) {
4042 sock->n_in += sock->n_read;
4043 sock->n_out += sock->n_written;
4044 }
4045 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
4046 s_DoLog(eLOG_Note, sock, eIO_Close, 0, 0, abort ? "Aborting" : 0);
4047 }
4048
4049 #ifdef NCBI_OS_MSWIN
4050 if (!(keep & fSOCK_KeepEvent))
4051 WSAEventSelect(sock->sock, sock->event/*ignored*/, 0/*de-associate*/);
4052 #endif /*NCBI_OS_MSWIN*/
4053
4054 if (s_Initialized > 0 && !sock->keep
4055 /* set the socket back to blocking mode */
4056 && linger && !s_SetNonblock(sock->sock, 0/*false*/)) {
4057 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4058 assert(!abort);
4059 CORE_LOGF_ERRNO_EXX(19, eLOG_Trace,
4060 error, strerr ? strerr : "",
4061 ("%s[SOCK::Close] "
4062 " Cannot set socket back to blocking mode",
4063 s_ID(sock, _id)));
4064 UTIL_ReleaseBuffer(strerr);
4065 }
4066
4067 if ((abort && abort < 2) || !sock->keep) {
4068 TSOCK_Handle fd = sock->sock;
4069 if (abort)
4070 abort = 1;
4071 #ifdef NCBI_MONKEY
4072 /* Not interception of close(): only to "forget" this socket */
4073 if (g_MONKEY_Close)
4074 g_MONKEY_Close(fd);
4075 #endif /*NCBI_MONKEY*/
4076 for (;;) { /* close persistently - retry if interrupted by a signal */
4077 if (SOCK_CLOSE(fd) == 0)
4078 break;
4079 /* error */
4080 if (s_Initialized <= 0)
4081 break;
4082 error = SOCK_ERRNO;
4083 #ifdef NCBI_OS_MSWIN
4084 if (error == WSANOTINITIALISED) {
4085 s_Initialized = -1/*deinited*/;
4086 break;
4087 }
4088 #endif /*NCBI_OS_MSWIN*/
4089 if (error == SOCK_ENOTCONN/*already closed by now*/
4090 || (!(sock->n_read | sock->n_written)
4091 && (error == SOCK_ENETRESET ||
4092 error == SOCK_ECONNRESET ||
4093 error == SOCK_ECONNABORTED))) {
4094 break;
4095 }
4096 if (abort || error != SOCK_EINTR) {
4097 const char* strerr = SOCK_STRERROR(error);
4098 /* NB: s_ID() won't show fd here since it's INVALID by now */
4099 CORE_LOGF_ERRNO_EXX(21, abort == 1 ? eLOG_Warning : eLOG_Error,
4100 error, strerr ? strerr : "",
4101 ("%s[SOCK::%s] "
4102 " Failed close()",
4103 s_ID(sock, _id),
4104 abort ? "Abort" : "Close"));
4105 UTIL_ReleaseBuffer(strerr);
4106 if (abort > 1 || error != SOCK_EINTR) {
4107 status =
4108 error == SOCK_ETIMEDOUT ? eIO_Timeout : eIO_Unknown;
4109 break;
4110 }
4111 if (abort)
4112 abort = 2;
4113 }
4114 }
4115 sock->sock = SOCK_INVALID;
4116 #ifdef NCBI_OS_MSWIN
4117 WSASetEvent(sock->event); /*signal closure*/
4118 #endif /*NCBI_OS_MSWIN*/
4119 } else
4120 sock->sock = SOCK_INVALID;
4121
4122 #ifdef NCBI_OS_MSWIN
4123 if (!(keep & fSOCK_KeepEvent)) {
4124 WSACloseEvent(sock->event);
4125 sock->event = 0;
4126 }
4127 #endif /*NCBI_OS_MSWIN*/
4128 sock->myport = 0;
4129 return status;
4130 }
4131
4132
s_Close(SOCK sock,int reclose,TSOCK_Keep keep)4133 static EIO_Status s_Close(SOCK sock, int/*bool*/ reclose, TSOCK_Keep keep)
4134 {
4135 EIO_Status status;
4136
4137 assert(!reclose || !keep);
4138 status = s_Close_(sock, reclose << 1, keep);
4139 if (s_ErrHook && status != eIO_Success) {
4140 SSOCK_ErrInfo info;
4141 char addr[40];
4142 memset(&info, 0, sizeof(info));
4143 info.type = eSOCK_ErrIO;
4144 info.sock = sock;
4145 if (sock->port) {
4146 SOCK_ntoa(sock->host, addr, sizeof(addr));
4147 info.host = addr;
4148 info.port = sock->port;
4149 }
4150 #ifdef NCBI_OS_UNIX
4151 else
4152 info.host = sock->path;
4153 #endif /*NCBI_OS_UNIX*/
4154 info.event = eIO_Close;
4155 info.status = status;
4156 s_ErrorCallback(&info);
4157 }
4158
4159 assert(sock->sock == SOCK_INVALID);
4160 return status;
4161 }
4162
4163
4164 /* Connect the (pre-allocated) socket to the specified "host:port"/"file" peer.
4165 * HINT: if "host" is NULL then keep the original host;
4166 * likewise for zero "port".
4167 * NOTE: Client-side stream sockets only.
4168 */
s_Connect_(SOCK sock,const char * host,unsigned short port,const STimeout * timeout)4169 static EIO_Status s_Connect_(SOCK sock,
4170 const char* host,
4171 unsigned short port,
4172 const STimeout* timeout)
4173 {
4174 union {
4175 struct sockaddr sa;
4176 struct sockaddr_in in;
4177 #ifdef NCBI_OS_UNIX
4178 struct sockaddr_un un;
4179 #endif /*NCBI_OS_UNIX*/
4180 } addr;
4181 char _id[MAXIDLEN];
4182 TSOCK_socklen_t addrlen;
4183 SNcbiSSLctx* sslctx;
4184 EIO_Status status;
4185 int error;
4186 int type;
4187 TSOCK_Handle fd;
4188 int n;
4189
4190 assert(sock->sock == SOCK_INVALID);
4191 assert(sock->type == eSocket && sock->side == eSOCK_Client);
4192
4193 sslctx = sock->sslctx;
4194 /* initialize internals */
4195 if (s_InitAPI(sslctx ? 1/*secure*/ : 0/*regular*/) != eIO_Success)
4196 return eIO_NotSupported;
4197
4198 memset(&addr, 0, sizeof(addr));
4199 #ifdef NCBI_OS_UNIX
4200 if (sock->path[0]) {
4201 size_t pathlen = strlen(sock->path);
4202 if (sizeof(addr.un.sun_path) <= pathlen++/*account for '\0'*/) {
4203 CORE_LOGF_X(142, eLOG_Error,
4204 ("%s[SOCK::Connect] "
4205 " Path too long (%lu vs %lu bytes allowed)",
4206 s_ID(sock, _id), (unsigned long) pathlen,
4207 (unsigned long) sizeof(addr.un.sun_path)));
4208 return eIO_InvalidArg;
4209 }
4210 addrlen = (TSOCK_socklen_t) sizeof(addr.un);
4211 # ifdef HAVE_SIN_LEN
4212 addr.un.sun_len = addrlen;
4213 # endif /*HAVE_SIN_LEN*/
4214 addr.un.sun_family = AF_UNIX;
4215 memcpy(addr.un.sun_path, sock->path, pathlen);
4216 assert(!sock->port && !port);
4217 } else
4218 #endif /*NCBI_OS_UNIX*/
4219 {
4220 /* first, set the port to connect to (same port if zero) */
4221 if (port)
4222 sock->port = port;
4223 else
4224 assert(sock->port);
4225 /* get address of the remote host (assume the same host if NULL) */
4226 if (host
4227 && !(sock->host = s_gethostbyname(host, 0, (ESwitch)sock->log))) {
4228 CORE_LOGF_X(22, eLOG_Error,
4229 ("%s[SOCK::Connect] "
4230 " Failed SOCK_gethostbyname(\"%.*s\")",
4231 s_ID(sock, _id), CONN_HOST_LEN, host));
4232 return eIO_Unknown;
4233 }
4234 addrlen = (TSOCK_socklen_t) sizeof(addr.in);
4235 #ifdef HAVE_SIN_LEN
4236 addr.in.sin_len = addrlen;
4237 #endif /*HAVE_SIN_LEN*/
4238 addr.in.sin_family = AF_INET;
4239 addr.in.sin_addr.s_addr = sock->host;
4240 addr.in.sin_port = htons(sock->port);
4241 }
4242
4243 /* create a new socket */
4244 type = SOCK_STREAM;
4245 #ifdef SOCK_NONBLOCK
4246 type |= SOCK_NONBLOCK;
4247 #endif /*SOCK_NONBLOCK*/
4248 #ifdef SOCK_CLOEXEC
4249 if (!sock->crossexec || sslctx)
4250 type |= SOCK_CLOEXEC;
4251 #endif /*SOCK_CLOEXEC*/
4252 if ((fd = socket(addr.sa.sa_family, type, 0)) == SOCK_INVALID) {
4253 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4254 CORE_LOGF_ERRNO_EXX(23, eLOG_Error,
4255 error, strerr ? strerr : "",
4256 ("%s[SOCK::Connect] "
4257 " Cannot create socket",
4258 s_ID(sock, _id)));
4259 UTIL_ReleaseBuffer(strerr);
4260 return eIO_Unknown;
4261 }
4262 sock->sock = fd;
4263
4264 #ifdef NCBI_MONKEY
4265 /* Bind created fd to the sock in Chaos Monkey, this information is
4266 important to keep rules working */
4267 if (g_MONKEY_SockHasSocket)
4268 g_MONKEY_SockHasSocket(sock, fd);
4269 #endif /*NCBI_MONKEY*/
4270
4271 #if defined(NCBI_OS_MSWIN)
4272 assert(!sock->event);
4273 if (!(sock->event = WSACreateEvent())) {
4274 DWORD err = GetLastError();
4275 const char* strerr = s_WinStrerror(err);
4276 CORE_LOGF_ERRNO_EXX(122, eLOG_Error,
4277 err, strerr ? strerr : "",
4278 ("%s[SOCK::Connect] "
4279 " Failed to create IO event",
4280 s_ID(sock, _id)));
4281 UTIL_ReleaseBufferOnHeap(strerr);
4282 s_Close_(sock, -2/*silent abort*/, fSOCK_KeepNone);
4283 return eIO_Unknown;
4284 }
4285 /* NB: WSAEventSelect() sets non-blocking automatically */
4286 if (WSAEventSelect(sock->sock, sock->event, SOCK_EVENTS) != 0) {
4287 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4288 CORE_LOGF_ERRNO_EXX(123, eLOG_Error,
4289 error, strerr ? strerr : "",
4290 ("%s[SOCK::Connect] "
4291 " Failed to bind IO event",
4292 s_ID(sock, _id)));
4293 UTIL_ReleaseBuffer(strerr);
4294 s_Close_(sock, -2/*silent abort*/, fSOCK_KeepNone);
4295 return eIO_Unknown;
4296 }
4297 #elif !defined(SOCK_NONBLOCK)
4298 /* set non-blocking mode */
4299 if (!s_SetNonblock(fd, 1/*true*/)) {
4300 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4301 CORE_LOGF_ERRNO_EXX(24, eLOG_Error,
4302 error, strerr ? strerr : "",
4303 ("%s[SOCK::Connect] "
4304 " Cannot set socket to non-blocking mode",
4305 s_ID(sock, _id)));
4306 UTIL_ReleaseBuffer(strerr);
4307 s_Close_(sock, -2/*silent abort*/, fSOCK_KeepNone);
4308 return eIO_Unknown;
4309 }
4310 #endif
4311
4312 if (sock->port) {
4313 #ifdef SO_KEEPALIVE
4314 if (sock->keepalive && !s_SetKeepAlive(fd, 1/*true*/)) {
4315 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4316 CORE_LOGF_ERRNO_EXX(151, eLOG_Warning,
4317 error, strerr ? strerr : "",
4318 ("%s[SOCK::Connect] "
4319 " Failed setsockopt(KEEPALIVE)",
4320 s_ID(sock, _id)));
4321 UTIL_ReleaseBuffer(strerr);
4322 }
4323 #endif /*SO_KEEPALIVE*/
4324 #ifdef SO_OOBINLINE
4325 if (!s_SetOobInline(fd, 1/*true*/)) {
4326 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4327 CORE_LOGF_ERRNO_EXX(135, eLOG_Warning,
4328 error, strerr ? strerr : "",
4329 ("%s[SOCK::Connect] "
4330 " Failed setsockopt(OOBINLINE)",
4331 s_ID(sock, _id)));
4332 UTIL_ReleaseBuffer(strerr);
4333 }
4334 #endif /*SO_OOBINLINE*/
4335 }
4336
4337 #ifndef SOCK_CLOEXEC
4338 if ((!sock->crossexec || sslctx) && !s_SetCloexec(fd, 1)) {
4339 const char* strerr;
4340 # ifdef NCBI_OS_MSWIN
4341 DWORD err = GetLastError();
4342 strerr = s_WinStrerror(err);
4343 error = err;
4344 # else
4345 error = errno;
4346 strerr = SOCK_STRERROR(error);
4347 # endif /*NCBI_OS_MSWIN*/
4348 CORE_LOGF_ERRNO_EXX(129, eLOG_Warning,
4349 error, strerr ? strerr : "",
4350 ("%s[SOCK::Connect] "
4351 " Cannot set socket close-on-exec mode",
4352 s_ID(sock, _id)));
4353 # ifdef NCBI_OS_MSWIN
4354 UTIL_ReleaseBufferOnHeap(strerr);
4355 # else
4356 UTIL_ReleaseBuffer(strerr);
4357 # endif /*NCBI_OS_MSWIN*/
4358 }
4359 #endif /*!SOCK_CLOEXEC*/
4360
4361 if (sslctx) {
4362 FSSLCreate sslcreate = s_SSL ? s_SSL->Create : 0;
4363 assert(!sslctx->sess);
4364 assert(!sslctx->host || *sslctx->host);
4365 if (sslcreate) {
4366 sslctx->sock = sock;
4367 sslctx->sess = sslcreate(eSOCK_Client, sslctx, &error);
4368 } else
4369 error = 0;
4370 if (!sslctx->sess) {
4371 const char* strerr = s_StrError(sock, error);
4372 CORE_LOGF_ERRNO_EXX(131, eLOG_Error,
4373 error, strerr ? strerr : "",
4374 ("%s[SOCK::Connect] "
4375 " %s to initialize secure session%s%s",
4376 s_ID(sock, _id),
4377 sslcreate ? "Failed" : "Unable",
4378 sslctx->host ? " with " : "",
4379 sslctx->host ? sslctx->host : 0));
4380 UTIL_ReleaseBuffer(strerr);
4381 s_Close_(sock, -2/*silent abort*/, fSOCK_KeepNone);
4382 return eIO_NotSupported;
4383 }
4384 }
4385
4386 /* establish connection to the peer */
4387 sock->eof = 0/*false*/;
4388 sock->r_status = eIO_Success;
4389 sock->w_status = eIO_Success;
4390 sock->pending = 1/*true*/;
4391 sock->connected = 0/*false*/;
4392 #ifdef NCBI_OS_MSWIN
4393 sock->readable = 0/*false*/;
4394 sock->writable = 0/*false*/;
4395 sock->closing = 0/*false*/;
4396 #endif /*NCBI_OS_MSWIN*/
4397 assert(sock->w_len == 0);
4398 for (n = 0; ; n = 1) { /* optionally auto-resume if interrupted */
4399 if (connect(fd, &addr.sa, addrlen) == 0) {
4400 error = 0;
4401 break;
4402 }
4403 error = SOCK_ERRNO;
4404 if (error != SOCK_EINTR || sock->i_on_sig == eOn
4405 || (sock->i_on_sig == eDefault && s_InterruptOnSignal == eOn)) {
4406 break;
4407 }
4408 }
4409
4410 /* statistics & logging */
4411 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
4412 s_DoLog(eLOG_Note, sock, eIO_Open, 0, 0, error ? 0 : "Connected");
4413
4414 if (error) {
4415 if (((n == 0 && error != SOCK_EINPROGRESS) ||
4416 (n != 0 && error != SOCK_EALREADY))
4417 && error != SOCK_EWOULDBLOCK) {
4418 if (error != SOCK_EINTR) {
4419 const char* strerr = SOCK_STRERROR(error);
4420 CORE_LOGF_ERRNO_EXX(25, sock->log != eOff
4421 ? eLOG_Error : eLOG_Trace,
4422 error, strerr ? strerr : "",
4423 ("%s[SOCK::Connect] "
4424 " Failed connect()",
4425 s_ID(sock, _id)));
4426 UTIL_ReleaseBuffer(strerr);
4427 if (error == SOCK_ECONNREFUSED
4428 #ifdef NCBI_OS_UNIX
4429 || (sock->path[0] && error == ENOENT)
4430 #endif /*NCBI_OS_UNIX*/
4431 ) {
4432 status = eIO_Closed;
4433 } else
4434 status = eIO_Unknown;
4435 } else
4436 status = eIO_Interrupt;
4437 s_Close_(sock, -1/*internal abort*/, fSOCK_KeepNone);
4438 return status/*error*/;
4439 }
4440 }
4441
4442 if (!error || !timeout || (timeout->sec | timeout->usec)) {
4443 const char* what;
4444 struct timeval tv;
4445 const struct timeval* x_tv = s_to2tv(timeout, &tv);
4446
4447 status = s_IsConnected_(sock, x_tv, &what, &error, !error);
4448 if (status != eIO_Success) {
4449 char buf[80];
4450 const char* reason;
4451 if (status == eIO_Timeout) {
4452 assert(x_tv/*it is also normalized*/);
4453 sprintf(buf, "%s[%u.%06u]",
4454 IO_StatusStr(status),
4455 (unsigned int) x_tv->tv_sec,
4456 (unsigned int) x_tv->tv_usec);
4457 reason = buf;
4458 } else
4459 reason = IO_StatusStr(status);
4460 {
4461 const char* strerr = s_StrError(sock, error);
4462 CORE_LOGF_ERRNO_EXX(26, sock->log != eOff
4463 ? eLOG_Error : eLOG_Trace,
4464 error, strerr ? strerr : "",
4465 ("%s[SOCK::Connect] "
4466 " Failed %s: %s", s_ID(sock, _id),
4467 what ? what : "pending connect()",
4468 reason));
4469 UTIL_ReleaseBuffer(strerr);
4470 }
4471 s_Close_(sock, -1/*internal abort*/, fSOCK_KeepNone);
4472 return status;
4473 }
4474 }
4475
4476 /* success: do not change any timeouts */
4477 sock->w_len = BUF_Size(sock->w_buf);
4478 return eIO_Success;
4479 }
4480
4481
s_Connect(SOCK sock,const char * host,unsigned short port,const STimeout * timeout)4482 static EIO_Status s_Connect(SOCK sock,
4483 const char* host,
4484 unsigned short port,
4485 const STimeout* timeout)
4486 {
4487 EIO_Status status = s_Connect_(sock, host, port, timeout);
4488 if (s_ErrHook && status != eIO_Success) {
4489 SSOCK_ErrInfo info;
4490 char addr[40];
4491 memset(&info, 0, sizeof(info));
4492 info.type = eSOCK_ErrIO;
4493 info.sock = sock;
4494 if (!host) {
4495 #ifdef NCBI_OS_UNIX
4496 if (sock->path[0]) {
4497 assert(!sock->port && !port);
4498 info.host = sock->path;
4499 } else
4500 #endif /*NCBI_OS_UNIX*/
4501 {
4502 SOCK_ntoa(sock->host, addr, sizeof(addr));
4503 info.host = addr;
4504 }
4505 } else
4506 info.host = host;
4507 info.port = port ? port : sock->port;
4508 info.event = eIO_Open;
4509 info.status = status;
4510 s_ErrorCallback(&info);
4511 }
4512 return status;
4513 }
4514
4515
s_Create(const char * hostpath,unsigned short port,const STimeout * timeout,SOCK * sock,const SSOCK_Init * init,TSOCK_Flags flags)4516 static EIO_Status s_Create(const char* hostpath,
4517 unsigned short port,
4518 const STimeout* timeout,
4519 SOCK* sock,
4520 const SSOCK_Init* init,
4521 TSOCK_Flags flags)
4522 {
4523 size_t size = port ? 0 : strlen(hostpath);
4524 unsigned int x_id = ++s_ID_Counter * 1000;
4525 char _id[MAXIDLEN];
4526 EIO_Status status;
4527 SOCK x_sock;
4528
4529 assert(!*sock);
4530
4531 /* allocate memory for the internal socket structure(s) */
4532 if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock) + size)))
4533 return eIO_Unknown;
4534 if (flags & fSOCK_Secure) {
4535 SNcbiSSLctx* sslctx;
4536 const char* host = init ? init->host : 0;
4537 if (port && !host)
4538 host = hostpath;
4539 if (SOCK_isip(host))
4540 host = 0;
4541 if (!(sslctx = (SNcbiSSLctx*) calloc(1, sizeof(*sslctx)))) {
4542 free(x_sock);
4543 return eIO_Unknown;
4544 }
4545 sslctx->host = host && *host ? strdup(host) : 0;
4546 sslctx->cred = init ? init->cred : 0;
4547 x_sock->sslctx = sslctx;
4548 }
4549 x_sock->sock = SOCK_INVALID;
4550 x_sock->id = x_id;
4551 x_sock->type = eSocket;
4552 x_sock->side = eSOCK_Client;
4553 x_sock->log = flags & (fSOCK_LogDefault | fSOCK_LogOn);
4554 x_sock->keep = flags & fSOCK_KeepOnClose ? 1/*true*/ : 0/*false*/;
4555 x_sock->r_on_w = flags & fSOCK_ReadOnWrite ? eOn : eDefault;
4556 x_sock->i_on_sig = flags & fSOCK_InterruptOnSignal ? eOn : eDefault;
4557 x_sock->crossexec = flags & fSOCK_KeepOnExec ? 1/*true*/ : 0/*false*/;
4558 x_sock->keepalive = flags & fSOCK_KeepAlive ? 1/*true*/ : 0/*false*/;
4559 #ifdef NCBI_OS_UNIX
4560 if (!port)
4561 memcpy(x_sock->path, hostpath, size + 1);
4562 #endif /*NCBI_OS_UNIX*/
4563
4564 /* setup initial data */
4565 size = init ? init->size : 0;
4566 BUF_SetChunkSize(&x_sock->r_buf, SOCK_BUF_CHUNK_SIZE);
4567 if (size
4568 && (BUF_SetChunkSize(&x_sock->w_buf, size) < size
4569 || !BUF_Write(&x_sock->w_buf, init ? init->data : 0, size))) {
4570 CORE_LOGF_ERRNO_X(27, eLOG_Error, errno,
4571 ("%s[SOCK::Create] "
4572 " Cannot store initial data",
4573 s_ID(x_sock, _id)));
4574 SOCK_Destroy(x_sock);
4575 return eIO_Unknown;
4576 }
4577
4578 /* connect */
4579 status = s_Connect(x_sock, hostpath, port, timeout);
4580 if (status != eIO_Success)
4581 SOCK_Destroy(x_sock);
4582 else
4583 *sock = x_sock;
4584 return status;
4585 }
4586
4587
4588 /* Mimic SOCK_CLOSE() */
SOCK_ABORT(TSOCK_Handle x_sock)4589 static void SOCK_ABORT(TSOCK_Handle x_sock)
4590 {
4591 struct SOCK_tag temp;
4592 memset(&temp, 0, sizeof(temp));
4593 temp.side = eSOCK_Server;
4594 temp.type = eSocket;
4595 temp.sock = x_sock;
4596 s_Close_(&temp, -2/*silent abort*/, fSOCK_KeepNone);
4597 }
4598
4599
s_CreateOnTop(const void * handle,size_t handle_size,SOCK * sock,const SSOCK_Init * init,TSOCK_Flags flags)4600 static EIO_Status s_CreateOnTop(const void* handle,
4601 size_t handle_size,
4602 SOCK* sock,
4603 const SSOCK_Init* init,
4604 TSOCK_Flags flags)
4605 {
4606 union {
4607 struct sockaddr sa;
4608 struct sockaddr_in in;
4609 #ifdef NCBI_OS_UNIX
4610 struct sockaddr_un un;
4611 #endif /*NCBI_OS_UNIX*/
4612 } peer;
4613 size_t size;
4614 int error;
4615 EIO_Status status;
4616 TSOCK_socklen_t peerlen;
4617 size_t socklen;
4618 #ifdef NCBI_OS_MSWIN
4619 WSAEVENT event = 0;
4620 #endif /*NCBI_OS_MSWIN*/
4621 BUF w_buf = 0;
4622 unsigned short myport = 0;
4623 char _id[MAXIDLEN];
4624 SOCK x_sock, x_orig = 0;
4625 SNcbiSSLctx* sslctx = 0, *oldctx = 0;
4626 TSOCK_Handle fd, oldfd = SOCK_INVALID;
4627 unsigned int x_id = ++s_ID_Counter * 1000;
4628
4629 assert(!*sock);
4630
4631 if (!handle || (handle_size && handle_size != sizeof(fd))) {
4632 CORE_LOGF_X(47, eLOG_Error,
4633 ("SOCK#%u[?]: [SOCK::CreateOnTop] "
4634 " Invalid handle%s %lu",
4635 x_id,
4636 handle ? " size" : "",
4637 handle ? (unsigned long) handle_size : 0));
4638 assert(0);
4639 return eIO_InvalidArg;
4640 }
4641
4642 if (!handle_size) {
4643 TSOCK_Keep keep = fSOCK_KeepEvent;
4644 x_orig = (SOCK) handle;
4645 if (x_orig->type != eSocket) {
4646 assert(0);
4647 return eIO_InvalidArg;
4648 }
4649 fd = x_orig->sock;
4650 if (s_Initialized <= 0 || fd == SOCK_INVALID)
4651 return eIO_Closed;
4652 if (!x_orig->keep) {
4653 x_orig->keep = 1/*true*/;
4654 oldfd = fd;
4655 }
4656 if (!x_orig->sslctx == !(flags & fSOCK_Secure)) {
4657 keep |= fSOCK_KeepPending;
4658 if (flags & fSOCK_Secure) {
4659 keep |= fSOCK_KeepSession;
4660 oldctx = x_orig->sslctx;
4661 }
4662 }
4663 myport = x_orig->myport;
4664 s_Close(x_orig, 0, keep);
4665 #ifdef NCBI_OS_MSWIN
4666 event = x_orig->event;
4667 x_orig->event = 0;
4668 assert(event);
4669 #endif/*NCBI_OS_MSWIN*/
4670 if (oldfd != SOCK_INVALID)
4671 x_orig->keep = 0/*false*/;
4672 } else
4673 memcpy(&fd, handle, sizeof(fd));
4674
4675 /* initialize internals */
4676 if (s_InitAPI(flags & fSOCK_Secure) != eIO_Success) {
4677 status = eIO_NotSupported;
4678 goto errout;
4679 }
4680
4681 /* get peer's address */
4682 memset(&peer, 0, sizeof(peer));
4683 if (!x_orig) {
4684 peerlen = (TSOCK_socklen_t) sizeof(peer);
4685 #ifdef HAVE_SIN_LEN
4686 peer.sa.sa_len = peerlen;
4687 #endif /*HAVE_SIN_LEN*/
4688 if (getpeername(fd, &peer.sa, &peerlen) != 0) {
4689 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4690 CORE_LOGF_ERRNO_EXX(148, eLOG_Error,
4691 error, strerr ? strerr : "",
4692 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4693 " %s %s handle",
4694 x_id, (unsigned int) fd,
4695 error == SOCK_ENOTCONN
4696 ? "Unconnected" : "Invalid",
4697 x_orig ? "SOCK" : "OS socket"));
4698 UTIL_ReleaseBuffer(strerr);
4699 return eIO_Closed;
4700 }
4701 #ifdef NCBI_OS_UNIX
4702 if (peer.sa.sa_family != AF_INET && peer.sa.sa_family != AF_UNIX)
4703 # if defined(NCBI_OS_BSD) || \
4704 defined(NCBI_OS_DARWIN) || \
4705 defined(NCBI_OS_IRIX)
4706 if (peer.sa.sa_family != AF_UNSPEC/*0*/)
4707 # endif /*NCBI_OS_???*/
4708 #else
4709 if (peer.sa.sa_family != AF_INET)
4710 #endif /*NCBI_OS_UNIX*/
4711 return eIO_NotSupported;
4712 }
4713
4714 #ifdef NCBI_OS_UNIX
4715 if (x_orig && x_orig->path[0])
4716 socklen = strlen(x_orig->path);
4717 else if (!x_orig && (
4718 # if defined(NCBI_OS_BSD) || \
4719 defined(NCBI_OS_DARWIN) || \
4720 defined(NCBI_OS_IRIX)
4721 peer.sa.sa_family == AF_UNSPEC/*0*/ ||
4722 # endif /*NCBI_OS*/
4723 peer.sa.sa_family == AF_UNIX)) {
4724 if (peerlen == sizeof(peer.sa.sa_family) || !peer.un.sun_path[0]) {
4725 peerlen = (TSOCK_socklen_t) sizeof(peer);
4726 memset(&peer, 0, sizeof(peer));
4727 # ifdef HAVE_SIN_LEN
4728 peer.sa.sa_len = peerlen;
4729 # endif /*HAVE_SIN_LEN*/
4730 if (getsockname(fd, &peer.sa, &peerlen) != 0)
4731 return eIO_Closed;
4732 assert(peer.sa.sa_family == AF_UNIX);
4733 if (peerlen == sizeof(peer.sa.sa_family) || !peer.un.sun_path[0]) {
4734 CORE_LOGF_X(48, eLOG_Error,
4735 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4736 " %s UNIX socket handle",
4737 x_id, (unsigned int) fd,
4738 peerlen == sizeof(peer.sa.sa_family)
4739 ? "Unnamed" : "Abstract"));
4740 return eIO_InvalidArg;
4741 }
4742 }
4743 socklen = strnlen(peer.un.sun_path,sizeof(peer.un.sun_path));
4744 assert(socklen);
4745 } else
4746 #endif /*NCBI_OS_UNIX*/
4747 {
4748 socklen = 0;
4749 assert(!x_orig || x_orig->port);
4750 }
4751
4752 #ifdef NCBI_OS_MSWIN
4753 if (!event) {
4754 assert(!x_orig);
4755 if (!(event = WSACreateEvent())) {
4756 DWORD err = GetLastError();
4757 const char* strerr = s_WinStrerror(err);
4758 CORE_LOGF_ERRNO_EXX(31, eLOG_Error,
4759 err, strerr ? strerr : "",
4760 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4761 " Failed to create IO event",
4762 x_id, (unsigned int) fd));
4763 UTIL_ReleaseBufferOnHeap(strerr);
4764 return eIO_Unknown;
4765 }
4766 /* NB: WSAEventSelect() sets non-blocking automatically */
4767 if (WSAEventSelect(fd, event, SOCK_EVENTS) != 0) {
4768 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4769 CORE_LOGF_ERRNO_EXX(32, eLOG_Error,
4770 error, strerr ? strerr : "",
4771 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4772 " Failed to bind IO event",
4773 x_id, (unsigned int) fd));
4774 UTIL_ReleaseBuffer(strerr);
4775 return eIO_Unknown;
4776 }
4777 } else
4778 assert(x_orig);
4779 #else
4780 /* set to non-blocking mode */
4781 if (!x_orig && !s_SetNonblock(fd, 1/*true*/)) {
4782 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4783 CORE_LOGF_ERRNO_EXX(50, eLOG_Error,
4784 error, strerr ? strerr : "",
4785 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4786 " Cannot set socket to non-blocking mode",
4787 x_id, (unsigned int) fd));
4788 UTIL_ReleaseBuffer(strerr);
4789 return eIO_Unknown;
4790 }
4791 #endif /*NCBI_OS_MSWIN*/
4792
4793 status = eIO_Unknown;
4794
4795 /* setup initial data */
4796 size = init ? init->size : 0;
4797 if (size
4798 && (BUF_SetChunkSize(&w_buf, size) < size
4799 || !BUF_Write(&w_buf, init ? init->data : 0, size))) {
4800 CORE_LOGF_ERRNO_X(49, eLOG_Error, errno,
4801 ("SOCK#%u[%u]: [SOCK::CreateOnTop] "
4802 " Cannot store initial data",
4803 x_id, (unsigned int) fd));
4804 goto errout;
4805 }
4806
4807 /* create and fill in a socket handle */
4808 if ((flags & fSOCK_Secure)
4809 && !(sslctx = (SNcbiSSLctx*) calloc(1, sizeof(*sslctx)))) {
4810 goto errout;
4811 }
4812 if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock) + socklen)))
4813 goto errout;
4814 x_sock->sock = fd;
4815 x_sock->id = x_id;
4816 #ifdef NCBI_OS_UNIX
4817 if (socklen) {
4818 strncpy0(x_sock->path,
4819 x_orig ? x_orig->path : peer.un.sun_path, socklen);
4820 } else
4821 #endif /*NCBI_OS_UNIX*/
4822 {
4823 assert(x_orig || peer.sa.sa_family == AF_INET);
4824 x_sock->host = x_orig ? x_orig->host : peer.in.sin_addr.s_addr;
4825 x_sock->port = x_orig ? x_orig->port : ntohs(peer.in.sin_port);
4826 assert(x_sock->port);
4827 }
4828 x_sock->myport = myport;
4829 x_sock->type = eSocket;
4830 x_sock->side = x_orig ? x_orig->side : eSOCK_Server;
4831 x_sock->log = flags & (fSOCK_LogDefault | fSOCK_LogOn);
4832 x_sock->keep = flags & fSOCK_KeepOnClose ? 1/*true*/ : 0/*false*/;
4833 x_sock->r_on_w = flags & fSOCK_ReadOnWrite ? eOn : eDefault;
4834 x_sock->i_on_sig = flags & fSOCK_InterruptOnSignal ? eOn : eDefault;
4835 x_sock->pending = 1/*have to check at the nearest I/O*/;
4836 #ifdef NCBI_OS_MSWIN
4837 x_sock->event = event;
4838 x_sock->writable = 1/*true*/;
4839 #endif /*NCBI_OS_MSWIN*/
4840 x_sock->connected = x_orig ? x_orig->connected : 0/*false*/;
4841 x_sock->crossexec = flags & fSOCK_KeepOnExec ? 1/*true*/ : 0/*false*/;
4842 x_sock->keepalive = flags & fSOCK_KeepAlive ? 1/*true*/ : 0/*false*/;
4843 /* all timeout bits zeroed - infinite */
4844 x_sock->w_buf = w_buf;
4845 if (oldctx && sslctx) {
4846 NCBI_CRED cred;
4847 const char* host;
4848 if (!oldctx->sess && init) {
4849 cred = init->cred;
4850 host = SOCK_isip(init->host) ? 0 : init->host;
4851 } else {
4852 cred = oldctx->cred;
4853 host = oldctx->host;
4854 }
4855 x_sock->sslctx = oldctx;
4856 x_sock->sslctx->sock = x_sock;
4857 x_orig->sslctx = sslctx;
4858 x_orig->sslctx->cred = oldctx->cred;
4859 x_orig->sslctx->host = oldctx->host;
4860 x_sock->sslctx->cred = cred;
4861 x_sock->sslctx->host = host && *host ? strdup(host) : 0;
4862 sslctx = x_sock->sslctx;
4863 } else if (sslctx) {
4864 const char* host;
4865 if (init)
4866 host = SOCK_isip(init->host) ? 0 : init->host;
4867 else
4868 host = 0;
4869 x_sock->sslctx = sslctx;
4870 x_sock->sslctx->sock = x_sock;
4871 x_sock->sslctx->cred = init ? init->cred : 0;
4872 x_sock->sslctx->host = host && *host ? strdup(host) : 0;
4873 }
4874
4875 if (sslctx) {
4876 assert(sslctx == x_sock->sslctx);
4877 if (!sslctx->sess) {
4878 FSSLCreate sslcreate = s_SSL ? s_SSL->Create : 0;
4879 assert(!sslctx->host || *sslctx->host);
4880 if (sslcreate) {
4881 assert(sslctx->sock == x_sock);
4882 sslctx->sess = sslcreate(eSOCK_Client, sslctx, &error);
4883 } else
4884 error = 0;
4885 if (!sslctx->sess) {
4886 const char* strerr = s_StrError(x_sock, error);
4887 CORE_LOGF_ERRNO_EXX(132, eLOG_Error,
4888 error, strerr ? strerr : "",
4889 ("%s[SOCK::CreateOnTop] "
4890 " %s to initialize secure session%s%s",
4891 s_ID(x_sock, _id),
4892 sslcreate ? "Failed" : "Unable",
4893 sslctx->host ? " with " : "",
4894 sslctx->host ? sslctx->host : ""));
4895 UTIL_ReleaseBuffer(strerr);
4896 x_sock->sock = SOCK_INVALID;
4897 #ifdef NCBI_OS_MSWIN
4898 WSAEventSelect(fd, event, 0/*de-associate*/);
4899 WSACloseEvent(event);
4900 #endif /*NCBI_OS_MSWIN*/
4901 SOCK_Destroy(x_sock);
4902 if (oldfd != SOCK_INVALID)
4903 SOCK_ABORT(oldfd);
4904 return eIO_NotSupported;
4905 }
4906 } else {
4907 if (x_sock->log == eOn
4908 || (x_sock->log == eDefault && s_Log == eOn)) {
4909 CORE_LOGF(eLOG_Trace,
4910 ("%sSSL session re-acquired%s%s%s",
4911 s_ID(x_sock, _id),
4912 sslctx->host ? " \"" : "",
4913 sslctx->host ? sslctx->host : "",
4914 &"\""[!sslctx->host]));
4915 }
4916 x_sock->pending = x_orig->pending;
4917 }
4918 }
4919
4920 if (x_orig) {
4921 size_t w_len = BUF_Size(x_orig->w_buf) - x_orig->w_len;
4922 x_sock->r_buf = x_orig->r_buf;
4923 x_orig->r_buf = 0;
4924 x_sock->w_buf = x_orig->w_buf;
4925 x_orig->w_buf = 0;
4926 x_orig->w_len = 0;
4927 BUF_Splice(&x_sock->w_buf, w_buf);
4928 BUF_Read(x_sock->w_buf, 0, w_len);
4929 BUF_Destroy(w_buf);
4930 } else
4931 BUF_SetChunkSize(&x_sock->r_buf, SOCK_BUF_CHUNK_SIZE);
4932 x_sock->w_len = BUF_Size(x_sock->w_buf);
4933
4934 if (!x_orig && x_sock->port) {
4935 #ifdef SO_KEEPALIVE
4936 if (!s_SetKeepAlive(fd, x_sock->keepalive)) {
4937 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4938 CORE_LOGF_ERRNO_EXX(153, eLOG_Warning,
4939 error, strerr ? strerr : "",
4940 ("%s[SOCK::CreateOnTop] "
4941 " Failed setsockopt(KEEPALIVE)",
4942 s_ID(x_sock, _id)));
4943 UTIL_ReleaseBuffer(strerr);
4944 }
4945 #endif /*SO_KEEPALIVE*/
4946 #ifdef SO_OOBINLINE
4947 if (!s_SetOobInline(fd, 1/*true*/)) {
4948 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4949 CORE_LOGF_ERRNO_EXX(138, eLOG_Warning,
4950 error, strerr ? strerr : "",
4951 ("%s[SOCK::CreateOnTop] "
4952 " Failed setsockopt(OOBINLINE)",
4953 s_ID(x_sock, _id)));
4954 UTIL_ReleaseBuffer(strerr);
4955 }
4956 #endif /*SO_OOBINLINE*/
4957 }
4958
4959 if ((!x_orig
4960 || ((!x_orig->crossexec || x_orig->sslctx) !=
4961 (!x_sock->crossexec || sslctx)))
4962 && !s_SetCloexec(fd, !x_sock->crossexec || sslctx)) {
4963 const char* strerr;
4964 #ifdef NCBI_OS_MSWIN
4965 DWORD err = GetLastError();
4966 strerr = s_WinStrerror(err);
4967 error = err;
4968 #else
4969 error = errno;
4970 strerr = SOCK_STRERROR(error);
4971 #endif /*NCBI_OS_MSWIN*/
4972 CORE_LOGF_ERRNO_EXX(124, eLOG_Warning,
4973 error, strerr ? strerr : "",
4974 ("%s[SOCK::CreateOnTop] "
4975 " Cannot modify socket close-on-exec mode",
4976 s_ID(x_sock, _id)));
4977 #ifdef NCBI_OS_MSWIN
4978 UTIL_ReleaseBufferOnHeap(strerr);
4979 #else
4980 UTIL_ReleaseBuffer(strerr);
4981 #endif /*NCBI_OS_MSWIN*/
4982 }
4983
4984 if (!x_orig) {
4985 struct linger lgr;
4986 memset(&lgr, 0, sizeof(lgr));
4987 if (setsockopt(fd, SOL_SOCKET, SO_LINGER,
4988 (char*) &lgr, sizeof(lgr)) != 0) {
4989 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
4990 CORE_LOGF_ERRNO_EXX(43, eLOG_Warning,
4991 error, strerr ? strerr : "",
4992 ("%s[SOCK::CreateOnTop] "
4993 " Failed setsockopt(SO_NOLINGER)",
4994 s_ID(x_sock, _id)));
4995 UTIL_ReleaseBuffer(strerr);
4996 }
4997 }
4998
4999 /* statistics & logging */
5000 if (x_sock->log == eOn || (x_sock->log == eDefault && s_Log == eOn))
5001 s_DoLog(eLOG_Note, x_sock, eIO_Open, 0, 0, "");
5002
5003 /* success */
5004 *sock = x_sock;
5005 return eIO_Success;
5006
5007 errout:
5008 assert(status != eIO_Success);
5009 if (sslctx) {
5010 assert(!oldctx || oldctx != sslctx);
5011 if (sslctx->host)
5012 free((void*) sslctx->host);
5013 free(sslctx);
5014 }
5015 BUF_Destroy(w_buf);
5016 if (x_orig) {
5017 assert(oldfd != SOCK_INVALID);
5018 x_orig->sock = oldfd;
5019 #ifdef NCBI_OS_MSWIN
5020 x_orig->event = event;
5021 #endif /*NCBI_OS_MSWIN*/
5022 s_Close(x_orig, 1/*re-close*/, fSOCK_KeepNone);
5023 }
5024 return status;
5025 }
5026
5027
s_CreateListening(const char * path,unsigned short port,unsigned short backlog,LSOCK * lsock,TSOCK_Flags flags)5028 static EIO_Status s_CreateListening(const char* path,
5029 unsigned short port,
5030 unsigned short backlog,
5031 LSOCK* lsock,
5032 TSOCK_Flags flags)
5033 {
5034 union {
5035 struct sockaddr sa;
5036 struct sockaddr_in in;
5037 #ifdef NCBI_OS_UNIX
5038 struct sockaddr_un un;
5039 #endif /*NCBI_OS_UNIX*/
5040 } addr;
5041 #ifdef NCBI_OS_UNIX
5042 mode_t u;
5043 #endif /*NCBI_OS_UNIX*/
5044 TSOCK_Handle fd;
5045 const char* cp;
5046 int type;
5047 #ifdef NCBI_OS_MSWIN
5048 WSAEVENT event;
5049 #endif /*NCBI_OS_MSWIN*/
5050 int error;
5051 TSOCK_socklen_t addrlen;
5052 LSOCK x_lsock;
5053 char _id[MAXIDLEN];
5054 unsigned int x_id = ++s_ID_Counter;
5055
5056 assert(!*lsock);
5057 assert(!path || *path);
5058
5059 memset(&addr, 0, sizeof(addr));
5060 if (path) {
5061 #ifdef NCBI_OS_UNIX
5062 size_t pathlen = strlen(path);
5063 if (sizeof(addr.un.sun_path) <= pathlen++/*account for end '\0'*/) {
5064 CORE_LOGF_X(144, eLOG_Error,
5065 ("LSOCK#%u[?]@%s: [LSOCK::Create] "
5066 " Path too long (%lu vs %lu bytes allowed)",
5067 x_id, path, (unsigned long) pathlen,
5068 (unsigned long) sizeof(addr.un.sun_path)));
5069 return eIO_InvalidArg;
5070 }
5071 addr.sa.sa_family = AF_UNIX;
5072 #else
5073 return eIO_NotSupported;
5074 #endif /*NCBI_OS_UNIX*/
5075 } else
5076 addr.sa.sa_family = AF_INET;
5077
5078 /* initialize internals */
5079 if (s_InitAPI(flags & fSOCK_Secure) != eIO_Success)
5080 return eIO_NotSupported;
5081
5082 if (flags & fSOCK_Secure) {
5083 /*FIXME: Add secure server support later*/
5084 return eIO_NotSupported;
5085 }
5086
5087 /* create new(listening) socket */
5088 type = SOCK_STREAM;
5089 #ifdef SOCK_NONBLOCK
5090 type |= SOCK_NONBLOCK;
5091 #endif /*SOCK_NONBLOCK*/
5092 #ifdef SOCK_CLOEXEC
5093 if (!(flags & fSOCK_KeepOnExec))
5094 type |= SOCK_CLOEXEC;
5095 #endif /*SOCK_CLOEXEC*/
5096 if ((fd = socket(addr.sa.sa_family, type, 0)) == SOCK_INVALID){
5097 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5098 if (!path) {
5099 if (port)
5100 sprintf(_id, ":%hu", port);
5101 else
5102 strcpy (_id, ":?");
5103 cp = _id;
5104 } else
5105 cp = path;
5106 CORE_LOGF_ERRNO_EXX(34, eLOG_Error,
5107 error, strerr ? strerr : "",
5108 ("LSOCK#%u[?]@%s: [LSOCK::Create] "
5109 " Failed socket()", x_id, cp));
5110 UTIL_ReleaseBuffer(strerr);
5111 return eIO_Unknown;
5112 }
5113
5114
5115 if (!path) {
5116 const char* failed = 0;
5117 #if defined(NCBI_OS_MSWIN) && defined(SO_EXCLUSIVEADDRUSE)
5118 /* The use of this option comes with caveats, but it is better
5119 * to use it rather than to have (or leave) a chance for another
5120 * process (which uses SO_REUSEADDR, maliciously or not) to be able
5121 * to bind to the same port number, and snatch incoming connections.
5122 * Until a connection exists, that originated from the port with this
5123 * option set, the port (even if the listening instance was closed)
5124 * cannot be re-bound (important for service restarts!). See MSDN.
5125 */
5126 BOOL excl = TRUE;
5127 if (setsockopt(fd, SOL_SOCKET, SO_EXCLUSIVEADDRUSE,
5128 (const char*) &excl, sizeof(excl)) != 0) {
5129 failed = "EXCLUSIVEADDRUSE";
5130 }
5131 #elif !defined(NCBI_OS_MSWIN)
5132 /*
5133 * It was confirmed(?) that at least on Solaris 2.5 this precaution:
5134 * 1) makes the address(port) released immediately upon the process
5135 * termination;
5136 * 2) still issues EADDRINUSE error on the attempt to bind() to the
5137 * same address being in-use by a living process (if SOCK_STREAM).
5138 * 3) MS-Win treats SO_REUSEADDR completely differently in (as always)
5139 * their own twisted way: it *allows* to bind() to an already
5140 * listening socket, which is why we jump the hoops above (also,
5141 * note that SO_EXCLUSIVEADDRUSE == ~SO_REUSEADDR on MS-Win).
5142 */
5143 if (!s_SetReuseAddress(fd, 1/*true*/))
5144 failed = "REUSEADDR";
5145 #endif /*NCBI_OS_MSWIN...*/
5146 if (failed) {
5147 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5148 if (port)
5149 sprintf(_id, "%hu", port);
5150 else
5151 strcpy (_id, "?");
5152 CORE_LOGF_ERRNO_EXX(35, eLOG_Error,
5153 error, strerr ? strerr : "",
5154 ("LSOCK#%u[%u]@:%s: [LSOCK::Create] "
5155 " Failed setsockopt(%s)", x_id,
5156 (unsigned int) fd, _id, failed));
5157 UTIL_ReleaseBuffer(strerr);
5158 SOCK_CLOSE(fd);
5159 return eIO_Unknown;
5160 }
5161 }
5162
5163 /* bind */
5164 #ifdef NCBI_OS_UNIX
5165 if (path) {
5166 assert(addr.un.sun_family == AF_UNIX);
5167 addrlen = (TSOCK_socklen_t) sizeof(addr.un);
5168 # ifdef HAVE_SIN_LEN
5169 addr.un.sun_len = addrlen;
5170 # endif /*HAVE_SIN_LEN*/
5171 strcpy(addr.un.sun_path, path);
5172 u = umask(0);
5173 } else
5174 #endif /*NCBI_OS_UNIX*/
5175 {
5176 unsigned int host =
5177 flags & fSOCK_BindLocal ? SOCK_LOOPBACK : htonl(INADDR_ANY);
5178 assert(addr.in.sin_family == AF_INET);
5179 addrlen = sizeof(addr.in);
5180 #ifdef HAVE_SIN_LEN
5181 addr.in.sin_len = addrlen;
5182 #endif /*HAVE_SIN_LEN*/
5183 addr.in.sin_addr.s_addr = host;
5184 addr.in.sin_port = htons(port);
5185 #ifdef NCBI_OS_UNIX
5186 u = 0/*dummy*/;
5187 #endif /*NCBI_OS_UNIX*/
5188 }
5189 error = bind(fd, &addr.sa, addrlen) != 0 ? SOCK_ERRNO : 0;
5190 #ifdef NCBI_OS_UNIX
5191 if (path)
5192 umask(u);
5193 #endif /*NCBI_OS_UNIX*/
5194 if (error) {
5195 const char* strerr = SOCK_STRERROR(error);
5196 if (!path) {
5197 if (!port) {
5198 SOCK_ntoa(addr.in.sin_addr.s_addr, _id, sizeof(_id));
5199 strcat(_id + strlen(_id), ":?");
5200 } else {
5201 SOCK_HostPortToString(addr.in.sin_addr.s_addr, port,
5202 _id, sizeof(_id));
5203 }
5204 cp = _id;
5205 } else
5206 cp = path;
5207 CORE_LOGF_ERRNO_EXX(36, error != SOCK_EADDRINUSE
5208 ? eLOG_Error : eLOG_Trace,
5209 error, strerr ? strerr : "",
5210 ("LSOCK#%u[%u]@%s: [LSOCK::Create] "
5211 " Failed bind()",
5212 x_id, (unsigned int) fd, cp));
5213 UTIL_ReleaseBuffer(strerr);
5214 SOCK_CLOSE(fd);
5215 return error != SOCK_EADDRINUSE ? eIO_Unknown : eIO_Closed;
5216 }
5217 if (path)
5218 #ifdef NCBI_OS_IRIX
5219 (void) fchmod(fd, S_IRWXU | S_IRWXG | S_IRWXO)
5220 #endif /*NCBI_OS_IRIX*/
5221 ;
5222 else if (!port) {
5223 assert(addr.in.sin_family == AF_INET);
5224 error = getsockname(fd, &addr.sa, &addrlen) != 0
5225 ? SOCK_ERRNO : 0;
5226 if (error || addr.sa.sa_family != AF_INET || !addr.in.sin_port) {
5227 const char* strerr = SOCK_STRERROR(error);
5228 CORE_LOGF_ERRNO_EXX(150, eLOG_Error,
5229 error, strerr ? strerr : "",
5230 ("LSOCK#%u[%u]@:?: [LSOCK::Create] "
5231 " Cannot obtain free socket port",
5232 x_id, (unsigned int) fd));
5233 UTIL_ReleaseBuffer(strerr);
5234 SOCK_CLOSE(fd);
5235 return eIO_Closed;
5236 }
5237 port = ntohs(addr.in.sin_port);
5238 }
5239 assert((path && !port) ||
5240 (port && !path));
5241
5242 #if defined(NCBI_OS_MSWIN)
5243 if (!(event = WSACreateEvent())) {
5244 DWORD err = GetLastError();
5245 const char* strerr = s_WinStrerror(err);
5246 assert(!path);
5247 CORE_LOGF_ERRNO_EXX(118, eLOG_Error,
5248 err, strerr ? strerr : "",
5249 ("LSOCK#%u[%u]@:%hu: [LSOCK::Create] "
5250 " Failed to create IO event",
5251 x_id, (unsigned int) fd, port));
5252 UTIL_ReleaseBufferOnHeap(strerr);
5253 SOCK_CLOSE(fd);
5254 return eIO_Unknown;
5255 }
5256 /* NB: WSAEventSelect() sets non-blocking automatically */
5257 if (WSAEventSelect(fd, event, FD_CLOSE/*X*/ | FD_ACCEPT/*A*/) != 0) {
5258 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5259 assert(!path);
5260 CORE_LOGF_ERRNO_EXX(119, eLOG_Error,
5261 error, strerr ? strerr : "",
5262 ("LSOCK#%u[%u]@:%hu: [LSOCK::Create] "
5263 " Failed to bind IO event",
5264 x_id, (unsigned int) fd, port));
5265 UTIL_ReleaseBuffer(strerr);
5266 SOCK_CLOSE(fd);
5267 WSACloseEvent(event);
5268 return eIO_Unknown;
5269 }
5270 #elif !defined(SOCK_NONBLOCK)
5271 /* set non-blocking mode */
5272 if (!s_SetNonblock(fd, 1/*true*/)) {
5273 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5274 if (!path) {
5275 sprintf(_id, ":%hu", port);
5276 cp = _id;
5277 } else
5278 cp = path;
5279 CORE_LOGF_ERRNO_EXX(38, eLOG_Error,
5280 error, strerr ? strerr : "",
5281 ("LSOCK#%u[%u]@%s: [LSOCK::Create] "
5282 " Cannot set socket to non-blocking mode",
5283 x_id, (unsigned int) fd, cp));
5284 UTIL_ReleaseBuffer(strerr);
5285 SOCK_CLOSE(fd);
5286 return eIO_Unknown;
5287 }
5288 #endif
5289
5290 /* listen */
5291 if (listen(fd, backlog) != 0) {
5292 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5293 if (!path) {
5294 sprintf(_id, ":%hu", port);
5295 cp = _id;
5296 } else
5297 cp = path;
5298 CORE_LOGF_ERRNO_EXX(37, eLOG_Error,
5299 error, strerr ? strerr : "",
5300 ("LSOCK#%u[%u]@%s: [LSOCK::Create] "
5301 " Failed listen(%hu)",
5302 x_id, (unsigned int) fd, cp, backlog));
5303 UTIL_ReleaseBuffer(strerr);
5304 SOCK_CLOSE(fd);
5305 #ifdef NCBI_OS_MSWIN
5306 WSACloseEvent(event);
5307 #endif /*NCBI_OS_MSWIN*/
5308 return eIO_Unknown;
5309 }
5310
5311 /* allocate memory for the internal socket structure */
5312 if (!(x_lsock =(LSOCK)calloc(1,sizeof(*x_lsock) + (path?strlen(path):0)))){
5313 SOCK_CLOSE(fd);
5314 #ifdef NCBI_OS_MSWIN
5315 WSACloseEvent(event);
5316 #endif /*NCBI_OS_MSWIN*/
5317 return eIO_Unknown;
5318 }
5319 x_lsock->sock = fd;
5320 x_lsock->id = x_id;
5321 x_lsock->port = port;
5322 x_lsock->type = eListening;
5323 x_lsock->side = eSOCK_Server;
5324 x_lsock->log = flags & (fSOCK_LogDefault | fSOCK_LogOn);
5325 x_lsock->keep = flags & fSOCK_KeepOnClose ? 1/*true*/ : 0/*false*/;
5326 x_lsock->i_on_sig = flags & fSOCK_InterruptOnSignal ? eOn : eDefault;
5327 #if defined(NCBI_OS_UNIX)
5328 if (path)
5329 strcpy(x_lsock->path, path);
5330 #elif defined(NCBI_OS_MSWIN)
5331 x_lsock->event = event;
5332 #endif /*NCBI_OS*/
5333
5334 #ifndef SOCK_CLOEXEC
5335 if (!(flags & fSOCK_KeepOnExec) && !s_SetCloexec(fd, 1/*true*/)) {
5336 const char* strerr;
5337 # ifdef NCBI_OS_MSWIN
5338 DWORD err = GetLastError();
5339 strerr = s_WinStrerror(err);
5340 error = err;
5341 # else
5342 error = errno;
5343 strerr = SOCK_STRERROR(error);
5344 # endif /*NCBI_OS_MSWIN*/
5345 if (!path) {
5346 sprintf(_id, ":%hu", port);
5347 cp = _id;
5348 } else
5349 cp = path;
5350 CORE_LOGF_ERRNO_EXX(110, eLOG_Warning,
5351 error, strerr ? strerr : "",
5352 ("LSOCK#%u[%u]@%s: [LSOCK::Create] "
5353 " Cannot set socket close-on-exec mode",
5354 x_id, (unsigned int) fd, cp));
5355 # ifdef NCBI_OS_MSWIN
5356 UTIL_ReleaseBufferOnHeap(strerr);
5357 # else
5358 UTIL_ReleaseBuffer(strerr);
5359 # endif /*NCBI_OS_MSWIN*/
5360 }
5361 #endif /*!SOCK_CLOEXEC*/
5362
5363 /* statistics & logging */
5364 if (x_lsock->log == eOn || (x_lsock->log == eDefault && s_Log == eOn)){
5365 CORE_LOGF_X(115, eLOG_Note,
5366 ("%sListening", s_ID((SOCK) x_lsock, _id)));
5367 }
5368
5369 *lsock = x_lsock;
5370 return eIO_Success;
5371 }
5372
5373
s_Accept(LSOCK lsock,const STimeout * timeout,SOCK * sock,TSOCK_Flags flags)5374 static EIO_Status s_Accept(LSOCK lsock,
5375 const STimeout* timeout,
5376 SOCK* sock,
5377 TSOCK_Flags flags)
5378 {
5379 union {
5380 struct sockaddr sa;
5381 struct sockaddr_in in;
5382 #ifdef NCBI_OS_UNIX
5383 struct sockaddr_un un;
5384 #endif /*NCBI_OS_UNIX*/
5385 } addr;
5386 TSOCK_Handle fd;
5387 unsigned int x_id;
5388 const char* path;
5389 unsigned int host;
5390 unsigned short port;
5391 #ifdef NCBI_OS_MSWIN
5392 WSAEVENT event;
5393 #endif /*NCBI_OS_MSWIN*/
5394 int error;
5395 SOCK x_sock;
5396 TSOCK_socklen_t addrlen;
5397 char _id[MAXIDLEN];
5398
5399 *sock = 0;
5400
5401 if (!lsock || lsock->sock == SOCK_INVALID) {
5402 CORE_LOGF_X(39, eLOG_Error,
5403 ("%s[LSOCK::Accept] "
5404 " Invalid socket",
5405 s_ID((SOCK) lsock, _id)));
5406 assert(0);
5407 return eIO_Unknown;
5408 }
5409
5410 if (flags & fSOCK_Secure) {
5411 /* FIXME: Add secure support later */
5412 return eIO_NotSupported;
5413 }
5414
5415 {{ /* wait for the connection request to come (up to timeout) */
5416 EIO_Status status;
5417 SSOCK_Poll poll;
5418 struct timeval tv;
5419
5420 poll.sock = (SOCK) lsock;
5421 poll.event = eIO_Read;
5422 poll.revent = eIO_Open;
5423 status = s_Select(1, &poll, s_to2tv(timeout, &tv), 1/*asis*/);
5424 assert(poll.event == eIO_Read);
5425 if (status != eIO_Success)
5426 return status;
5427 if (poll.revent == eIO_Close)
5428 return eIO_Unknown;
5429 assert(poll.revent == eIO_Read);
5430 }}
5431
5432 x_id = (lsock->id * 1000 + ++s_ID_Counter) * 1000;
5433
5434 /* accept next connection */
5435 memset(&addr, 0, sizeof(addr));
5436 #ifdef NCBI_OS_UNIX
5437 if (lsock->path[0]) {
5438 addrlen = (TSOCK_socklen_t) sizeof(addr.un);
5439 # ifdef HAVE_SIN_LEN
5440 addr.un.sun_len = addrlen;
5441 # endif /*HAVE_SIN_LEN*/
5442 assert(!lsock->port);
5443 } else
5444 #endif /*NCBI_OS_UNIX*/
5445 {
5446 addrlen = (TSOCK_socklen_t) sizeof(addr.in);
5447 #ifdef HAVE_SIN_LEN
5448 addr.in.sin_len = addrlen;
5449 #endif /*HAVE_SIN_LEN*/
5450 assert(lsock->port);
5451 #ifdef NCBI_OS_MSWIN
5452 /* accept() [to follow shortly] resets IO event recording */
5453 lsock->readable = 0/*false*/;
5454 #endif /*NCBI_OS_MSWIN*/
5455 }
5456 if ((fd = accept(lsock->sock, &addr.sa, &addrlen)) == SOCK_INVALID) {
5457 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5458 CORE_LOGF_ERRNO_EXX(40, eLOG_Error,
5459 error, strerr ? strerr : "",
5460 ("%s[LSOCK::Accept] "
5461 " Failed accept()",
5462 s_ID((SOCK) lsock, _id)));
5463 UTIL_ReleaseBuffer(strerr);
5464 return eIO_Unknown;
5465 }
5466 lsock->n_accept++;
5467
5468 #ifdef NCBI_OS_UNIX
5469 if (lsock->path[0]) {
5470 assert(addr.un.sun_family == AF_UNIX);
5471 path = lsock->path;
5472 host = 0;
5473 port = 0;
5474 } else
5475 #endif /*NCBI_OS_UNIX*/
5476 {
5477 assert(addr.in.sin_family == AF_INET);
5478 host = addr.in.sin_addr.s_addr;
5479 port = ntohs(addr.in.sin_port);
5480 assert(port);
5481 path = "";
5482 }
5483
5484 #ifdef NCBI_OS_MSWIN
5485 if (!(event = WSACreateEvent())) {
5486 DWORD err = GetLastError();
5487 const char* strerr = s_WinStrerror(err);
5488 CORE_LOGF_ERRNO_EXX(120, eLOG_Error,
5489 err, strerr ? strerr : "",
5490 ("SOCK#%u[%u]@%s: [LSOCK::Accept] "
5491 " Failed to create IO event",
5492 x_id, (unsigned int) fd,
5493 s_CP(host, port, path, _id, sizeof(_id))));
5494 UTIL_ReleaseBufferOnHeap(strerr);
5495 SOCK_ABORT(fd);
5496 return eIO_Unknown;
5497 }
5498 /* NB: WSAEventSelect() sets non-blocking automatically */
5499 if (WSAEventSelect(fd, event, SOCK_EVENTS) != 0) {
5500 int error = SOCK_ERRNO;
5501 const char* strerr = SOCK_STRERROR(error);
5502 CORE_LOGF_ERRNO_EXX(121, eLOG_Error,
5503 error, strerr ? strerr : "",
5504 ("SOCK#%u[%u]@%s: [LSOCK::Accept] "
5505 " Failed to bind IO event",
5506 x_id, (unsigned int) fd,
5507 s_CP(host, port, path, _id, sizeof(_id))));
5508 UTIL_ReleaseBuffer(strerr);
5509 SOCK_ABORT(fd);
5510 WSACloseEvent(event);
5511 return eIO_Unknown;
5512 }
5513 #else
5514 /* man accept(2) notes that non-blocking state may not be inherited */
5515 if (!s_SetNonblock(fd, 1/*true*/)) {
5516 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5517 CORE_LOGF_ERRNO_EXX(41, eLOG_Error,
5518 error, strerr ? strerr : "",
5519 ("SOCK#%u[%u]@%s: [LSOCK::Accept] "
5520 " Cannot set socket to non-blocking mode",
5521 x_id, (unsigned int) fd,
5522 s_CP(host, port, path, _id, sizeof(_id))));
5523 UTIL_ReleaseBuffer(strerr);
5524 SOCK_ABORT(fd);
5525 return eIO_Unknown;
5526 }
5527 #endif /*NCBI_OS_MSWIN*/
5528
5529 /* create new SOCK structure */
5530 addrlen = *path ? (TSOCK_socklen_t) strlen(path) : 0;
5531 if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock) + addrlen))) {
5532 SOCK_ABORT(fd);
5533 #ifdef NCBI_OS_MSWIN
5534 WSACloseEvent(event);
5535 #endif /*NCBI_OS_MSWIN*/
5536 return eIO_Unknown;
5537 }
5538
5539 /* success */
5540 #ifdef NCBI_OS_UNIX
5541 if (!port) {
5542 assert(!lsock->port && path[0]);
5543 strcpy(x_sock->path, path);
5544 } else
5545 #endif /*NCBI_OS_UNIX*/
5546 {
5547 assert(!path[0]);
5548 x_sock->host = host;
5549 x_sock->port = port;
5550 }
5551 x_sock->myport = lsock->port;
5552 x_sock->sock = fd;
5553 x_sock->id = x_id;
5554 x_sock->type = eSocket;
5555 x_sock->side = eSOCK_Server;
5556 x_sock->log = flags & (fSOCK_LogDefault | fSOCK_LogOn);
5557 x_sock->keep = flags & fSOCK_KeepOnClose ? 1/*true*/ : 0/*false*/;
5558 x_sock->r_on_w = flags & fSOCK_ReadOnWrite ? eOn : eDefault;
5559 x_sock->i_on_sig = flags & fSOCK_InterruptOnSignal ? eOn : eDefault;
5560 #ifdef NCBI_OS_MSWIN
5561 x_sock->event = event;
5562 x_sock->writable = 1/*true*/;
5563 #endif /*NCBI_OS_MSWIN*/
5564 x_sock->connected = 1/*true*/;
5565 x_sock->crossexec = flags & fSOCK_KeepOnExec ? 1/*true*/ : 0/*false*/;
5566 x_sock->keepalive = flags & fSOCK_KeepAlive ? 1/*true*/ : 0/*false*/;
5567 /* all timeouts zeroed - infinite */
5568 BUF_SetChunkSize(&x_sock->r_buf, SOCK_BUF_CHUNK_SIZE);
5569 /* w_buf is unused for accepted sockets */
5570
5571 if (port) {
5572 if (s_ReuseAddress == eOn && !s_SetReuseAddress(fd, 1)) {
5573 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5574 CORE_LOGF_ERRNO_EXX(42, eLOG_Warning,
5575 error, strerr ? strerr : "",
5576 ("%s[LSOCK::Accept] "
5577 " Failed setsockopt(REUSEADDR)",
5578 s_ID(*sock, _id)));
5579 UTIL_ReleaseBuffer(strerr);
5580 }
5581
5582 #ifdef SO_KEEPALIVE
5583 if (x_sock->keepalive && !s_SetKeepAlive(fd, 1)) {
5584 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5585 CORE_LOGF_ERRNO_EXX(152, eLOG_Warning,
5586 error, strerr ? strerr : "",
5587 ("%s[LSOCK::Accept] "
5588 " Failed setsockopt(KEEPALIVE)",
5589 s_ID(*sock, _id)));
5590 UTIL_ReleaseBuffer(strerr);
5591 }
5592 #endif /*SO_KEEPALIVE*/
5593 #ifdef SO_OOBINLINE
5594 if (!s_SetOobInline(fd, 1/*true*/)) {
5595 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5596 CORE_LOGF_ERRNO_EXX(137, eLOG_Warning,
5597 error, strerr ? strerr : "",
5598 ("%s[LSOCK::Accept] "
5599 " Failed setsockopt(OOBINLINE)",
5600 s_ID(*sock, _id)));
5601 UTIL_ReleaseBuffer(strerr);
5602 }
5603 #endif /*SO_OOBINLINE*/
5604 }
5605
5606 if (!x_sock->crossexec && !s_SetCloexec(fd, 1/*true*/)) {
5607 const char* strerr;
5608 #ifdef NCBI_OS_MSWIN
5609 DWORD err = GetLastError();
5610 strerr = s_WinStrerror(err);
5611 error = err;
5612 #else
5613 error = errno;
5614 strerr = SOCK_STRERROR(error);
5615 #endif /*NCBI_OS_MSWIN*/
5616 CORE_LOGF_ERRNO_EXX(128, eLOG_Warning,
5617 error, strerr ? strerr : "",
5618 ("%s[LSOCK::Accept] "
5619 " Cannot set socket close-on-exec mode",
5620 s_ID(*sock, _id)));
5621 #ifdef NCBI_OS_MSWIN
5622 UTIL_ReleaseBufferOnHeap(strerr);
5623 #else
5624 UTIL_ReleaseBuffer(strerr);
5625 #endif /*NCBI_OS_MSWIN*/
5626 }
5627
5628 /* statistics & logging */
5629 if (x_sock->log == eOn || (x_sock->log == eDefault && s_Log == eOn))
5630 s_DoLog(eLOG_Note, x_sock, eIO_Open, 0, 0, 0);
5631
5632 *sock = x_sock;
5633 return eIO_Success;
5634 }
5635
5636
s_CloseListening(LSOCK lsock)5637 static EIO_Status s_CloseListening(LSOCK lsock)
5638 {
5639 int error;
5640 EIO_Status status;
5641
5642 assert(lsock->sock != SOCK_INVALID);
5643
5644 #if defined(NCBI_OS_UNIX)
5645 if (!lsock->keep && lsock->path[0]) {
5646 assert(!lsock->port);
5647 remove(lsock->path);
5648 }
5649 #elif defined(NCBI_OS_MSWIN)
5650 assert(lsock->event);
5651 WSAEventSelect(lsock->sock, lsock->event/*ignored*/, 0/*de-associate*/);
5652 #endif /*NCBI_OS*/
5653
5654 /* statistics & logging */
5655 if (lsock->log == eOn || (lsock->log == eDefault && s_Log == eOn)) {
5656 char port[10];
5657 const char* c;
5658 #ifdef NCBI_OS_UNIX
5659 if (lsock->path[0]) {
5660 assert(!lsock->port);
5661 c = lsock->path;
5662 } else
5663 #endif /*NCBI_OS_UNIX*/
5664 {
5665 sprintf(port, ":%hu", lsock->port);
5666 c = port;
5667 }
5668 CORE_LOGF_X(44, eLOG_Note,
5669 ("LSOCK#%u[%u]: %s at %s (%u accept%s total)",
5670 lsock->id, (unsigned int) lsock->sock,
5671 lsock->keep ? "Leaving" : "Closing", c,
5672 lsock->n_accept, lsock->n_accept == 1 ? "" : "s"));
5673 }
5674
5675 status = eIO_Success;
5676 if (!lsock->keep) {
5677 TSOCK_Handle fd = lsock->sock;
5678 for (;;) { /* close persistently - retry if interrupted */
5679 if (SOCK_CLOSE(fd) == 0)
5680 break;
5681
5682 /* error */
5683 if (s_Initialized <= 0)
5684 break;
5685 error = SOCK_ERRNO;
5686 #ifdef NCBI_OS_MSWIN
5687 if (error == WSANOTINITIALISED) {
5688 s_Initialized = -1/*deinited*/;
5689 break;
5690 }
5691 #endif /*NCBI_OS_MSWIN*/
5692 if (error != SOCK_EINTR) {
5693 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
5694 CORE_LOGF_ERRNO_EXX(45, eLOG_Error,
5695 error, strerr ? strerr : "",
5696 ("LSOCK#%u[%u]: [LSOCK::Close] "
5697 " Failed close()",
5698 lsock->id, (unsigned int) fd));
5699 UTIL_ReleaseBuffer(strerr);
5700 status = eIO_Unknown;
5701 break;
5702 }
5703 }
5704 lsock->sock = SOCK_INVALID;
5705 #ifdef NCBI_OS_MSWIN
5706 WSASetEvent(lsock->event); /*signal closure*/
5707 #endif /*NCBI_OS_MSWIN*/
5708 } else
5709 lsock->sock = SOCK_INVALID;
5710
5711 /* cleanup & return */
5712 #ifdef NCBI_OS_MSWIN
5713 WSACloseEvent(lsock->event);
5714 lsock->event = 0;
5715 #endif /*NCBI_OS_MSWIN*/
5716 return status;
5717 }
5718
5719
s_RecvMsg(SOCK sock,void * buf,size_t bufsize,size_t msgsize,size_t * msglen,unsigned int * sender_addr,unsigned short * sender_port)5720 static EIO_Status s_RecvMsg(SOCK sock,
5721 void* buf,
5722 size_t bufsize,
5723 size_t msgsize,
5724 size_t* msglen,
5725 unsigned int* sender_addr,
5726 unsigned short* sender_port)
5727 {
5728 size_t x_msgsize;
5729 char w[1536];
5730 EIO_Status status;
5731 void* x_msg;
5732
5733 BUF_Erase(sock->r_buf);
5734 sock->r_len = 0;
5735
5736 x_msgsize = (msgsize && msgsize < ((1 << 16) - 1))
5737 ? msgsize : ((1 << 16) - 1);
5738
5739 if (!(x_msg = (x_msgsize <= bufsize
5740 ? buf : (x_msgsize <= sizeof(w)
5741 ? w : malloc(x_msgsize))))) {
5742 sock->r_status = eIO_Unknown;
5743 return eIO_Unknown;
5744 }
5745
5746 for (;;) { /* auto-resume if either blocked or interrupted (optional) */
5747 ssize_t x_read;
5748 int error;
5749 struct sockaddr_in sin;
5750 TSOCK_socklen_t sinlen = (TSOCK_socklen_t) sizeof(sin);
5751 memset(&sin, 0, sizeof(sin));
5752 #ifdef HAVE_SIN_LEN
5753 sin.sin_len = sinlen;
5754 #endif
5755 x_read = recvfrom(sock->sock, x_msg,
5756 #ifdef NCBI_OS_MSWIN
5757 /*WINSOCK wants it weird*/ (int)
5758 #endif /*NCBI_OS_MSWIN*/
5759 x_msgsize, 0/*flags*/,
5760 (struct sockaddr*) &sin, &sinlen);
5761 #ifdef NCBI_OS_MSWIN
5762 /* recvfrom() resets IO event recording */
5763 sock->readable = 0/*false*/;
5764 #endif /*NCBI_OS_MSWIN*/
5765
5766 if (x_read >= 0) {
5767 /* got a message */
5768 sock->r_status = eIO_Success;
5769 sock->r_len = (TNCBI_BigCount) x_read;
5770 if ( msglen )
5771 *msglen = (size_t) x_read;
5772 if ( sender_addr )
5773 *sender_addr = sin.sin_addr.s_addr;
5774 if ( sender_port )
5775 *sender_port = ntohs(sin.sin_port);
5776 if ((size_t) x_read > bufsize
5777 && !BUF_Write(&sock->r_buf,
5778 (char*) x_msg + bufsize,
5779 (size_t)x_read - bufsize)) {
5780 CORE_LOGF_X(20, eLOG_Error,
5781 ("%s[DSOCK::RecvMsg] "
5782 " Message truncated: %lu/%lu",
5783 s_ID(sock, w),
5784 (unsigned long) bufsize, (unsigned long) x_read));
5785 status = eIO_Unknown;
5786 } else
5787 status = eIO_Success;
5788 if (bufsize && bufsize < x_msgsize) {
5789 memcpy(buf, x_msg,
5790 (size_t) x_read < bufsize ? (size_t) x_read : bufsize);
5791 }
5792
5793 /* statistics & logging */
5794 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn)){
5795 s_DoLog(eLOG_Note, sock, eIO_Read, x_msg, (size_t) x_read,
5796 &sin);
5797 }
5798
5799 sock->n_read += (TNCBI_BigCount) x_read;
5800 sock->n_in++;
5801 break;
5802 }
5803
5804 error = SOCK_ERRNO;
5805
5806 /* blocked -- retry if unblocked before the timeout expires */
5807 if (error == SOCK_EWOULDBLOCK || error == SOCK_EAGAIN) {
5808 SSOCK_Poll poll;
5809 poll.sock = sock;
5810 poll.event = eIO_Read;
5811 poll.revent = eIO_Open;
5812 status = s_Select(1, &poll, SOCK_GET_TIMEOUT(sock, r), 1/*asis*/);
5813 assert(poll.event == eIO_Read);
5814 if (status != eIO_Success)
5815 break;
5816 if (poll.revent != eIO_Close) {
5817 assert(poll.revent == eIO_Read);
5818 continue/*read again*/;
5819 }
5820 } else if (error == SOCK_EINTR) {
5821 if (sock->i_on_sig == eOn
5822 || (sock->i_on_sig == eDefault && s_InterruptOnSignal == eOn)){
5823 sock->r_status = status = eIO_Interrupt;
5824 break/*interrupt*/;
5825 }
5826 continue;
5827 } else {
5828 const char* strerr = SOCK_STRERROR(error);
5829 CORE_LOGF_ERRNO_EXX(94, eLOG_Trace,
5830 error, strerr ? strerr : "",
5831 ("%s[DSOCK::RecvMsg] "
5832 " Failed recvfrom()",
5833 s_ID(sock, w)));
5834 UTIL_ReleaseBuffer(strerr);
5835 }
5836 /* don't want to handle all possible errors... let them be "unknown" */
5837 sock->r_status = status = eIO_Unknown;
5838 break;
5839 }
5840
5841 if (x_msgsize > bufsize && x_msg != w)
5842 free(x_msg);
5843 return status;
5844 }
5845
5846
s_SendMsg(SOCK sock,const char * host,unsigned short port,const void * data,size_t datalen)5847 static EIO_Status s_SendMsg(SOCK sock,
5848 const char* host,
5849 unsigned short port,
5850 const void* data,
5851 size_t datalen)
5852 {
5853 size_t x_msgsize;
5854 char w[1536];
5855 EIO_Status status;
5856 unsigned short x_port;
5857 unsigned int x_host;
5858 void* x_msg;
5859 struct sockaddr_in sin;
5860
5861 if (datalen) {
5862 status = s_Write_(sock, data, datalen, &x_msgsize, 0/*no OOB*/);
5863 if (status != eIO_Success) {
5864 CORE_LOGF_ERRNO_X(154, eLOG_Error, errno,
5865 ("%s[DSOCK::SendMsg] "
5866 " Failed to finalize message (%lu byte%s)",
5867 s_ID(sock, w), (unsigned long) datalen,
5868 &"s"[datalen == 1]));
5869 return status;
5870 }
5871 assert(x_msgsize == datalen);
5872 assert(sock->w_len == 0);
5873 } else
5874 sock->w_len = 0;
5875 sock->eof = 1/*true - finalized message*/;
5876
5877 x_port = port ? port : sock->port;
5878 if (!host || !*host)
5879 x_host = sock->host;
5880 else if (!(x_host = s_gethostbyname(host, 0, (ESwitch) sock->log))) {
5881 CORE_LOGF_X(88, eLOG_Error,
5882 ("%s[DSOCK::SendMsg] "
5883 " Failed SOCK_gethostbyname(\"%.*s\")",
5884 s_ID(sock, w), CONN_HOST_LEN, host));
5885 return eIO_Unknown;
5886 }
5887
5888 if (!x_host || !x_port) {
5889 SOCK_HostPortToString(x_host, x_port, w, sizeof(w)/2);
5890 CORE_LOGF_X(89, eLOG_Error,
5891 ("%s[DSOCK::SendMsg] "
5892 " Address \"%s\" incomplete, missing %s",
5893 s_ID(sock, w + sizeof(w)/2), w,
5894 x_port ? "host" : &"host:port"[x_host ? 5 : 0]));
5895 return eIO_Unknown;
5896 }
5897
5898 if ((x_msgsize = BUF_Size(sock->w_buf)) != 0) {
5899 if (x_msgsize <= sizeof(w))
5900 x_msg = w;
5901 else if (!(x_msg = malloc(x_msgsize)))
5902 return eIO_Unknown;
5903 verify(BUF_Peek(sock->w_buf, x_msg, x_msgsize) == x_msgsize);
5904 } else
5905 x_msg = 0;
5906
5907 memset(&sin, 0, sizeof(sin));
5908 #ifdef HAVE_SIN_LEN
5909 sin.sin_len = (TSOCK_socklen_t) sizeof(sin);
5910 #endif /*HAVE_SIN_LEN*/
5911 sin.sin_family = AF_INET;
5912 sin.sin_addr.s_addr = x_host;
5913 sin.sin_port = htons(x_port);
5914
5915 for (;;) { /* optionally auto-resume if interrupted */
5916 int error;
5917 ssize_t x_written;
5918
5919 if ((x_written = sendto(sock->sock, x_msg,
5920 #ifdef NCBI_OS_MSWIN
5921 /*WINSOCK wants it weird*/ (int)
5922 #endif /*NCBI_OS_MSWIN*/
5923 x_msgsize, 0/*flags*/,
5924 (struct sockaddr*) &sin, sizeof(sin))) >= 0) {
5925 /* statistics & logging */
5926 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn)){
5927 s_DoLog(eLOG_Note, sock, eIO_Write, x_msg, (size_t) x_written,
5928 &sin);
5929 }
5930
5931 sock->w_len = (TNCBI_BigCount) x_written;
5932 sock->n_written += (TNCBI_BigCount) x_written;
5933 sock->n_out++;
5934 if ((size_t) x_written != x_msgsize) {
5935 sock->w_status = status = eIO_Closed;
5936 if (!host && !port)
5937 w[0] = '\0';
5938 else
5939 SOCK_HostPortToString(x_host, x_port, w, sizeof(w)/2);
5940 CORE_LOGF_X(90, eLOG_Error,
5941 ("%s[DSOCK::SendMsg] "
5942 " Partial datagram sent (%lu out of %lu)%s%s",
5943 s_ID(sock, w + sizeof(w)/2),
5944 (unsigned long) x_written,
5945 (unsigned long) x_msgsize, *w ? " to " : "", w));
5946 break;
5947 }
5948 sock->w_status = status = eIO_Success;
5949 break;
5950 }
5951
5952 #ifdef NCBI_OS_MSWIN
5953 /* special sendto()'s semantics of IO recording reset */
5954 sock->writable = 0/*false*/;
5955 #endif /*NCBI_OS_MSWIN*/
5956
5957 error = SOCK_ERRNO;
5958
5959 /* blocked -- retry if unblocked before the timeout expires */
5960 if (error == SOCK_EWOULDBLOCK || error == SOCK_EAGAIN) {
5961 SSOCK_Poll poll;
5962 poll.sock = sock;
5963 poll.event = eIO_Write;
5964 poll.revent = eIO_Open;
5965 status = s_Select(1, &poll, SOCK_GET_TIMEOUT(sock, w), 1/*asis*/);
5966 assert(poll.event == eIO_Write);
5967 if (status != eIO_Success)
5968 break;
5969 if (poll.revent != eIO_Close) {
5970 assert(poll.revent == eIO_Write);
5971 continue;
5972 }
5973 } else if (error == SOCK_EINTR) {
5974 if (sock->i_on_sig == eOn
5975 || (sock->i_on_sig == eDefault && s_InterruptOnSignal == eOn)){
5976 sock->w_status = status = eIO_Interrupt;
5977 break/*interrupt*/;
5978 }
5979 continue;
5980 } else {
5981 const char* strerr = SOCK_STRERROR(error);
5982 if (!host && !port)
5983 w[0] = '\0';
5984 else
5985 SOCK_HostPortToString(x_host, x_port, w, sizeof(w)/2);
5986 CORE_LOGF_ERRNO_EXX(91, eLOG_Trace,
5987 error, strerr ? strerr : "",
5988 ("%s[DSOCK::SendMsg] "
5989 " Failed sendto(%s)",
5990 s_ID(sock, w + sizeof(w)/2), w));
5991 UTIL_ReleaseBuffer(strerr);
5992 }
5993 /* don't want to handle all possible errors... let them be "unknown" */
5994 sock->w_status = status = eIO_Unknown;
5995 break;
5996 }
5997
5998 if (x_msg && x_msg != w)
5999 free(x_msg);
6000 if (status == eIO_Success)
6001 BUF_Erase(sock->w_buf);
6002 return status;
6003 }
6004
6005
6006
6007 /******************************************************************************
6008 * TRIGGER
6009 */
6010
6011
TRIGGER_Create(TRIGGER * trigger,ESwitch log)6012 extern EIO_Status TRIGGER_Create(TRIGGER* trigger, ESwitch log)
6013 {
6014 unsigned int x_id = ++s_ID_Counter;
6015
6016 *trigger = 0;
6017
6018 /* initialize internals */
6019 if (s_InitAPI(0) != eIO_Success)
6020 return eIO_NotSupported;
6021
6022 #ifndef NCBI_CXX_TOOLKIT
6023
6024 return eIO_NotSupported;
6025
6026 #elif defined(NCBI_OS_UNIX)
6027 {{
6028 int fd[3];
6029
6030 if (pipe(fd) != 0) {
6031 CORE_LOGF_ERRNO_X(28, eLOG_Error, errno,
6032 ("TRIGGER#%u[?]: [TRIGGER::Create] "
6033 " Cannot create pipe", x_id));
6034 return eIO_Closed;
6035 }
6036
6037 # ifdef FD_SETSIZE
6038 if ((fd[2] = fcntl(fd[1], F_DUPFD, FD_SETSIZE)) < 0) {
6039 /* We don't need "out" to be selectable, so move it out
6040 * of the way to spare precious "selectable" fd numbers */
6041 CORE_LOGF_ERRNO_X(143, eLOG_Warning, errno,
6042 ("TRIGGER#%u[?]: [TRIGGER::Create] "
6043 " Failed to dup(%d) to higher fd(%d+))",
6044 x_id, fd[1], FD_SETSIZE));
6045 } else {
6046 close(fd[1]);
6047 fd[1] = fd[2];
6048 }
6049 # endif /*FD_SETSIZE*/
6050
6051 if (!s_SetNonblock(fd[0], 1/*true*/) ||
6052 !s_SetNonblock(fd[1], 1/*true*/)) {
6053 CORE_LOGF_ERRNO_X(29, eLOG_Error, errno,
6054 ("TRIGGER#%u[?]: [TRIGGER::Create] "
6055 " Failed to set non-blocking mode", x_id));
6056 close(fd[0]);
6057 close(fd[1]);
6058 return eIO_Unknown;
6059 }
6060
6061 if (!s_SetCloexec(fd[0], 1/*true*/) ||
6062 !s_SetCloexec(fd[1], 1/*true*/)) {
6063 CORE_LOGF_ERRNO_X(30, eLOG_Warning, errno,
6064 ("TRIGGER#%u[?]: [TRIGGER::Create] "
6065 " Failed to set close-on-exec", x_id));
6066 }
6067
6068 if (!(*trigger = (TRIGGER) calloc(1, sizeof(**trigger)))) {
6069 close(fd[0]);
6070 close(fd[1]);
6071 return eIO_Unknown;
6072 }
6073 (*trigger)->fd = fd[0];
6074 (*trigger)->id = x_id;
6075 (*trigger)->out = fd[1];
6076 (*trigger)->type = eTrigger;
6077 (*trigger)->log = log;
6078 (*trigger)->i_on_sig = eDefault;
6079
6080 /* statistics & logging */
6081 if (log == eOn || (log == eDefault && s_Log == eOn)) {
6082 CORE_LOGF_X(116, eLOG_Note,
6083 ("TRIGGER#%u[%u, %u]: Ready", x_id, fd[0], fd[1]));
6084 }
6085 }}
6086 return eIO_Success;
6087
6088 #elif defined(NCBI_OS_MSWIN)
6089 {{
6090 HANDLE event = WSACreateEvent();
6091 if (!event) {
6092 DWORD err = GetLastError();
6093 const char* strerr = s_WinStrerror(err);
6094 CORE_LOGF_ERRNO_EXX(14, eLOG_Error,
6095 err, strerr ? strerr : "",
6096 ("TRIGGER#%u: [TRIGGER::Create] "
6097 " Cannot create event object", x_id));
6098 UTIL_ReleaseBufferOnHeap(strerr);
6099 return eIO_Closed;
6100 }
6101 if (!(*trigger = (TRIGGER) calloc(1, sizeof(**trigger)))) {
6102 WSACloseEvent(event);
6103 return eIO_Unknown;
6104 }
6105 (*trigger)->fd = event;
6106 (*trigger)->id = x_id;
6107 (*trigger)->type = eTrigger;
6108 (*trigger)->log = log;
6109 (*trigger)->i_on_sig = eDefault;
6110
6111 /* statistics & logging */
6112 if (log == eOn || (log == eDefault && s_Log == eOn)) {
6113 CORE_LOGF_X(116, eLOG_Note,
6114 ("TRIGGER#%u: Ready", x_id));
6115 }
6116 }}
6117 return eIO_Success;
6118
6119 #else
6120 # error "Unsupported platform"
6121 #endif /*NCBI_OS*/
6122 }
6123
6124
6125 /*ARGSUSED*/
TRIGGER_Close(TRIGGER trigger)6126 extern EIO_Status TRIGGER_Close(TRIGGER trigger)
6127 {
6128 #ifndef NCBI_CXX_TOOLKIT
6129
6130 return eIO_NotSupported;
6131
6132 #else
6133
6134 /* statistics & logging */
6135 if (trigger->log == eOn || (trigger->log == eDefault && s_Log == eOn)){
6136 CORE_LOGF_X(117, eLOG_Note,
6137 ("TRIGGER#%u[%u]: Closing", trigger->id, trigger->fd));
6138 }
6139
6140 # if defined(NCBI_OS_UNIX)
6141
6142 /* Prevent SIGPIPE by closing in this order: writing end first */
6143 close(trigger->out);
6144 close(trigger->fd);
6145
6146 # elif defined(NCBI_OS_MSWIN)
6147
6148 WSACloseEvent(trigger->fd);
6149
6150 # endif /*NCBI_OS*/
6151
6152 free(trigger);
6153 return eIO_Success;
6154
6155 #endif /*NCBI_CXX_TOOLKIT*/
6156 }
6157
6158
6159 /*ARGSUSED*/
TRIGGER_Set(TRIGGER trigger)6160 extern EIO_Status TRIGGER_Set(TRIGGER trigger)
6161 {
6162 #ifndef NCBI_CXX_TOOLKIT
6163
6164 return eIO_NotSupported;
6165
6166 #elif defined(NCBI_OS_UNIX)
6167
6168 if (CORE_Once((void**) &trigger->isset.ptr)) {
6169 if (write(trigger->out, "", 1) < 0 && errno != EAGAIN)
6170 return eIO_Unknown;
6171 }
6172
6173 return eIO_Success;
6174
6175 #elif defined(NCBI_OS_MSWIN)
6176
6177 return WSASetEvent(trigger->fd) ? eIO_Success : eIO_Unknown;
6178
6179 #else
6180 # error "Unsupported platform"
6181 #endif /*NCBI_OS*/
6182 }
6183
6184
6185 /*ARGSUSED*/
x_TriggerRead(const TRIGGER trigger,int isset)6186 static EIO_Status x_TriggerRead(const TRIGGER trigger, int/*bool*/ isset)
6187 {
6188 #ifndef NCBI_CXX_TOOLKIT
6189
6190 return eIO_NotSupported;
6191
6192 #elif defined(NCBI_OS_UNIX)
6193
6194 # ifdef PIPE_SIZE
6195 # define MAX_TRIGGER_BUF PIPE_SIZE
6196 # else
6197 # define MAX_TRIGGER_BUF 8192
6198 # endif /*PIPE_SIZE*/
6199
6200 EIO_Status status = eIO_Unknown;
6201 for (;;) {
6202 static char x_buf[MAX_TRIGGER_BUF];
6203 ssize_t x_read = read(trigger->fd, x_buf, sizeof(x_buf));
6204 if (x_read == 0/*EOF?*/)
6205 break;
6206 if (x_read < 0) {
6207 int error;
6208 if (status == eIO_Success)
6209 break;
6210 if ((error = errno) == EAGAIN || error == EWOULDBLOCK)
6211 status = eIO_Timeout;
6212 break;
6213 }
6214 status = eIO_Success;
6215 }
6216 return status;
6217
6218 #elif defined(NCBI_OS_MSWIN)
6219
6220 switch (WaitForSingleObject(trigger->fd, 0)) {
6221 case WAIT_OBJECT_0:
6222 return eIO_Success;
6223 case WAIT_TIMEOUT:
6224 return eIO_Timeout;
6225 default:
6226 break;
6227 }
6228 return eIO_Unknown;
6229
6230 #else
6231 # error "Unsupported platform"
6232 #endif /*NCBI_OS*/
6233 }
6234
6235
TRIGGER_IsSet(TRIGGER trigger)6236 extern EIO_Status TRIGGER_IsSet(TRIGGER trigger)
6237 {
6238 #ifndef NCBI_CXX_TOOLKIT
6239
6240 return eIO_NotSupported;
6241
6242 #else
6243 EIO_Status status = x_TriggerRead(trigger, 1/*IsSet*/);
6244
6245 # ifdef NCBI_OS_UNIX
6246
6247 if (status == eIO_Success)
6248 trigger->isset.ptr = (void*) 1/*true*/;
6249 else if (status != eIO_Timeout)
6250 return status;
6251 return trigger->isset.ptr ? eIO_Success : eIO_Closed;
6252
6253 # else
6254
6255 return status == eIO_Timeout ? eIO_Closed : status;
6256
6257 # endif /*NCBI_OS_UNIX*/
6258
6259 #endif /*NCBI_CXX_TOOLKIT*/
6260 }
6261
6262
TRIGGER_Reset(TRIGGER trigger)6263 extern EIO_Status TRIGGER_Reset(TRIGGER trigger)
6264 {
6265 EIO_Status status = x_TriggerRead(trigger, 0/*Reset*/);
6266
6267 #if defined(NCBI_OS_UNIX)
6268
6269 trigger->isset.ptr = (void*) 0/*false*/;
6270
6271 #elif defined(NCBI_OS_MSWIN)
6272
6273 if (!WSAResetEvent(trigger->fd))
6274 return eIO_Unknown;
6275
6276 #endif /*NCBI_OS*/
6277
6278 return status == eIO_Timeout ? eIO_Success : status;
6279 }
6280
6281
6282
6283 /******************************************************************************
6284 * LISTENING SOCKET
6285 */
6286
6287
LSOCK_Create(unsigned short port,unsigned short backlog,LSOCK * lsock)6288 extern EIO_Status LSOCK_Create(unsigned short port,
6289 unsigned short backlog,
6290 LSOCK* lsock)
6291 {
6292 *lsock = 0;
6293 return s_CreateListening(0, port, backlog, lsock, fSOCK_LogDefault);
6294 }
6295
6296
LSOCK_CreateEx(unsigned short port,unsigned short backlog,LSOCK * lsock,TSOCK_Flags flags)6297 extern EIO_Status LSOCK_CreateEx(unsigned short port,
6298 unsigned short backlog,
6299 LSOCK* lsock,
6300 TSOCK_Flags flags)
6301 {
6302 *lsock = 0;
6303 return s_CreateListening(0, port, backlog, lsock, flags);
6304 }
6305
6306
LSOCK_CreateUNIX(const char * path,unsigned short backlog,LSOCK * lsock,TSOCK_Flags flags)6307 extern EIO_Status LSOCK_CreateUNIX(const char* path,
6308 unsigned short backlog,
6309 LSOCK* lsock,
6310 TSOCK_Flags flags)
6311 {
6312 *lsock = 0;
6313 if (!path || !*path)
6314 return eIO_InvalidArg;
6315 return s_CreateListening(path, 0, backlog, lsock, flags);
6316 }
6317
6318
LSOCK_Accept(LSOCK lsock,const STimeout * timeout,SOCK * sock)6319 extern EIO_Status LSOCK_Accept(LSOCK lsock,
6320 const STimeout* timeout,
6321 SOCK* sock)
6322 {
6323 return s_Accept(lsock, timeout, sock, fSOCK_LogDefault);
6324 }
6325
6326
LSOCK_AcceptEx(LSOCK lsock,const STimeout * timeout,SOCK * sock,TSOCK_Flags flags)6327 extern EIO_Status LSOCK_AcceptEx(LSOCK lsock,
6328 const STimeout* timeout,
6329 SOCK* sock,
6330 TSOCK_Flags flags)
6331 {
6332 return s_Accept(lsock, timeout, sock, flags);
6333 }
6334
6335
LSOCK_Close(LSOCK lsock)6336 extern EIO_Status LSOCK_Close(LSOCK lsock)
6337 {
6338 EIO_Status status;
6339
6340 if (lsock) {
6341 status = (lsock->sock != SOCK_INVALID
6342 ? s_CloseListening(lsock)
6343 : eIO_Closed);
6344 free(lsock);
6345 } else
6346 status = eIO_InvalidArg;
6347 return status;
6348 }
6349
6350
LSOCK_GetOSHandleEx(LSOCK lsock,void * handle,size_t handle_size,EOwnership ownership)6351 extern EIO_Status LSOCK_GetOSHandleEx(LSOCK lsock,
6352 void* handle,
6353 size_t handle_size,
6354 EOwnership ownership)
6355 {
6356 TSOCK_Handle fd;
6357 EIO_Status status;
6358
6359 if (!handle || handle_size != sizeof(lsock->sock)) {
6360 CORE_LOGF_X(46, eLOG_Error,
6361 ("LSOCK#%u[%u]: [LSOCK::GetOSHandle] "
6362 " Invalid handle%s %lu",
6363 lsock->id, (unsigned int) lsock->sock,
6364 handle ? " size" : "",
6365 handle ? (unsigned long) handle_size : 0));
6366 assert(0);
6367 return eIO_InvalidArg;
6368 }
6369 if (!lsock) {
6370 fd = SOCK_INVALID;
6371 memcpy(handle, &fd, handle_size);
6372 return eIO_InvalidArg;
6373 }
6374 fd = lsock->sock;
6375 memcpy(handle, &fd, handle_size);
6376 if (s_Initialized <= 0 || fd == SOCK_INVALID)
6377 status = eIO_Closed;
6378 else if (ownership != eTakeOwnership)
6379 status = eIO_Success;
6380 else {
6381 lsock->keep = 1/*true*/;
6382 status = s_CloseListening(lsock);
6383 assert(lsock->sock == SOCK_INVALID);
6384 }
6385 return status;
6386 }
6387
6388
LSOCK_GetOSHandle(LSOCK lsock,void * handle,size_t handle_size)6389 extern EIO_Status LSOCK_GetOSHandle(LSOCK lsock,
6390 void* handle,
6391 size_t handle_size)
6392 {
6393 return LSOCK_GetOSHandleEx(lsock, handle, handle_size, eNoOwnership);
6394 }
6395
6396
LSOCK_GetPort(LSOCK lsock,ENH_ByteOrder byte_order)6397 extern unsigned short LSOCK_GetPort(LSOCK lsock,
6398 ENH_ByteOrder byte_order)
6399 {
6400 unsigned short port;
6401 port = lsock && lsock->sock != SOCK_INVALID ? lsock->port : 0;
6402 return byte_order == eNH_HostByteOrder ? port : htons(port);
6403 }
6404
6405
6406
6407 /******************************************************************************
6408 * SOCKET
6409 */
6410
6411
SOCK_CreateInternal(const char * host,unsigned short port,const STimeout * timeout,SOCK * sock,const SSOCK_Init * init,TSOCK_Flags flags)6412 EIO_Status SOCK_CreateInternal(const char* host,
6413 unsigned short port,
6414 const STimeout* timeout,
6415 SOCK* sock,
6416 const SSOCK_Init* init,
6417 TSOCK_Flags flags)
6418 {
6419 EIO_Status status;
6420 *sock = 0;
6421 if (!host || !port)
6422 return eIO_InvalidArg;
6423 status = s_Create(host, port, timeout, sock, init, flags);
6424 assert(!*sock == !(status == eIO_Success));
6425 return status;
6426 }
6427
6428
SOCK_CreateEx(const char * host,unsigned short port,const STimeout * timeout,SOCK * sock,const void * data,size_t size,TSOCK_Flags flags)6429 extern EIO_Status SOCK_CreateEx(const char* host,
6430 unsigned short port,
6431 const STimeout* timeout,
6432 SOCK* sock,
6433 const void* data,
6434 size_t size,
6435 TSOCK_Flags flags)
6436 {
6437 SSOCK_Init init;
6438 memset(&init, 0, sizeof(init));
6439 init.data = data;
6440 init.size = size;
6441 return SOCK_CreateInternal(host, port, timeout, sock, &init, flags);
6442 }
6443
6444
SOCK_Create(const char * host,unsigned short port,const STimeout * timeout,SOCK * sock)6445 extern EIO_Status SOCK_Create(const char* host,
6446 unsigned short port,
6447 const STimeout* timeout,
6448 SOCK* sock)
6449 {
6450 return SOCK_CreateInternal(host, port, timeout, sock, 0, fSOCK_LogDefault);
6451 }
6452
6453
SOCK_CreateUNIX(const char * path,const STimeout * timeout,SOCK * sock,const void * data,size_t size,TSOCK_Flags flags)6454 extern EIO_Status SOCK_CreateUNIX(const char* path,
6455 const STimeout* timeout,
6456 SOCK* sock,
6457 const void* data,
6458 size_t size,
6459 TSOCK_Flags flags)
6460 {
6461 EIO_Status status;
6462 *sock = 0;
6463 if (!path || !*path)
6464 return eIO_InvalidArg;
6465 #ifndef NCBI_OS_UNIX
6466 status = eIO_NotSupported;
6467 #else
6468 {{
6469 SSOCK_Init init;
6470 memset(&init, 0, sizeof(init));
6471 init.data = data;
6472 init.size = size;
6473 status = s_Create(path, 0, timeout, sock, &init, flags);
6474 assert(!*sock == !(status == eIO_Success));
6475 }}
6476 #endif /*!NCBI_OS_UNIX*/
6477 return status;
6478 }
6479
6480
SOCK_CreateOnTopInternal(const void * handle,size_t handle_size,SOCK * sock,const SSOCK_Init * init,TSOCK_Flags flags)6481 EIO_Status SOCK_CreateOnTopInternal(const void* handle,
6482 size_t handle_size,
6483 SOCK* sock,
6484 const SSOCK_Init* init,
6485 TSOCK_Flags flags)
6486 {
6487 EIO_Status status;
6488 *sock = 0;
6489 status = s_CreateOnTop(handle, handle_size, sock, init, flags);
6490 assert(!*sock == !(status == eIO_Success));
6491 return status;
6492 }
6493
6494
SOCK_CreateOnTopEx(const void * handle,size_t handle_size,SOCK * sock,const void * data,size_t size,TSOCK_Flags flags)6495 extern EIO_Status SOCK_CreateOnTopEx(const void* handle,
6496 size_t handle_size,
6497 SOCK* sock,
6498 const void* data,
6499 size_t size,
6500 TSOCK_Flags flags)
6501 {
6502 SSOCK_Init init;
6503 memset(&init, 0, sizeof(init));
6504 init.data = data;
6505 init.size = size;
6506 return SOCK_CreateOnTopInternal(handle, handle_size, sock,
6507 &init, flags);
6508 }
6509
6510
SOCK_CreateOnTop(const void * handle,size_t handle_size,SOCK * sock)6511 extern EIO_Status SOCK_CreateOnTop(const void* handle,
6512 size_t handle_size,
6513 SOCK* sock)
6514 {
6515 return SOCK_CreateOnTopInternal(handle, handle_size, sock,
6516 0, fSOCK_LogDefault);
6517 }
6518
6519
SOCK_Reconnect(SOCK sock,const char * host,unsigned short port,const STimeout * timeout)6520 extern EIO_Status SOCK_Reconnect(SOCK sock,
6521 const char* host,
6522 unsigned short port,
6523 const STimeout* timeout)
6524 {
6525 char _id[MAXIDLEN];
6526
6527 if (sock->type == eDatagram) {
6528 CORE_LOGF_X(52, eLOG_Error,
6529 ("%s[SOCK::Reconnect] "
6530 " Datagram socket",
6531 s_ID(sock, _id)));
6532 assert(0);
6533 return eIO_InvalidArg;
6534 }
6535
6536 #ifdef NCBI_OS_UNIX
6537 if (sock->path[0] && (host || port)) {
6538 CORE_LOGF_X(53, eLOG_Error,
6539 ("%s[SOCK::Reconnect] "
6540 " Unable to reconnect UNIX socket as INET at \"%s:%hu\"",
6541 s_ID(sock, _id), host ? host : "", port));
6542 assert(0);
6543 return eIO_InvalidArg;
6544 }
6545 #endif /*NCBI_OS_UNIX*/
6546
6547 /* special treatment for server-side socket */
6548 if (sock->side == eSOCK_Server) {
6549 if (!host || !port) {
6550 CORE_LOGF_X(51, eLOG_Error,
6551 ("%s[SOCK::Reconnect] "
6552 " Attempt to reconnect server-side socket as"
6553 " client one to its peer address",
6554 s_ID(sock, _id)));
6555 return eIO_InvalidArg;
6556 }
6557 }
6558
6559 /* close the socket if necessary */
6560 if (sock->sock != SOCK_INVALID) {
6561 s_Close(sock, 0, fSOCK_KeepNone);
6562 /* likely NOOP */
6563 BUF_Erase(sock->r_buf);
6564 BUF_Erase(sock->w_buf);
6565 }
6566
6567 /* connect */
6568 sock->id++;
6569 sock->side = eSOCK_Client;
6570 sock->n_read = 0;
6571 sock->n_written = 0;
6572 if (host && sock->sslctx) {
6573 if (sock->sslctx->host)
6574 free((void*) sock->sslctx->host);
6575 sock->sslctx->host = *host && !SOCK_isip(host) ? strdup(host) : 0;
6576 }
6577 return s_Connect(sock, host, port, timeout);
6578 }
6579
6580
SOCK_Shutdown(SOCK sock,EIO_Event dir)6581 extern EIO_Status SOCK_Shutdown(SOCK sock,
6582 EIO_Event dir)
6583 {
6584 char _id[MAXIDLEN];
6585 EIO_Status status;
6586
6587 if (sock->sock == SOCK_INVALID) {
6588 CORE_LOGF_X(54, eLOG_Error,
6589 ("%s[SOCK::Shutdown] "
6590 " Invalid socket",
6591 s_ID(sock, _id)));
6592 return eIO_Closed;
6593 }
6594 if (sock->type == eDatagram) {
6595 CORE_LOGF_X(55, eLOG_Error,
6596 ("%s[SOCK::Shutdown] "
6597 " Datagram socket",
6598 s_ID(sock, _id)));
6599 assert(0);
6600 return eIO_InvalidArg;
6601 }
6602 if (!dir || (EIO_Event)(dir | eIO_ReadWrite) != eIO_ReadWrite) {
6603 CORE_LOGF_X(15, eLOG_Error,
6604 ("%s[SOCK::Shutdown] "
6605 " Invalid direction #%u",
6606 s_ID(sock, _id), (unsigned int) dir));
6607 return eIO_InvalidArg;
6608 }
6609
6610 status = s_Shutdown(sock, dir, SOCK_GET_TIMEOUT(sock, c));
6611 if (s_ErrHook && status != eIO_Success) {
6612 SSOCK_ErrInfo info;
6613 char addr[40];
6614 memset(&info, 0, sizeof(info));
6615 info.type = eSOCK_ErrIO;
6616 info.sock = sock;
6617 if (sock->port) {
6618 SOCK_ntoa(sock->host, addr, sizeof(addr));
6619 info.host = addr;
6620 info.port = sock->port;
6621 }
6622 #ifdef NCBI_OS_UNIX
6623 else
6624 info.host = sock->path;
6625 #endif /*NCBI_OS_UNIX*/
6626 info.event = eIO_Close;
6627 info.status = status;
6628 s_ErrorCallback(&info);
6629 }
6630 return status;
6631 }
6632
6633
6634 /* NB: aka SOCK_Destroy() */
SOCK_Close(SOCK sock)6635 extern EIO_Status SOCK_Close(SOCK sock)
6636 {
6637 return SOCK_CloseEx(sock, 1/*destroy*/);
6638 }
6639
6640
SOCK_CloseEx(SOCK sock,int destroy)6641 extern EIO_Status SOCK_CloseEx(SOCK sock, int/*bool*/ destroy)
6642 {
6643 EIO_Status status;
6644 if (!sock)
6645 return eIO_InvalidArg;
6646 if (sock->sock == SOCK_INVALID)
6647 status = eIO_Closed;
6648 else if (s_Initialized > 0)
6649 status = s_Close(sock, 0, fSOCK_KeepNone);
6650 else {
6651 if (sock->sslctx)
6652 sock->sslctx->sess = 0; /*NB: session may leak out, if deinited*/
6653 sock->sock = SOCK_INVALID;
6654 status = eIO_Success;
6655 }
6656 /* likely NOOP */
6657 BUF_Erase(sock->r_buf);
6658 BUF_Erase(sock->w_buf);
6659 if (destroy) {
6660 if (sock->sslctx) {
6661 if (sock->sslctx->host)
6662 free((void*) sock->sslctx->host);
6663 assert(!sock->sslctx->sess);
6664 free(sock->sslctx);
6665 }
6666 BUF_Destroy(sock->r_buf);
6667 BUF_Destroy(sock->w_buf);
6668 free(sock);
6669 }
6670 return status;
6671 }
6672
6673
SOCK_CloseOSHandle(const void * handle,size_t handle_size)6674 extern EIO_Status SOCK_CloseOSHandle(const void* handle, size_t handle_size)
6675 {
6676 EIO_Status status;
6677 struct linger lgr;
6678 TSOCK_Handle fd;
6679
6680 if (!handle || handle_size != sizeof(fd))
6681 return eIO_InvalidArg;
6682
6683 memcpy(&fd, handle, sizeof(fd));
6684 if (fd == SOCK_INVALID)
6685 return eIO_Closed;
6686
6687 /* drop all possible hold-ups w/o checks */
6688 lgr.l_linger = 0; /* RFC 793, Abort */
6689 lgr.l_onoff = 1;
6690 setsockopt(fd, SOL_SOCKET, SO_LINGER, (char*) &lgr, sizeof(lgr));
6691 #ifdef TCP_LINGER2
6692 {{
6693 int no = -1;
6694 setsockopt(fd, IPPROTO_TCP, TCP_LINGER2, (char*) &no, sizeof(no));
6695 }}
6696 #endif /*TCP_LINGER2*/
6697
6698 status = eIO_Success;
6699 for (;;) { /* close persistently - retry if interrupted by a signal */
6700 int error;
6701
6702 if (SOCK_CLOSE(fd) == 0)
6703 break;
6704
6705 /* error */
6706 if (s_Initialized <= 0)
6707 break;
6708 error = SOCK_ERRNO;
6709 #ifdef NCBI_OS_MSWIN
6710 if (error == WSANOTINITIALISED) {
6711 s_Initialized = -1/*deinited*/;
6712 break;
6713 }
6714 #endif /*NCBI_OS_MSWIN*/
6715 if (error == SOCK_ENOTCONN ||
6716 error == SOCK_ENETRESET ||
6717 error == SOCK_ECONNRESET ||
6718 error == SOCK_ECONNABORTED) {
6719 status = eIO_Closed;
6720 break;
6721 }
6722 if (error != SOCK_EINTR) {
6723 status = error == SOCK_ETIMEDOUT ? eIO_Timeout : eIO_Unknown;
6724 break;
6725 }
6726 /* Maybe in an Ex version of this call someday...
6727 if (s_InterruptOnSignal == eOn) {
6728 status = eIO_Interrupt;
6729 break;
6730 }
6731 */
6732 }
6733 return status;
6734 }
6735
6736
SOCK_Wait(SOCK sock,EIO_Event event,const STimeout * timeout)6737 extern EIO_Status SOCK_Wait(SOCK sock,
6738 EIO_Event event,
6739 const STimeout* timeout)
6740 {
6741 char _id[MAXIDLEN];
6742 EIO_Status status;
6743
6744 if (timeout == kDefaultTimeout) {
6745 assert(0);
6746 return eIO_InvalidArg;
6747 }
6748 if (sock->sock == SOCK_INVALID) {
6749 CORE_LOGF_X(56, eLOG_Error,
6750 ("%s[SOCK::Wait] "
6751 " Invalid socket",
6752 s_ID(sock, _id)));
6753 return eIO_Unknown;
6754 }
6755
6756 /* check against already shutdown socket there */
6757 switch (event) {
6758 case eIO_Open:
6759 if (sock->type == eDatagram)
6760 return eIO_Success/*always connected*/;
6761 if (!sock->connected || sock->pending) {
6762 struct timeval tv;
6763 return s_WaitConnected(sock, s_to2tv(timeout, &tv));
6764 }
6765 if (sock->r_status == eIO_Success && sock->w_status == eIO_Success)
6766 return sock->eof ? eIO_Unknown : eIO_Success;
6767 if (sock->r_status == eIO_Closed && sock->w_status == eIO_Closed)
6768 return eIO_Closed;
6769 return eIO_Unknown;
6770
6771 case eIO_Read:
6772 if (BUF_Size(sock->r_buf) != 0)
6773 return eIO_Success;
6774 if (sock->type == eDatagram)
6775 return eIO_Closed;
6776 if (sock->r_status == eIO_Closed) {
6777 CORE_LOGF_X(57, eLOG_Warning,
6778 ("%s[SOCK::Wait(R)] "
6779 " Socket already %s",
6780 s_ID(sock, _id), sock->eof ? "closed" : "shut down"));
6781 return eIO_Closed;
6782 }
6783 if (sock->eof)
6784 return eIO_Closed;
6785 break;
6786
6787 case eIO_Write:
6788 if (sock->type == eDatagram)
6789 return eIO_Success;
6790 if (sock->w_status == eIO_Closed) {
6791 CORE_LOGF_X(58, eLOG_Warning,
6792 ("%s[SOCK::Wait(W)] "
6793 " Socket already shut down",
6794 s_ID(sock, _id)));
6795 return eIO_Closed;
6796 }
6797 break;
6798
6799 case eIO_ReadWrite:
6800 if (sock->type == eDatagram || BUF_Size(sock->r_buf) != 0)
6801 return eIO_Success;
6802 if ((sock->r_status == eIO_Closed || sock->eof) &&
6803 (sock->w_status == eIO_Closed)) {
6804 if (sock->r_status == eIO_Closed) {
6805 CORE_LOGF_X(59, eLOG_Warning,
6806 ("%s[SOCK::Wait(RW)] "
6807 " Socket already shut down",
6808 s_ID(sock, _id)));
6809 }
6810 return eIO_Closed;
6811 }
6812 if (sock->r_status == eIO_Closed || sock->eof) {
6813 if (sock->r_status == eIO_Closed) {
6814 CORE_LOGF_X(60, eLOG_Warning,
6815 ("%s[SOCK::Wait(RW)] "
6816 " Socket already %s",
6817 s_ID(sock, _id), sock->eof
6818 ? "closed" : "shut down for reading"));
6819 }
6820 event = eIO_Write;
6821 break;
6822 }
6823 if (sock->w_status == eIO_Closed) {
6824 CORE_LOGF_X(61, eLOG_Warning,
6825 ("%s[SOCK::Wait(RW)] "
6826 " Socket already shut down for writing",
6827 s_ID(sock, _id)));
6828 event = eIO_Read;
6829 break;
6830 }
6831 break;
6832
6833 default:
6834 CORE_LOGF_X(62, eLOG_Error,
6835 ("%s[SOCK::Wait] "
6836 " Invalid event #%u",
6837 s_ID(sock, _id), (unsigned int) event));
6838 assert(0);
6839 return eIO_InvalidArg;
6840 }
6841
6842 assert(sock->type == eSocket);
6843 status = s_Wait(sock, event, timeout);
6844 if (s_ErrHook && status != eIO_Success && status != eIO_Timeout) {
6845 SSOCK_ErrInfo info;
6846 char addr[40];
6847 memset(&info, 0, sizeof(info));
6848 info.type = eSOCK_ErrIO;
6849 info.sock = sock;
6850 if (sock->port) {
6851 SOCK_ntoa(sock->host, addr, sizeof(addr));
6852 info.host = addr;
6853 info.port = sock->port;
6854 }
6855 #ifdef NCBI_OS_UNIX
6856 else
6857 info.host = sock->path;
6858 #endif /*NCBI_OS_UNIX*/
6859 info.event = event;
6860 info.status = status;
6861 s_ErrorCallback(&info);
6862 }
6863 return status;
6864 }
6865
6866
SOCK_Poll(size_t n,SSOCK_Poll polls[],const STimeout * timeout,size_t * n_ready)6867 extern EIO_Status SOCK_Poll(size_t n,
6868 SSOCK_Poll polls[],
6869 const STimeout* timeout,
6870 size_t* n_ready)
6871 {
6872 EIO_Status status;
6873 struct timeval tv;
6874 size_t i;
6875
6876 #ifdef NCBI_MONKEY
6877 SSOCK_Poll* orig_polls = polls; /* to know if 'polls' was replaced */
6878 EIO_Status mnk_status = -1;
6879 size_t orig_n = n;
6880 /* Not a poll function itself, just removes some of "polls" items */
6881 if (g_MONKEY_Poll)
6882 g_MONKEY_Poll(&n, &polls, &mnk_status);
6883 /* Even if call was intercepted, s_Select() continues as if nothing
6884 happened, because what we did was just removed some SSOCK_Poll pointers.
6885 The changes made in s_Select() will appear in the original array, but
6886 only for those SSOCK_Poll's that were left by Monkey */
6887 #endif /*NCBI_MONKEY*/
6888
6889 if (n && !polls) {
6890 if ( n_ready )
6891 *n_ready = 0;
6892 return eIO_InvalidArg;
6893 }
6894
6895 for (i = 0; i < n; ++i) {
6896 SOCK sock = polls[i].sock;
6897 polls[i].revent =
6898 sock && sock->type == eTrigger && ((TRIGGER)sock)->isset.ptr
6899 ? polls[i].event
6900 : eIO_Open;
6901 if (!sock || !(sock->type & eSocket) || sock->sock == SOCK_INVALID)
6902 continue;
6903 if ((polls[i].event & eIO_Read) && BUF_Size(sock->r_buf) != 0) {
6904 polls[i].revent = eIO_Read;
6905 continue;
6906 }
6907 if (sock->type != eSocket)
6908 continue;
6909 if ((polls[i].event == eIO_Read
6910 && (sock->r_status == eIO_Closed || sock->eof)) ||
6911 (polls[i].event == eIO_Write
6912 && sock->w_status == eIO_Closed)) {
6913 polls[i].revent = eIO_Close;
6914 }
6915 }
6916
6917 status = s_SelectStallsafe(n, polls, s_to2tv(timeout, &tv), n_ready);
6918
6919 #ifdef NCBI_MONKEY
6920 if (orig_polls != polls) {
6921 /* Copy poll results to the original array if some were excluded */
6922 size_t orig_iter, new_iter;
6923 for (orig_iter = 0; orig_iter < orig_n; ++orig_iter) {
6924 for (new_iter = 0; new_iter < n; ++new_iter) {
6925 if (orig_polls[orig_iter].sock == polls[new_iter].sock) {
6926 orig_polls[orig_iter] = polls[new_iter];
6927 break;
6928 }
6929 if (new_iter >= n)
6930 orig_polls[orig_iter].revent = eIO_Open/*no event*/;
6931 }
6932 }
6933 free(polls);
6934 polls = orig_polls;
6935 if (mnk_status != -1)
6936 status = mnk_status;
6937 }
6938 #endif /*NCBI_MONKEY*/
6939
6940 return status;
6941 }
6942
6943
SOCK_SetTimeout(SOCK sock,EIO_Event event,const STimeout * timeout)6944 extern EIO_Status SOCK_SetTimeout(SOCK sock,
6945 EIO_Event event,
6946 const STimeout* timeout)
6947 {
6948 char _id[MAXIDLEN];
6949
6950 if (timeout == kDefaultTimeout) {
6951 assert(0);
6952 return eIO_InvalidArg;
6953 }
6954 switch (event) {
6955 case eIO_Read:
6956 sock->r_tv_set = s_to2tv(timeout, &sock->r_tv) ? 1 : 0;
6957 break;
6958 case eIO_Write:
6959 sock->w_tv_set = s_to2tv(timeout, &sock->w_tv) ? 1 : 0;
6960 break;
6961 case eIO_ReadWrite:
6962 sock->r_tv_set = s_to2tv(timeout, &sock->r_tv) ? 1 : 0;
6963 sock->w_tv_set = s_to2tv(timeout, &sock->w_tv) ? 1 : 0;
6964 break;
6965 case eIO_Close:
6966 sock->c_tv_set = s_to2tv(timeout, &sock->c_tv) ? 1 : 0;
6967 break;
6968 default:
6969 CORE_LOGF_X(63, eLOG_Error,
6970 ("%s[SOCK::SetTimeout] "
6971 " Invalid event #%u",
6972 s_ID(sock, _id), (unsigned int) event));
6973 assert(0);
6974 return eIO_InvalidArg;
6975 }
6976 return eIO_Success;
6977 }
6978
6979
SOCK_GetTimeout(SOCK sock,EIO_Event event)6980 extern const STimeout* SOCK_GetTimeout(SOCK sock,
6981 EIO_Event event)
6982 {
6983 char _id[MAXIDLEN];
6984
6985 if (event == eIO_ReadWrite) {
6986 if (!sock->r_tv_set)
6987 event = eIO_Write;
6988 else if (!sock->w_tv_set)
6989 event = eIO_Read;
6990 else {
6991 /* timeouts stored normalized */
6992 if (sock->r_tv.tv_sec > sock->w_tv.tv_sec)
6993 return s_tv2to(&sock->w_tv, &sock->w_to);
6994 if (sock->w_tv.tv_sec > sock->r_tv.tv_sec)
6995 return s_tv2to(&sock->r_tv, &sock->r_to);
6996 assert(sock->r_tv.tv_sec == sock->w_tv.tv_sec);
6997 return sock->r_tv.tv_usec > sock->w_tv.tv_usec
6998 ? s_tv2to(&sock->w_tv, &sock->w_to)
6999 : s_tv2to(&sock->r_tv, &sock->r_to);
7000 }
7001 }
7002 switch (event) {
7003 case eIO_Read:
7004 return sock->r_tv_set ? s_tv2to(&sock->r_tv, &sock->r_to) : 0;
7005 case eIO_Write:
7006 return sock->w_tv_set ? s_tv2to(&sock->w_tv, &sock->w_to) : 0;
7007 case eIO_Close:
7008 return sock->c_tv_set ? s_tv2to(&sock->c_tv, &sock->c_to) : 0;
7009 default:
7010 CORE_LOGF_X(64, eLOG_Error,
7011 ("%s[SOCK::GetTimeout] "
7012 " Invalid event #%u",
7013 s_ID(sock, _id), (unsigned int) event));
7014 assert(0);
7015 }
7016 return 0/*kInfiniteTimeout*/;
7017 }
7018
7019
SOCK_Read(SOCK sock,void * buf,size_t size,size_t * n_read,EIO_ReadMethod how)7020 extern EIO_Status SOCK_Read(SOCK sock,
7021 void* buf,
7022 size_t size,
7023 size_t* n_read,
7024 EIO_ReadMethod how)
7025 {
7026 EIO_Status status;
7027 size_t x_read;
7028 char _id[MAXIDLEN];
7029
7030 if (sock->sock != SOCK_INVALID) {
7031 switch (how) {
7032 case eIO_ReadPeek:
7033 status = s_Read(sock, buf, size, &x_read, 1/*peek*/);
7034 break;
7035
7036 case eIO_ReadPlain:
7037 status = s_Read(sock, buf, size, &x_read, 0/*read*/);
7038 break;
7039
7040 case eIO_ReadPersist:
7041 x_read = 0;
7042 do {
7043 size_t xx_read;
7044 status = s_Read(sock, (char*) buf + (buf ? x_read : 0),
7045 size, &xx_read, 0/*read*/);
7046 x_read += xx_read;
7047 size -= xx_read;
7048 } while (size && status == eIO_Success);
7049 break;
7050
7051 default:
7052 CORE_LOGF_X(65, eLOG_Error,
7053 ("%s[SOCK::Read] "
7054 " Unsupported read method #%u",
7055 s_ID(sock, _id), (unsigned int) how));
7056 status = eIO_NotSupported;
7057 x_read = 0;
7058 assert(0);
7059 break;
7060 }
7061 } else {
7062 CORE_LOGF_X(66, eLOG_Error,
7063 ("%s[SOCK::Read] "
7064 " Invalid socket",
7065 s_ID(sock, _id)));
7066 status = eIO_Unknown;
7067 x_read = 0;
7068 }
7069
7070 if ( n_read )
7071 *n_read = x_read;
7072 return status;
7073 }
7074
7075
7076 #define s_Pushback(s, b, n) BUF_Pushback(&(s)->r_buf, b, n)
7077
7078
SOCK_ReadLine(SOCK sock,char * line,size_t size,size_t * n_read)7079 extern EIO_Status SOCK_ReadLine(SOCK sock,
7080 char* line,
7081 size_t size,
7082 size_t* n_read)
7083 {
7084 unsigned int/*bool*/ cr_seen, done;
7085 EIO_Status status;
7086 size_t len;
7087
7088 if ( n_read )
7089 *n_read = 0;
7090 if (!size || !line) {
7091 assert(0);
7092 return eIO_InvalidArg;
7093 }
7094 if (sock->sock == SOCK_INVALID) {
7095 char _id[MAXIDLEN];
7096 CORE_LOGF_X(125, eLOG_Error,
7097 ("%s[SOCK::ReadLine] "
7098 " Invalid socket",
7099 s_ID(sock, _id)));
7100 return eIO_Unknown;
7101 }
7102
7103 cr_seen = done = 0/*false*/;
7104 len = 0;
7105 do {
7106 size_t i;
7107 char w[1024], c;
7108 size_t x_size = BUF_Size(sock->r_buf);
7109 char* x_buf = size - len < sizeof(w) - cr_seen ? w : line + len;
7110 if (!x_size || x_size > sizeof(w) - cr_seen)
7111 x_size = sizeof(w) - cr_seen;
7112 status = s_Read(sock, x_buf + cr_seen, x_size, &x_size, 0/*read*/);
7113 assert(status == eIO_Success || !x_size);
7114 if (!x_size)
7115 done = 1/*true*/;
7116 else if (cr_seen)
7117 x_size++;
7118 i = cr_seen;
7119 while (i < x_size && len < size) {
7120 c = x_buf[i++];
7121 if (c == '\n') {
7122 cr_seen = 0/*false*/;
7123 done = 1/*true*/;
7124 break;
7125 }
7126 if (c == '\r' && !cr_seen) {
7127 cr_seen = 1/*true*/;
7128 continue;
7129 }
7130 if (cr_seen)
7131 line[len++] = '\r';
7132 cr_seen = 0/*false*/;
7133 if (len >= size) {
7134 --i; /* have to read it again */
7135 break;
7136 }
7137 if (c == '\r') {
7138 cr_seen = 1/*true*/;
7139 continue;
7140 } else if (!c) {
7141 done = 1/*true*/;
7142 break;
7143 }
7144 line[len++] = c;
7145 }
7146 if (len >= size)
7147 done = 1/*true*/;
7148 if (done && cr_seen) {
7149 c = '\r';
7150 if (!s_Pushback(sock, &c, 1))
7151 status = eIO_Unknown;
7152 }
7153 if (i < x_size && !s_Pushback(sock, &x_buf[i], x_size - i))
7154 status = eIO_Unknown;
7155 } while (!done && status == eIO_Success);
7156
7157 if (len < size)
7158 line[len] = '\0';
7159 if ( n_read )
7160 *n_read = len;
7161
7162 return status;
7163 }
7164
7165
SOCK_Pushback(SOCK sock,const void * buf,size_t size)7166 extern EIO_Status SOCK_Pushback(SOCK sock,
7167 const void* buf,
7168 size_t size)
7169 {
7170 if (size && !buf) {
7171 assert(0);
7172 return eIO_InvalidArg;
7173 }
7174 if (sock->sock == SOCK_INVALID) {
7175 char _id[MAXIDLEN];
7176 CORE_LOGF_X(67, eLOG_Error,
7177 ("%s[SOCK::Pushback] "
7178 " Invalid socket",
7179 s_ID(sock, _id)));
7180 return eIO_Closed;
7181 }
7182 return s_Pushback(sock, buf, size) ? eIO_Success : eIO_Unknown;
7183 }
7184
7185
SOCK_Status(SOCK sock,EIO_Event direction)7186 extern EIO_Status SOCK_Status(SOCK sock,
7187 EIO_Event direction)
7188 {
7189 if (sock) {
7190 switch (direction) {
7191 case eIO_Open:
7192 case eIO_Read:
7193 case eIO_Write:
7194 if (sock->sock == SOCK_INVALID)
7195 return direction/*!eIO_Open*/ ? eIO_Unknown : eIO_Closed;
7196 if (!sock->connected || sock->pending)
7197 return eIO_Timeout;
7198 if (direction == eIO_Read) {
7199 return sock->type == eSocket && sock->eof
7200 ? eIO_Closed : (EIO_Status) sock->r_status;
7201 }
7202 if (direction == eIO_Write)
7203 return (EIO_Status) sock->w_status;
7204 return eIO_Success;
7205 default:
7206 break;
7207 }
7208 }
7209 return eIO_InvalidArg;
7210 }
7211
7212
SOCK_Write(SOCK sock,const void * buf,size_t size,size_t * n_written,EIO_WriteMethod how)7213 extern EIO_Status SOCK_Write(SOCK sock,
7214 const void* buf,
7215 size_t size,
7216 size_t* n_written,
7217 EIO_WriteMethod how)
7218 {
7219 EIO_Status status;
7220 size_t x_written;
7221 char _id[MAXIDLEN];
7222
7223 if (size && !buf) {
7224 if ( n_written )
7225 *n_written = 0;
7226 assert(0);
7227 return eIO_InvalidArg;
7228 }
7229 if (sock->sock != SOCK_INVALID) {
7230 switch (how) {
7231 case eIO_WriteOutOfBand:
7232 if (sock->type == eDatagram) {
7233 CORE_LOGF_X(68, eLOG_Error,
7234 ("%s[SOCK::Write] "
7235 " OOB not supported for datagrams",
7236 s_ID(sock, _id)));
7237 status = eIO_NotSupported;
7238 x_written = 0;
7239 break;
7240 }
7241 /*FALLTHRU*/
7242
7243 case eIO_WritePlain:
7244 status = s_Write(sock, buf, size, &x_written,
7245 how == eIO_WriteOutOfBand ? 1 : 0);
7246 break;
7247
7248 case eIO_WritePersist:
7249 x_written = 0;
7250 do {
7251 size_t xx_written;
7252 status = s_Write(sock, (char*) buf + x_written,
7253 size, &xx_written, 0);
7254 x_written += xx_written;
7255 size -= xx_written;
7256 } while (size && status == eIO_Success);
7257 break;
7258
7259 default:
7260 CORE_LOGF_X(69, eLOG_Error,
7261 ("%s[SOCK::Write] "
7262 " Unsupported write method #%u",
7263 s_ID(sock, _id), (unsigned int) how));
7264 status = eIO_NotSupported;
7265 x_written = 0;
7266 assert(0);
7267 break;
7268 }
7269 } else {
7270 CORE_LOGF_X(70, eLOG_Error,
7271 ("%s[SOCK::Write] "
7272 " Invalid socket",
7273 s_ID(sock, _id)));
7274 status = eIO_Closed;
7275 x_written = 0;
7276 }
7277
7278 if ( n_written )
7279 *n_written = x_written;
7280 return status;
7281 }
7282
7283
SOCK_Abort(SOCK sock)7284 extern EIO_Status SOCK_Abort(SOCK sock)
7285 {
7286 char _id[MAXIDLEN];
7287
7288 if (sock->sock == SOCK_INVALID) {
7289 CORE_LOGF_X(71, eLOG_Warning,
7290 ("%s[SOCK::Abort] "
7291 " Invalid socket",
7292 s_ID(sock, _id)));
7293 return eIO_Closed;
7294 }
7295 if (sock->type == eDatagram) {
7296 CORE_LOGF_X(72, eLOG_Error,
7297 ("%s[SOCK::Abort] "
7298 " Datagram socket",
7299 s_ID(sock, _id)));
7300 assert(0);
7301 return eIO_InvalidArg;
7302 }
7303
7304 return s_Close_(sock, 1/*abort*/, fSOCK_KeepNone);
7305 }
7306
7307
SOCK_GetLocalPortEx(SOCK sock,int trueport,ENH_ByteOrder byte_order)7308 extern unsigned short SOCK_GetLocalPortEx(SOCK sock,
7309 int/*bool*/ trueport,
7310 ENH_ByteOrder byte_order)
7311 {
7312 unsigned short port;
7313
7314 if (!sock || sock->sock == SOCK_INVALID)
7315 return 0;
7316
7317 #ifdef NCBI_OS_UNIX
7318 if (sock->path[0])
7319 return 0/*UNIX socket*/;
7320 #endif /*NCBI_OS_UNIX*/
7321
7322 if (trueport || !sock->myport) {
7323 port = s_GetLocalPort(sock->sock);
7324 if (!trueport)
7325 sock->myport = port; /*cache it*/
7326 } else
7327 port = sock->myport;
7328 return byte_order == eNH_HostByteOrder ? port : htons(port);
7329 }
7330
7331
SOCK_GetLocalPort(SOCK sock,ENH_ByteOrder byte_order)7332 extern unsigned short SOCK_GetLocalPort(SOCK sock,
7333 ENH_ByteOrder byte_order)
7334 {
7335 return SOCK_GetLocalPortEx(sock, 0/*false*/, byte_order);
7336 }
7337
7338
SOCK_GetPeerAddress(SOCK sock,unsigned int * host,unsigned short * port,ENH_ByteOrder byte_order)7339 extern void SOCK_GetPeerAddress(SOCK sock,
7340 unsigned int* host,
7341 unsigned short* port,
7342 ENH_ByteOrder byte_order)
7343 {
7344 if (!sock) {
7345 if ( host )
7346 *host = 0;
7347 if ( port )
7348 *port = 0;
7349 return;
7350 }
7351 if ( host ) {
7352 *host = byte_order == eNH_HostByteOrder
7353 ? ntohl(sock->host) : sock->host;
7354 }
7355 if ( port ) {
7356 *port = byte_order == eNH_HostByteOrder
7357 ? sock->port : ntohs(sock->port);
7358 }
7359 }
7360
7361
SOCK_GetRemotePort(SOCK sock,ENH_ByteOrder byte_order)7362 extern unsigned short SOCK_GetRemotePort(SOCK sock,
7363 ENH_ByteOrder byte_order)
7364 {
7365 unsigned short port;
7366 SOCK_GetPeerAddress(sock, 0, &port, byte_order);
7367 return port;
7368 }
7369
7370
SOCK_GetPeerAddressString(SOCK sock,char * buf,size_t bufsize)7371 extern char* SOCK_GetPeerAddressString(SOCK sock,
7372 char* buf,
7373 size_t bufsize)
7374 {
7375 return SOCK_GetPeerAddressStringEx(sock, buf, bufsize, eSAF_Full);
7376 }
7377
7378
SOCK_GetPeerAddressStringEx(SOCK sock,char * buf,size_t bufsize,ESOCK_AddressFormat format)7379 extern char* SOCK_GetPeerAddressStringEx(SOCK sock,
7380 char* buf,
7381 size_t bufsize,
7382 ESOCK_AddressFormat format)
7383 {
7384 char port[10];
7385 size_t len;
7386
7387 if (!buf || !bufsize)
7388 return 0/*error*/;
7389 if (!sock) {
7390 *buf = '\0';
7391 return 0/*error*/;
7392 }
7393 switch (format) {
7394 case eSAF_Full:
7395 #ifdef NCBI_OS_UNIX
7396 if (sock->path[0]) {
7397 if ((len = strlen(sock->path)) < bufsize)
7398 memcpy(buf, sock->path, len + 1);
7399 else
7400 return 0/*error*/;
7401 } else
7402 #endif /*NCBI_OS_UNIX*/
7403 if (!SOCK_HostPortToString(sock->host, sock->port, buf, bufsize))
7404 return 0/*error*/;
7405 break;
7406 case eSAF_Port:
7407 #ifdef NCBI_OS_UNIX
7408 if (sock->path[0])
7409 *buf = '\0';
7410 else
7411 #endif /*NCBI_OS_UNIX*/
7412 if ((len = (size_t) sprintf(port, "%hu", sock->port)) < bufsize)
7413 memcpy(buf, port, len + 1);
7414 else
7415 return 0/*error*/;
7416 break;
7417 case eSAF_IP:
7418 #ifdef NCBI_OS_UNIX
7419 if (sock->path[0])
7420 *buf = '\0';
7421 else
7422 #endif /*NCBI_OS_UNIX*/
7423 if (SOCK_ntoa(sock->host, buf, bufsize) != 0)
7424 return 0/*error*/;
7425 break;
7426 default:
7427 return 0/*error*/;
7428 }
7429 return buf;
7430 }
7431
7432
SOCK_GetOSHandleEx(SOCK sock,void * handle,size_t handle_size,EOwnership ownership)7433 extern EIO_Status SOCK_GetOSHandleEx(SOCK sock,
7434 void* handle,
7435 size_t handle_size,
7436 EOwnership ownership)
7437 {
7438 EIO_Status status;
7439 TSOCK_Handle fd;
7440
7441 if (!handle || handle_size != sizeof(sock->sock)) {
7442 char _id[MAXIDLEN];
7443 CORE_LOGF_X(73, eLOG_Error,
7444 ("%s[SOCK::GetOSHandle] "
7445 " Invalid handle%s %lu",
7446 s_ID(sock, _id),
7447 handle ? " size" : "",
7448 handle ? (unsigned long) handle_size : 0));
7449 assert(0);
7450 return eIO_InvalidArg;
7451 }
7452 if (!sock) {
7453 fd = SOCK_INVALID;
7454 memcpy(handle, &fd, handle_size);
7455 return eIO_InvalidArg;
7456 }
7457 fd = sock->sock;
7458 memcpy(handle, &fd, handle_size);
7459 if (s_Initialized <= 0 || fd == SOCK_INVALID)
7460 status = eIO_Closed;
7461 else if (ownership != eTakeOwnership)
7462 status = eIO_Success;
7463 else {
7464 sock->keep = 1/*true*/;
7465 status = s_Close(sock, 0, fSOCK_KeepNone);
7466 }
7467 return status;
7468 }
7469
7470
SOCK_GetOSHandle(SOCK sock,void * handle,size_t handle_size)7471 extern EIO_Status SOCK_GetOSHandle(SOCK sock,
7472 void* handle,
7473 size_t handle_size)
7474 {
7475 return SOCK_GetOSHandleEx(sock, handle, handle_size, eNoOwnership);
7476 }
7477
7478
SOCK_SetReadOnWriteAPI(ESwitch on_off)7479 extern ESwitch SOCK_SetReadOnWriteAPI(ESwitch on_off)
7480 {
7481 ESwitch old = s_ReadOnWrite;
7482 if (on_off != eDefault)
7483 s_ReadOnWrite = on_off;
7484 return old;
7485 }
7486
7487
SOCK_SetReadOnWrite(SOCK sock,ESwitch on_off)7488 extern ESwitch SOCK_SetReadOnWrite(SOCK sock, ESwitch on_off)
7489 {
7490 if (sock->type != eDatagram) {
7491 ESwitch old = (ESwitch) sock->r_on_w;
7492 sock->r_on_w = on_off;
7493 return old;
7494 }
7495 return eDefault;
7496 }
7497
7498
7499 /*ARGSUSED*/
SOCK_SetCork(SOCK sock,int on_off)7500 extern void SOCK_SetCork(SOCK sock, int/*bool*/ on_off)
7501 {
7502 char _id[MAXIDLEN];
7503
7504 if (sock->sock == SOCK_INVALID) {
7505 CORE_LOGF_X(158, eLOG_Warning,
7506 ("%s[SOCK::SetCork] "
7507 " Invalid socket",
7508 s_ID(sock, _id)));
7509 return;
7510 }
7511 if (sock->type == eDatagram) {
7512 CORE_LOGF_X(159, eLOG_Error,
7513 ("%s[SOCK::SetCork] "
7514 " Datagram socket",
7515 s_ID(sock, _id)));
7516 assert(0);
7517 return;
7518 }
7519
7520 #if defined(TCP_CORK) && !defined(NCBI_OS_CYGWIN)
7521 if (setsockopt(sock->sock, IPPROTO_TCP, TCP_CORK,
7522 (char*) &on_off, sizeof(on_off)) != 0) {
7523 int error = SOCK_ERRNO;
7524 const char* strerr = SOCK_STRERROR(error);
7525 CORE_LOGF_ERRNO_EXX(160, eLOG_Warning,
7526 error, strerr ? strerr : "",
7527 ("%s[SOCK::SetCork] "
7528 " Failed setsockopt(%sTCP_CORK)",
7529 s_ID(sock, _id), on_off ? "" : "!"));
7530 UTIL_ReleaseBuffer(strerr);
7531 }
7532 # ifdef TCP_NOPUSH
7533 /* try to avoid 5 second delay on BSD systems (incl. Darwin) */
7534 if (!on_off)
7535 (void) send(sock->sock, _id/*dontcare*/, 0, 0);
7536 # endif /*TCP_NOPUSH*/
7537 #endif /*TCP_CORK && !NCBI_OS_CYGWIN*/
7538 }
7539
7540
7541 /*ARGSUSED*/
SOCK_DisableOSSendDelay(SOCK sock,int on_off)7542 extern void SOCK_DisableOSSendDelay(SOCK sock, int/*bool*/ on_off)
7543 {
7544 char _id[MAXIDLEN];
7545
7546 if (sock->sock == SOCK_INVALID) {
7547 CORE_LOGF_X(156, eLOG_Warning,
7548 ("%s[SOCK::DisableOSSendDelay] "
7549 " Invalid socket",
7550 s_ID(sock, _id)));
7551 return;
7552 }
7553 if (sock->type == eDatagram) {
7554 CORE_LOGF_X(157, eLOG_Error,
7555 ("%s[SOCK::DisableOSSendDelay] "
7556 " Datagram socket",
7557 s_ID(sock, _id)));
7558 assert(0);
7559 return;
7560 }
7561
7562 #ifdef TCP_NODELAY
7563 if (setsockopt(sock->sock, IPPROTO_TCP, TCP_NODELAY,
7564 (char*) &on_off, sizeof(on_off)) != 0) {
7565 int error = SOCK_ERRNO;
7566 const char* strerr = SOCK_STRERROR(error);
7567 CORE_LOGF_ERRNO_EXX(75, eLOG_Warning,
7568 error, strerr ? strerr : "",
7569 ("%s[SOCK::DisableOSSendDelay] "
7570 " Failed setsockopt(%sTCP_NODELAY)",
7571 s_ID(sock, _id), on_off ? "" : "!"));
7572 UTIL_ReleaseBuffer(strerr);
7573 }
7574 #endif /*TCP_NODELAY*/
7575 }
7576
7577
7578
7579 /******************************************************************************
7580 * DATAGRAM SOCKET
7581 */
7582
7583
DSOCK_Create(SOCK * sock)7584 extern EIO_Status DSOCK_Create(SOCK* sock)
7585 {
7586 return DSOCK_CreateEx(sock, fSOCK_LogDefault);
7587 }
7588
7589
DSOCK_CreateEx(SOCK * sock,TSOCK_Flags flags)7590 extern EIO_Status DSOCK_CreateEx(SOCK* sock, TSOCK_Flags flags)
7591 {
7592 TSOCK_Handle fd;
7593 int type;
7594 #ifdef NCBI_OS_MSWIN
7595 HANDLE event;
7596 #endif /*NCBI_OS_MSWIN*/
7597 int error;
7598 SOCK x_sock;
7599 unsigned int x_id = ++s_ID_Counter * 1000;
7600
7601 *sock = 0;
7602
7603 /* initialize internals */
7604 if ((flags & fSOCK_Secure) || s_InitAPI(0) != eIO_Success)
7605 return eIO_NotSupported;
7606
7607 type = SOCK_DGRAM;
7608 #ifdef SOCK_NONBLOCK
7609 type |= SOCK_NONBLOCK;
7610 #endif /*SOCK_NONBLOCK*/
7611 #ifdef SOCK_CLOEXEC
7612 if (!(flags & fSOCK_KeepOnExec))
7613 type |= SOCK_CLOEXEC;
7614 #endif /*SOCK_CLOEXEC*/
7615 /* create new datagram socket */
7616 if ((fd = socket(AF_INET, type, 0)) == SOCK_INVALID) {
7617 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
7618 CORE_LOGF_ERRNO_EXX(76, eLOG_Error,
7619 error, strerr ? strerr : "",
7620 ("DSOCK#%u[?]: [DSOCK::Create] "
7621 " Cannot create socket",
7622 x_id));
7623 UTIL_ReleaseBuffer(strerr);
7624 return eIO_Unknown;
7625 }
7626
7627 #if defined(NCBI_OS_MSWIN)
7628 if (!(event = WSACreateEvent())) {
7629 DWORD err = GetLastError();
7630 const char* strerr = s_WinStrerror(err);
7631 CORE_LOGF_ERRNO_EXX(139, eLOG_Error,
7632 err, strerr ? strerr : "",
7633 ("DSOCK#%u[%u]: [DSOCK::Create] "
7634 " Failed to create IO event",
7635 x_id, (unsigned int) fd));
7636 UTIL_ReleaseBufferOnHeap(strerr);
7637 SOCK_CLOSE(fd);
7638 return eIO_Unknown;
7639 }
7640 /* NB: WSAEventSelect() sets non-blocking automatically */
7641 if (WSAEventSelect(fd, event, SOCK_EVENTS) != 0) {
7642 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
7643 CORE_LOGF_ERRNO_EXX(140, eLOG_Error,
7644 error, strerr ? strerr : "",
7645 ("DSOCK#%u[%u]: [DSOCK::Create] "
7646 " Failed to bind IO event",
7647 x_id, (unsigned int) fd));
7648 UTIL_ReleaseBuffer(strerr);
7649 SOCK_CLOSE(fd);
7650 WSACloseEvent(event);
7651 return eIO_Unknown;
7652 }
7653 #elif !defined(SOCK_NONBLOCK)
7654 /* set to non-blocking mode */
7655 if (!s_SetNonblock(fd, 1/*true*/)) {
7656 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
7657 CORE_LOGF_ERRNO_EXX(77, eLOG_Error,
7658 error, strerr ? strerr : "",
7659 ("DSOCK#%u[%u]: [DSOCK::Create] "
7660 " Cannot set socket to non-blocking mode",
7661 x_id, (unsigned int) fd));
7662 UTIL_ReleaseBuffer(strerr);
7663 SOCK_CLOSE(fd);
7664 return eIO_Unknown;
7665 }
7666 #endif
7667
7668 if (!(x_sock = (SOCK) calloc(1, sizeof(*x_sock)))) {
7669 SOCK_CLOSE(fd);
7670 #ifdef NCBI_OS_MSWIN
7671 WSACloseEvent(event);
7672 #endif /*NCBI_OS_MSWIN*/
7673 return eIO_Unknown;
7674 }
7675
7676 /* success... */
7677 x_sock->sock = fd;
7678 x_sock->id = x_id;
7679 /* no host and port - not "connected" */
7680 x_sock->type = eDatagram;
7681 x_sock->side = eSOCK_Client;
7682 x_sock->log = flags & (fSOCK_LogDefault | fSOCK_LogOn);
7683 x_sock->keep = flags & fSOCK_KeepOnClose ? 1/*true*/ : 0/*false*/;
7684 x_sock->i_on_sig = flags & fSOCK_InterruptOnSignal ? eOn : eDefault;
7685 #ifdef NCBI_OS_MSWIN
7686 x_sock->event = event;
7687 x_sock->writable = 1/*true*/;
7688 #endif /*NCBI_OS_MSWIN*/
7689 x_sock->crossexec = flags & fSOCK_KeepOnExec ? 1/*true*/ : 0/*false*/;
7690 /* all timeout bits cleared - infinite */
7691 BUF_SetChunkSize(&x_sock->r_buf, SOCK_BUF_CHUNK_SIZE);
7692 BUF_SetChunkSize(&x_sock->w_buf, SOCK_BUF_CHUNK_SIZE);
7693
7694 #ifndef SOCK_CLOEXEC
7695 if (!x_sock->crossexec && !s_SetCloexec(fd, 1/*true*/)) {
7696 const char* strerr;
7697 char _id[MAXIDLEN];
7698 # ifdef NCBI_OS_MSWIN
7699 DWORD err = GetLastError();
7700 strerr = s_WinStrerror(err);
7701 error = err;
7702 # else
7703 error = errno;
7704 strerr = SOCK_STRERROR(error);
7705 # endif /*NCBI_OS_MSWIN*/
7706 CORE_LOGF_ERRNO_EXX(130, eLOG_Warning,
7707 error, strerr ? strerr : "",
7708 ("%s[DSOCK::Create] Cannot set"
7709 " socket close-on-exec mode",
7710 s_ID(*sock, _id)));
7711 # ifdef NCBI_OS_MSWIN
7712 UTIL_ReleaseBufferOnHeap(strerr);
7713 # else
7714 UTIL_ReleaseBuffer(strerr);
7715 # endif /*NCBI_OS_MSWIN*/
7716 }
7717 #endif /*!SOCK_CLOEXEC*/
7718
7719 /* statistics & logging */
7720 if (x_sock->log == eOn || (x_sock->log == eDefault && s_Log == eOn))
7721 s_DoLog(eLOG_Note, x_sock, eIO_Open, 0, 0, 0);
7722
7723 *sock = x_sock;
7724 return eIO_Success;
7725 }
7726
7727
DSOCK_Bind(SOCK sock,unsigned short port)7728 extern EIO_Status DSOCK_Bind(SOCK sock, unsigned short port)
7729 {
7730 char _id[MAXIDLEN];
7731 int error;
7732 union {
7733 struct sockaddr sa;
7734 struct sockaddr_in in;
7735 } addr;
7736
7737 if (sock->sock == SOCK_INVALID) {
7738 CORE_LOGF_X(79, eLOG_Error,
7739 ("%s[DSOCK::Bind] "
7740 " Invalid socket",
7741 s_ID(sock, _id)));
7742 return eIO_Closed;
7743 }
7744 if (sock->type != eDatagram) {
7745 CORE_LOGF_X(78, eLOG_Error,
7746 ("%s[DSOCK::Bind] "
7747 " Not a datagram socket",
7748 s_ID(sock, _id)));
7749 assert(0);
7750 return eIO_InvalidArg;
7751 }
7752
7753 /* bind */
7754 memset(&addr, 0, sizeof(addr));
7755 #ifdef HAVE_SIN_LEN
7756 addr.in.sin_len = (TSOCK_socklen_t) sizeof(addr.in);
7757 #endif /*HAVE_SIN_LEN*/
7758 addr.in.sin_family = AF_INET;
7759 addr.in.sin_addr.s_addr = htonl(INADDR_ANY);
7760 addr.in.sin_port = htons(port);
7761 if (bind(sock->sock, &addr.sa, sizeof(addr.in)) != 0) {
7762 const char* strerr = SOCK_STRERROR(error = SOCK_ERRNO);
7763 CORE_LOGF_ERRNO_EXX(80, error != SOCK_EADDRINUSE
7764 ? eLOG_Error : eLOG_Trace,
7765 error, strerr ? strerr : "",
7766 ("%s[DSOCK::Bind] "
7767 " Failed bind(:%hu)",
7768 s_ID(sock, _id), port));
7769 UTIL_ReleaseBuffer(strerr);
7770 return error != SOCK_EADDRINUSE ? eIO_Unknown : eIO_Closed;
7771 }
7772 if (!port) {
7773 TSOCK_socklen_t addrlen = sizeof(addr);
7774 assert(addr.sa.sa_family == AF_INET);
7775 error = getsockname(sock->sock, &addr.sa, &addrlen) != 0
7776 ? SOCK_ERRNO : 0;
7777 if (error || addr.sa.sa_family != AF_INET || !addr.in.sin_port) {
7778 const char* strerr = SOCK_STRERROR(error);
7779 CORE_LOGF_ERRNO_EXX(114, eLOG_Error,
7780 error, strerr ? strerr : "",
7781 ("%s[DSOCK::Bind] "
7782 " Cannot obtain a free socket port",
7783 s_ID(sock, _id)));
7784 UTIL_ReleaseBuffer(strerr);
7785 return eIO_Closed;
7786 }
7787 port = ntohs(addr.in.sin_port);
7788 }
7789
7790 /* statistics & logging */
7791 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
7792 s_DoLog(eLOG_Note, sock, eIO_Open, 0, 0, &addr.in);
7793
7794 sock->myport = port;
7795 return eIO_Success;
7796 }
7797
7798
DSOCK_Connect(SOCK sock,const char * hostname,unsigned short port)7799 extern EIO_Status DSOCK_Connect(SOCK sock,
7800 const char* hostname, unsigned short port)
7801 {
7802 struct sockaddr_in peer;
7803 char _id[MAXIDLEN];
7804 unsigned int host;
7805 char addr[40];
7806
7807 if (sock->sock == SOCK_INVALID) {
7808 CORE_LOGF_X(82, eLOG_Error,
7809 ("%s[DSOCK::Connect] "
7810 " Invalid socket",
7811 s_ID(sock, _id)));
7812 return eIO_Closed;
7813 }
7814 if (sock->type != eDatagram) {
7815 CORE_LOGF_X(81, eLOG_Error,
7816 ("%s[DSOCK::Connect] "
7817 " Not a datagram socket",
7818 s_ID(sock, _id)));
7819 assert(0);
7820 return eIO_InvalidArg;
7821 }
7822
7823 /* drop all pending data */
7824 BUF_Erase(sock->r_buf);
7825 BUF_Erase(sock->w_buf);
7826 sock->r_len = 0;
7827 sock->w_len = 0;
7828 sock->eof = 0;
7829 sock->id++;
7830
7831 if (!hostname || !*hostname)
7832 host = 0;
7833 else if (!(host = s_gethostbyname(hostname, 0, (ESwitch) sock->log))) {
7834 CORE_LOGF_X(83, eLOG_Error,
7835 ("%s[DSOCK::Connect] "
7836 " Failed SOCK_gethostbyname(\"%.*s\")",
7837 s_ID(sock, _id), CONN_HOST_LEN, hostname));
7838 return eIO_Unknown;
7839 }
7840
7841 if (!host != !port) {
7842 if (port) {
7843 assert(!host);
7844 sprintf(addr, ":%hu", port);
7845 } else
7846 *addr = '\0';
7847 CORE_LOGF_X(84, eLOG_Error,
7848 ("%s[DSOCK::Connect] "
7849 " Address \"%.*s%s\" incomplete, missing %s",
7850 s_ID(sock, _id), CONN_HOST_LEN, host ? hostname : "",
7851 addr, port ? "host" : "port"));
7852 return eIO_InvalidArg;
7853 }
7854
7855 /* connect (non-empty address) or drop association (on empty address) */
7856 memset(&peer, 0, sizeof(peer));
7857 #ifdef HAVE_SIN_LEN
7858 peer.sin_len = (TSOCK_socklen_t) sizeof(peer);
7859 #endif /*HAVE_SIN_LEN*/
7860 if (host/* && port*/) {
7861 peer.sin_family = AF_INET;
7862 peer.sin_addr.s_addr = host;
7863 peer.sin_port = htons(port);
7864 }
7865 #ifdef AF_UNSPEC
7866 else
7867 peer.sin_family = AF_UNSPEC;
7868 #endif /*AF_UNSPEC*/
7869 if (connect(sock->sock, (struct sockaddr*) &peer, sizeof(peer)) != 0) {
7870 int error = SOCK_ERRNO;
7871 const char* strerr = SOCK_STRERROR(error);
7872 if (host)
7873 SOCK_HostPortToString(host, port, addr, sizeof(addr));
7874 else
7875 *addr = '\0';
7876 CORE_LOGF_ERRNO_EXX(85, eLOG_Error,
7877 error, strerr ? strerr : "",
7878 ("%s[DSOCK::Connect] "
7879 " Failed %sconnect%s%s%s",
7880 s_ID(sock, _id), *addr ? "" : "to dis",
7881 &"("[!*addr], addr, &")"[!*addr]));
7882 UTIL_ReleaseBuffer(strerr);
7883 return eIO_Closed;
7884 }
7885
7886 /* statistics & logging */
7887 if (sock->log == eOn || (sock->log == eDefault && s_Log == eOn))
7888 s_DoLog(eLOG_Note, sock, eIO_Open, "", 0, &peer);
7889
7890 sock->host = host;
7891 sock->port = port;
7892 return eIO_Success;
7893 }
7894
7895
DSOCK_WaitMsg(SOCK sock,const STimeout * timeout)7896 extern EIO_Status DSOCK_WaitMsg(SOCK sock, const STimeout* timeout)
7897 {
7898 char _id[MAXIDLEN];
7899 EIO_Status status;
7900 SSOCK_Poll poll;
7901 struct timeval tv;
7902
7903 if (sock->sock == SOCK_INVALID) {
7904 CORE_LOGF_X(96, eLOG_Error,
7905 ("%s[DSOCK::WaitMsg] "
7906 " Invalid socket",
7907 s_ID(sock, _id)));
7908 return eIO_Unknown;
7909 }
7910 if (sock->type != eDatagram) {
7911 CORE_LOGF_X(95, eLOG_Error,
7912 ("%s[DSOCK::WaitMsg] "
7913 " Not a datagram socket",
7914 s_ID(sock, _id)));
7915 assert(0);
7916 return eIO_InvalidArg;
7917 }
7918
7919 poll.sock = sock;
7920 poll.event = eIO_Read;
7921 poll.revent = eIO_Open;
7922 status = s_Select(1, &poll, s_to2tv(timeout, &tv), 1/*asis*/);
7923 assert(poll.event == eIO_Read);
7924 if (status == eIO_Success && poll.revent != eIO_Read) {
7925 assert(poll.revent == eIO_Close);
7926 status = eIO_Closed;
7927 }
7928 if (s_ErrHook && status != eIO_Success && status != eIO_Timeout) {
7929 SSOCK_ErrInfo info;
7930 char addr[40];
7931 memset(&info, 0, sizeof(info));
7932 info.type = eSOCK_ErrIO;
7933 info.sock = sock;
7934 SOCK_ntoa(sock->host, addr, sizeof(addr));
7935 info.host = addr;
7936 info.port = sock->port;
7937 info.event = eIO_Read;
7938 info.status = status;
7939 s_ErrorCallback(&info);
7940 }
7941 return status;
7942 }
7943
7944
DSOCK_RecvMsg(SOCK sock,void * buf,size_t bufsize,size_t msgsize,size_t * msglen,unsigned int * sender_addr,unsigned short * sender_port)7945 extern EIO_Status DSOCK_RecvMsg(SOCK sock,
7946 void* buf,
7947 size_t bufsize,
7948 size_t msgsize,
7949 size_t* msglen,
7950 unsigned int* sender_addr,
7951 unsigned short* sender_port)
7952 {
7953 char _id[MAXIDLEN];
7954 EIO_Status status;
7955
7956 if ( msglen )
7957 *msglen = 0;
7958 if ( sender_addr )
7959 *sender_addr = 0;
7960 if ( sender_port )
7961 *sender_port = 0;
7962
7963 if (sock->sock == SOCK_INVALID) {
7964 CORE_LOGF_X(93, eLOG_Error,
7965 ("%s[DSOCK::RecvMsg] "
7966 " Invalid socket",
7967 s_ID(sock, _id)));
7968 return eIO_Unknown;
7969 }
7970 if (sock->type != eDatagram) {
7971 CORE_LOGF_X(92, eLOG_Error,
7972 ("%s[DSOCK::RecvMsg] "
7973 " Not a datagram socket",
7974 s_ID(sock, _id)));
7975 assert(0);
7976 return eIO_InvalidArg;
7977 }
7978
7979 status = s_RecvMsg(sock, buf, bufsize, msgsize, msglen,
7980 sender_addr, sender_port);
7981 if (s_ErrHook && status != eIO_Success) {
7982 SSOCK_ErrInfo info;
7983 char addr[40];
7984 memset(&info, 0, sizeof(info));
7985 info.type = eSOCK_ErrIO;
7986 info.sock = sock;
7987 SOCK_ntoa(sock->host, addr, sizeof(addr));
7988 info.host = addr;
7989 info.port = sock->port;
7990 info.event = eIO_Read;
7991 info.status = status;
7992 s_ErrorCallback(&info);
7993 }
7994 return status;
7995 }
7996
7997
DSOCK_SendMsg(SOCK sock,const char * host,unsigned short port,const void * data,size_t datalen)7998 extern EIO_Status DSOCK_SendMsg(SOCK sock,
7999 const char* host,
8000 unsigned short port,
8001 const void* data,
8002 size_t datalen)
8003 {
8004 char _id[MAXIDLEN];
8005 EIO_Status status;
8006
8007 if (sock->sock == SOCK_INVALID) {
8008 CORE_LOGF_X(87, eLOG_Error,
8009 ("%s[DSOCK::SendMsg] "
8010 " Invalid socket",
8011 s_ID(sock, _id)));
8012 return eIO_Closed;
8013 }
8014 if (sock->type != eDatagram) {
8015 CORE_LOGF_X(86, eLOG_Error,
8016 ("%s[DSOCK::SendMsg] "
8017 " Not a datagram socket",
8018 s_ID(sock, _id)));
8019 assert(0);
8020 return eIO_InvalidArg;
8021 }
8022
8023 status = s_SendMsg(sock, host, port, data, datalen);
8024 if (s_ErrHook && status != eIO_Success) {
8025 SSOCK_ErrInfo info;
8026 char addr[40];
8027 memset(&info, 0, sizeof(info));
8028 info.type = eSOCK_ErrIO;
8029 info.sock = sock;
8030 SOCK_ntoa(sock->host, addr, sizeof(addr));
8031 info.host = addr;
8032 info.port = sock->port;
8033 info.event = eIO_Write;
8034 info.status = status;
8035 s_ErrorCallback(&info);
8036 }
8037 return status;
8038 }
8039
8040
DSOCK_WipeMsg(SOCK sock,EIO_Event direction)8041 extern EIO_Status DSOCK_WipeMsg(SOCK sock, EIO_Event direction)
8042 {
8043 char _id[MAXIDLEN];
8044 EIO_Status status;
8045
8046 if (sock->sock == SOCK_INVALID) {
8047 CORE_LOGF_X(98, eLOG_Error,
8048 ("%s[DSOCK::WipeMsg] "
8049 " Invalid socket",
8050 s_ID(sock, _id)));
8051 return eIO_Closed;
8052 }
8053 if (sock->type != eDatagram) {
8054 CORE_LOGF_X(97, eLOG_Error,
8055 ("%s[DSOCK::WipeMsg] "
8056 " Not a datagram socket",
8057 s_ID(sock, _id)));
8058 assert(0);
8059 return eIO_InvalidArg;
8060 }
8061
8062 switch (direction) {
8063 case eIO_Read:
8064 sock->r_len = 0;
8065 BUF_Erase(sock->r_buf);
8066 sock->r_status = status = eIO_Success;
8067 break;
8068 case eIO_Write:
8069 sock->r_len = 0;
8070 BUF_Erase(sock->w_buf);
8071 sock->w_status = status = eIO_Success;
8072 break;
8073 default:
8074 CORE_LOGF_X(99, eLOG_Error,
8075 ("%s[DSOCK::WipeMsg] "
8076 " Invalid direction #%u",
8077 s_ID(sock, _id), (unsigned int) direction));
8078 assert(0);
8079 status = eIO_InvalidArg;
8080 break;
8081 }
8082
8083 return status;
8084 }
8085
8086
DSOCK_SetBroadcast(SOCK sock,int broadcast)8087 extern EIO_Status DSOCK_SetBroadcast(SOCK sock, int/*bool*/ broadcast)
8088 {
8089 char _id[MAXIDLEN];
8090
8091 if (sock->sock == SOCK_INVALID) {
8092 CORE_LOGF_X(101, eLOG_Error,
8093 ("%s[DSOCK::SetBroadcast] "
8094 " Invalid socket",
8095 s_ID(sock, _id)));
8096 return eIO_Closed;
8097 }
8098 if (sock->type != eDatagram) {
8099 CORE_LOGF_X(100, eLOG_Error,
8100 ("%s[DSOCK::SetBroadcast] "
8101 " Not a datagram socket",
8102 s_ID(sock, _id)));
8103 assert(0);
8104 return eIO_InvalidArg;
8105 }
8106
8107 #if defined(NCBI_OS_UNIX) || defined(NCBI_OS_MSWIN)
8108 /* setsockopt() is not implemented for MAC (in MIT socket emulation lib) */
8109 {{
8110 # ifdef NCBI_OS_MSWIN
8111 BOOL bcast = !!broadcast;
8112 # else
8113 int bcast = !!broadcast;
8114 # endif /*NCBI_OS_MSWIN*/
8115 if (setsockopt(sock->sock, SOL_SOCKET, SO_BROADCAST,
8116 (const char*) &bcast, sizeof(bcast)) != 0) {
8117 int error = SOCK_ERRNO;
8118 const char* strerr = SOCK_STRERROR(error);
8119 CORE_LOGF_ERRNO_EXX(102, eLOG_Error,
8120 error, strerr ? strerr : "",
8121 ("%s[DSOCK::SetBroadcast] "
8122 " Failed setsockopt(%sBROADCAST)",
8123 s_ID(sock, _id), bcast ? "" : "NO"));
8124 UTIL_ReleaseBuffer(strerr);
8125 return eIO_Unknown;
8126 }
8127 }}
8128 #else
8129 return eIO_NotSupported;
8130 #endif /*NCBI_OS_UNIX || NXBI_OS_MSWIN*/
8131 return eIO_Success;
8132 }
8133
8134
DSOCK_GetMessageCount(SOCK sock,EIO_Event direction)8135 extern TNCBI_BigCount DSOCK_GetMessageCount(SOCK sock, EIO_Event direction)
8136 {
8137 if (sock && sock->type == eDatagram) {
8138 switch (direction) {
8139 case eIO_Read:
8140 return sock->n_in;
8141 case eIO_Write:
8142 return sock->n_out;
8143 default:
8144 assert(0);
8145 break;
8146 }
8147 }
8148 return 0;
8149 }
8150
8151
8152
8153 /******************************************************************************
8154 * CLASSIFICATION & STATS
8155 */
8156
8157
SOCK_IsDatagram(SOCK sock)8158 extern int/*bool*/ SOCK_IsDatagram(SOCK sock)
8159 {
8160 return sock && sock->sock != SOCK_INVALID && sock->type == eDatagram;
8161 }
8162
8163
SOCK_IsClientSide(SOCK sock)8164 extern int/*bool*/ SOCK_IsClientSide(SOCK sock)
8165 {
8166 return sock && sock->sock != SOCK_INVALID && sock->side == eSOCK_Client;
8167 }
8168
8169
SOCK_IsServerSide(SOCK sock)8170 extern int/*bool*/ SOCK_IsServerSide(SOCK sock)
8171 {
8172 return sock && sock->sock != SOCK_INVALID && sock->side == eSOCK_Server;
8173 }
8174
8175
SOCK_IsUNIX(SOCK sock)8176 extern int/*bool*/ SOCK_IsUNIX(SOCK sock)
8177 {
8178 #ifdef NCBI_OS_UNIX
8179 return sock && sock->sock != SOCK_INVALID && sock->path[0];
8180 #else
8181 return 0/*false*/;
8182 #endif /*NCBI_OS_UNIX*/
8183 }
8184
8185
SOCK_IsSecure(SOCK sock)8186 extern int/*bool*/ SOCK_IsSecure(SOCK sock)
8187 {
8188 return sock && sock->sock != SOCK_INVALID && sock->sslctx;
8189 }
8190
8191
SOCK_GetPosition(SOCK sock,EIO_Event direction)8192 extern TNCBI_BigCount SOCK_GetPosition(SOCK sock, EIO_Event direction)
8193 {
8194 if (sock) {
8195 switch (direction) {
8196 case eIO_Read:
8197 if (sock->type == eDatagram)
8198 return sock->r_len - BUF_Size(sock->r_buf);
8199 return sock->n_read - (TNCBI_BigCount) BUF_Size(sock->r_buf);
8200 case eIO_Write:
8201 if (sock->type == eDatagram)
8202 return BUF_Size(sock->w_buf);
8203 return sock->n_written + (TNCBI_BigCount) sock->w_len;
8204 default:
8205 assert(0);
8206 break;
8207 }
8208 }
8209 return 0;
8210 }
8211
8212
SOCK_GetCount(SOCK sock,EIO_Event direction)8213 extern TNCBI_BigCount SOCK_GetCount(SOCK sock, EIO_Event direction)
8214 {
8215 if (sock) {
8216 switch (direction) {
8217 case eIO_Read:
8218 return sock->type == eDatagram ? sock->r_len : sock->n_read;
8219 case eIO_Write:
8220 return sock->type == eDatagram ? sock->w_len : sock->n_written;
8221 default:
8222 assert(0);
8223 break;
8224 }
8225 }
8226 return 0;
8227 }
8228
8229
SOCK_GetTotalCount(SOCK sock,EIO_Event direction)8230 extern TNCBI_BigCount SOCK_GetTotalCount(SOCK sock, EIO_Event direction)
8231 {
8232 if (sock) {
8233 switch (direction) {
8234 case eIO_Read:
8235 return sock->type != eDatagram ? sock->n_in : sock->n_read;
8236 case eIO_Write:
8237 return sock->type != eDatagram ? sock->n_out : sock->n_written;
8238 default:
8239 assert(0);
8240 break;
8241 }
8242 }
8243 return 0;
8244 }
8245
8246
8247
8248 /******************************************************************************
8249 * SOCKET SETTINGS
8250 */
8251
8252
SOCK_SetInterruptOnSignalAPI(ESwitch on_off)8253 extern ESwitch SOCK_SetInterruptOnSignalAPI(ESwitch on_off)
8254 {
8255 ESwitch old = s_InterruptOnSignal;
8256 if (on_off != eDefault)
8257 s_InterruptOnSignal = on_off;
8258 return old;
8259 }
8260
8261
SOCK_SetInterruptOnSignal(SOCK sock,ESwitch on_off)8262 extern ESwitch SOCK_SetInterruptOnSignal(SOCK sock, ESwitch on_off)
8263 {
8264 ESwitch old = (ESwitch) sock->i_on_sig;
8265 sock->i_on_sig = on_off;
8266 return old;
8267 }
8268
8269
SOCK_SetReuseAddressAPI(ESwitch on_off)8270 extern ESwitch SOCK_SetReuseAddressAPI(ESwitch on_off)
8271 {
8272 ESwitch old = s_ReuseAddress;
8273 if (on_off != eDefault)
8274 s_ReuseAddress = on_off;
8275 return old;
8276 }
8277
8278
SOCK_SetReuseAddress(SOCK sock,int on_off)8279 extern void SOCK_SetReuseAddress(SOCK sock, int/*bool*/ on_off)
8280 {
8281 if (sock->sock != SOCK_INVALID && !s_SetReuseAddress(sock->sock, on_off)) {
8282 char _id[MAXIDLEN];
8283 int error = SOCK_ERRNO;
8284 const char* strerr = SOCK_STRERROR(error);
8285 CORE_LOGF_ERRNO_EXX(74, eLOG_Warning,
8286 error, strerr ? strerr : "",
8287 ("%s[SOCK::SetReuseAddress] "
8288 " Failed setsockopt(%sREUSEADDR)",
8289 s_ID(sock, _id), on_off ? "" : "NO"));
8290 UTIL_ReleaseBuffer(strerr);
8291 }
8292 }
8293
8294
SOCK_SetDataLoggingAPI(ESwitch log)8295 extern ESwitch SOCK_SetDataLoggingAPI(ESwitch log)
8296 {
8297 ESwitch old = s_Log;
8298 if (log != eDefault)
8299 s_Log = log;
8300 return old;
8301 }
8302
8303
SOCK_SetDataLogging(SOCK sock,ESwitch log)8304 extern ESwitch SOCK_SetDataLogging(SOCK sock, ESwitch log)
8305 {
8306 ESwitch old = (ESwitch) sock->log;
8307 sock->log = log;
8308 return old;
8309 }
8310
8311
8312
8313 /******************************************************************************
8314 * GENERIC POLLABLE API
8315 */
8316
8317
POLLABLE_Poll(size_t n,SPOLLABLE_Poll polls[],const STimeout * timeout,size_t * n_ready)8318 extern EIO_Status POLLABLE_Poll(size_t n,
8319 SPOLLABLE_Poll polls[],
8320 const STimeout* timeout,
8321 size_t* n_ready)
8322 {
8323 return SOCK_Poll(n, (SSOCK_Poll*) polls, timeout, n_ready);
8324 }
8325
8326
POLLABLE_FromTRIGGER(TRIGGER trigger)8327 extern POLLABLE POLLABLE_FromTRIGGER(TRIGGER trigger)
8328 {
8329 assert(!trigger || trigger->type == eTrigger);
8330 return (POLLABLE) trigger;
8331 }
8332
8333
POLLABLE_FromLSOCK(LSOCK lsock)8334 extern POLLABLE POLLABLE_FromLSOCK(LSOCK lsock)
8335 {
8336 assert(!lsock || lsock->type == eListening);
8337 return (POLLABLE) lsock;
8338 }
8339
8340
POLLABLE_FromSOCK(SOCK sock)8341 extern POLLABLE POLLABLE_FromSOCK(SOCK sock)
8342 {
8343 assert(!sock || (sock->type & eSocket));
8344 return (POLLABLE) sock;
8345 }
8346
8347
POLLABLE_ToTRIGGER(POLLABLE poll)8348 extern TRIGGER POLLABLE_ToTRIGGER(POLLABLE poll)
8349 {
8350 TRIGGER trigger = (TRIGGER) poll;
8351 return trigger && trigger->type == eTrigger ? trigger : 0;
8352 }
8353
8354
POLLABLE_ToLSOCK(POLLABLE poll)8355 extern LSOCK POLLABLE_ToLSOCK(POLLABLE poll)
8356 {
8357 LSOCK lsock = (LSOCK) poll;
8358 return lsock && lsock->type == eListening ? lsock : 0;
8359 }
8360
8361
POLLABLE_ToSOCK(POLLABLE poll)8362 extern SOCK POLLABLE_ToSOCK(POLLABLE poll)
8363 {
8364 SOCK sock = (SOCK) poll;
8365 return sock && (sock->type & eSocket) ? sock : 0;
8366 }
8367
8368
8369
8370 /******************************************************************************
8371 * BSD-LIKE INTERFACE
8372 */
8373
8374
SOCK_ntoa(unsigned int host,char * buf,size_t bufsize)8375 extern int SOCK_ntoa(unsigned int host,
8376 char* buf,
8377 size_t bufsize)
8378 {
8379 if (buf && bufsize) {
8380 char x_buf[16/*sizeof("255.255.255.255")*/];
8381 const unsigned char* b = (const unsigned char*) &host;
8382 int len = sprintf(x_buf, "%u.%u.%u.%u", b[0], b[1], b[2], b[3]);
8383 assert(0 < len && (size_t) len < sizeof(x_buf));
8384 if ((size_t) len < bufsize) {
8385 memcpy(buf, x_buf, (size_t) len + 1);
8386 return 0/*success*/;
8387 }
8388 *buf = '\0';
8389 }
8390 return -1/*failed*/;
8391 }
8392
8393
SOCK_isip(const char * str)8394 extern int/*bool*/ SOCK_isip(const char* str)
8395 {
8396 return SOCK_isipEx(str, 0/*nofullquad*/);
8397 }
8398
8399
SOCK_isipEx(const char * str,int fullquad)8400 extern int/*bool*/ SOCK_isipEx(const char* str, int/*bool*/ fullquad)
8401 {
8402 unsigned long val;
8403 int dots;
8404
8405 if (!str || !*str)
8406 return 0/*false*/;
8407
8408 dots = 0;
8409 for (;;) {
8410 char* e;
8411 if (!isdigit((unsigned char)(*str)))
8412 return 0/*false*/;
8413 errno = 0;
8414 val = strtoul(str, &e, 0);
8415 if (errno || str == e)
8416 return 0/*false*/;
8417 str = e;
8418 if (*str != '.')
8419 break;
8420 if (++dots > 3)
8421 return 0/*false*/;
8422 if (val > 255)
8423 return 0/*false*/;
8424 ++str;
8425 }
8426
8427 return !*str &&
8428 (!fullquad || dots == 3) && val <= (0xFFFFFFFFUL >> (dots << 3));
8429 }
8430
8431
SOCK_IsLoopbackAddress(unsigned int ip)8432 extern int/*bool*/ SOCK_IsLoopbackAddress(unsigned int ip)
8433 {
8434 if (ip == htonl(INADDR_LOOPBACK))
8435 return 1/*true*/;
8436 /* 127/8 */
8437 if (ip) {
8438 unsigned int addr = ntohl(ip);
8439 #if defined(IN_CLASSA) && defined(IN_CLASSA_NET) && defined(IN_CLASSA_NSHIFT)
8440 return IN_CLASSA(addr)
8441 && (addr & IN_CLASSA_NET) == (IN_LOOPBACKNET << IN_CLASSA_NSHIFT);
8442 #else
8443 return !((addr & 0xFF000000) ^ (INADDR_LOOPBACK-1));
8444 #endif /*IN_CLASSA && IN_CLASSA_NET && IN_CLASSA_NSHIFT*/
8445 }
8446 return 0/*false*/;
8447 }
8448
8449
SOCK_HostToNetLong(unsigned int value)8450 extern unsigned int SOCK_HostToNetLong(unsigned int value)
8451 {
8452 return htonl(value);
8453 }
8454
8455
SOCK_HostToNetShort(unsigned short value)8456 extern unsigned short SOCK_HostToNetShort(unsigned short value)
8457 {
8458 return htons(value);
8459 }
8460
8461
SOCK_htonl(unsigned int value)8462 extern unsigned int SOCK_htonl(unsigned int value)
8463 {
8464 return htonl(value);
8465 }
8466
8467
SOCK_htons(unsigned short value)8468 extern unsigned short SOCK_htons(unsigned short value)
8469 {
8470 return htons(value);
8471 }
8472
8473
SOCK_gethostnameEx(char * buf,size_t bufsize,ESwitch log)8474 extern int SOCK_gethostnameEx(char* buf, size_t bufsize, ESwitch log)
8475 {
8476 assert(buf && bufsize > 0);
8477
8478 /* initialize internals */
8479 if (s_InitAPI(0) != eIO_Success) {
8480 buf[0] = buf[bufsize - 1] = '\0';
8481 return -1/*failure*/;
8482 }
8483
8484 return s_gethostname(buf, bufsize, log == eDefault ? s_Log : log);
8485 }
8486
8487
SOCK_gethostname(char * buf,size_t bufsize)8488 extern int SOCK_gethostname(char* buf, size_t bufsize)
8489 {
8490 return SOCK_gethostnameEx(buf, bufsize, s_Log);
8491 }
8492
8493
SOCK_gethostbynameEx(const char * hostname,ESwitch log)8494 extern unsigned int SOCK_gethostbynameEx(const char* hostname, ESwitch log)
8495 {
8496 /* initialize internals */
8497 if (s_InitAPI(0) != eIO_Success)
8498 return 0;
8499
8500 return s_gethostbyname(hostname, 0, log == eDefault ? s_Log : log);
8501 }
8502
8503
SOCK_gethostbyname(const char * hostname)8504 extern unsigned int SOCK_gethostbyname(const char* hostname)
8505 {
8506 return SOCK_gethostbynameEx(hostname, s_Log);
8507 }
8508
8509
SOCK_gethostbyaddrEx(unsigned int host,char * buf,size_t bufsize,ESwitch log)8510 extern const char* SOCK_gethostbyaddrEx(unsigned int host,
8511 char* buf,
8512 size_t bufsize,
8513 ESwitch log)
8514 {
8515 assert(buf && bufsize > 0);
8516
8517 /* initialize internals */
8518 if (s_InitAPI(0) != eIO_Success) {
8519 *buf = '\0';
8520 return 0;
8521 }
8522
8523 return s_gethostbyaddr(host, buf, bufsize, log == eDefault ? s_Log : log);
8524 }
8525
8526
SOCK_gethostbyaddr(unsigned int host,char * buf,size_t bufsize)8527 extern const char* SOCK_gethostbyaddr(unsigned int host,
8528 char* buf,
8529 size_t bufsize)
8530 {
8531 return SOCK_gethostbyaddrEx(host, buf, bufsize, s_Log);
8532 }
8533
8534
SOCK_GetLoopbackAddress(void)8535 extern unsigned int SOCK_GetLoopbackAddress(void)
8536 {
8537 return SOCK_LOOPBACK;
8538 }
8539
8540
SOCK_GetLocalHostAddress(ESwitch reget)8541 extern unsigned int SOCK_GetLocalHostAddress(ESwitch reget)
8542 {
8543 /* initialize internals */
8544 if (s_InitAPI(0) != eIO_Success)
8545 return 0;
8546
8547 return s_getlocalhostaddress(reget, s_Log);
8548 }
8549
8550
SOCK_StringToHostPortEx(const char * str,unsigned int * host,unsigned short * port,int flag)8551 const char* SOCK_StringToHostPortEx(const char* str,
8552 unsigned int* host,
8553 unsigned short* port,
8554 int/*bool*/ flag)
8555 {
8556 char x_buf[CONN_HOST_LEN + 1];
8557 unsigned short p;
8558 unsigned int h;
8559 const char* s;
8560 size_t len;
8561 size_t n;
8562
8563 if ( host )
8564 *host = 0;
8565 if ( port )
8566 *port = 0;
8567 if (!*str)
8568 return 0;
8569
8570 /* initialize internals */
8571 if (s_InitAPI(0) != eIO_Success)
8572 return 0;
8573
8574 for (s = str; *s; ++s) {
8575 if (isspace((unsigned char)(*s)) || *s == ':')
8576 break;
8577 }
8578 if ((len = (size_t)(s - str)) > sizeof(x_buf) - 1)
8579 return 0;
8580 if (*s == ':') {
8581 long i;
8582 char* e;
8583 if (isspace((unsigned char) s[1]))
8584 return str;
8585 errno = 0;
8586 i = strtol(++s, &e, 10);
8587 if (errno || s == e || i ^ (i & 0xFFFF)
8588 || (*e && !isspace((unsigned char)(*e)))) {
8589 return str;
8590 }
8591 p = (unsigned short) i;
8592 n = (size_t)(e - s);
8593 } else {
8594 p = 0;
8595 n = 0;
8596 }
8597 if (len) {
8598 memcpy(x_buf, str, len);
8599 x_buf[len] = '\0';
8600 if ((h = inet_addr(x_buf)) == htonl(INADDR_NONE)
8601 && !(h = s_gethostbyname(x_buf, 1/*not-IP*/, s_Log))) {
8602 if (!flag)
8603 return str;
8604 h = htonl(INADDR_NONE);
8605 }
8606 if ( host )
8607 *host = h;
8608 }
8609 if (port && p)
8610 *port = p;
8611 return s + n;
8612 }
8613
8614
SOCK_StringToHostPort(const char * str,unsigned int * host,unsigned short * port)8615 extern const char* SOCK_StringToHostPort(const char* str,
8616 unsigned int* host,
8617 unsigned short* port)
8618 {
8619 return SOCK_StringToHostPortEx(str, host, port, 0/*false*/);
8620 }
8621
8622
SOCK_HostPortToString(unsigned int host,unsigned short port,char * buf,size_t bufsize)8623 extern size_t SOCK_HostPortToString(unsigned int host,
8624 unsigned short port,
8625 char* buf,
8626 size_t bufsize)
8627 {
8628 char x_buf[16/*sizeof("255.255.255.255")*/ + 6/*:port#*/];
8629 size_t len;
8630
8631 if (!buf || !bufsize)
8632 return 0;
8633 if (!host) {
8634 *x_buf = '\0';
8635 len = 0;
8636 } else if (SOCK_ntoa(host, x_buf, sizeof(x_buf)) != 0) {
8637 *buf = '\0';
8638 return 0;
8639 } else
8640 len = strlen(x_buf);
8641 if (port || !host)
8642 len += (size_t) sprintf(x_buf + len, ":%hu", port);
8643 assert(len < sizeof(x_buf));
8644 if (len >= bufsize) {
8645 *buf = '\0';
8646 return 0;
8647 }
8648 memcpy(buf, x_buf, len + 1);
8649 return len;
8650 }
8651
8652
8653
8654 /******************************************************************************
8655 * SECURE SOCKET LAYER SUPPORT
8656 */
8657
8658
SOCK_SetupSSLInternal(FSSLSetup setup,int init)8659 void SOCK_SetupSSLInternal(FSSLSetup setup, int/*bool*/ init)
8660 {
8661 CORE_LOCK_WRITE;
8662
8663 if (!setup && !init)
8664 x_ShutdownSSL();
8665 else if (s_SSLSetup != setup || (s_SSL && init)) {
8666 if (s_SSLSetup) {
8667 const char* verb;
8668 if (!setup && init) {
8669 s_SSL = 0; /* NB: race / memory leak if was non-NULL ! */
8670 verb = "Must not";
8671 } else
8672 verb = "Cannot";
8673 CORE_UNLOCK;
8674 CORE_LOGF(eLOG_Critical, ("%s reset SSL while it is in use",verb));
8675 return;
8676 }
8677 assert(!s_SSL);
8678 s_SSLSetup = s_Initialized < 0 ? 0 : setup;
8679 }
8680 g_CORE_Set |= eCORE_SetSSL;
8681
8682 CORE_UNLOCK;
8683 }
8684
8685
SOCK_SetupSSL(FSSLSetup setup)8686 extern void SOCK_SetupSSL(FSSLSetup setup)
8687 {
8688 SOCK_SetupSSLInternal(setup, 0/*false*/);
8689 }
8690
8691
SOCK_SetupSSLEx(FSSLSetup setup)8692 extern EIO_Status SOCK_SetupSSLEx(FSSLSetup setup)
8693 {
8694 SOCK_SetupSSLInternal(setup, 0/*false*/);
8695 return setup ? s_InitAPI(1/*secure*/) : eIO_Success;
8696 }
8697
8698
SOCK_SSLName(void)8699 extern const char* SOCK_SSLName(void)
8700 {
8701 return !s_SSLSetup ? 0 : !s_SSL ? "" : s_SSL->Name;
8702 }
8703