1 /*
2 * tclUnixSock.c --
3 *
4 * This file contains Unix-specific socket related code.
5 *
6 * Copyright © 1995 Sun Microsystems, Inc.
7 *
8 * See the file "license.terms" for information on usage and redistribution of
9 * this file, and for a DISCLAIMER OF ALL WARRANTIES.
10 */
11
12 #include "tclInt.h"
13
14 /*
15 * Helper macros to make parts of this file clearer. The macros do exactly
16 * what they say on the tin. :-) They also only ever refer to their arguments
17 * once, and so can be used without regard to side effects.
18 */
19
20 #define SET_BITS(var, bits) ((var) |= (bits))
21 #define CLEAR_BITS(var, bits) ((var) &= ~(bits))
22 #define GOT_BITS(var, bits) (((var) & (bits)) != 0)
23
24 /* "sock" + a pointer in hex + \0 */
25 #define SOCK_CHAN_LENGTH (4 + sizeof(void *) * 2 + 1)
26 #define SOCK_TEMPLATE "sock%lx"
27
28 #undef SOCKET /* Possible conflict with win32 SOCKET */
29
30 /*
31 * This is needed to comply with the strict aliasing rules of GCC, but it also
32 * simplifies casting between the different sockaddr types.
33 */
34
35 typedef union {
36 struct sockaddr sa;
37 struct sockaddr_in sa4;
38 struct sockaddr_in6 sa6;
39 struct sockaddr_storage sas;
40 } address;
41
42 /*
43 * This structure describes per-instance state of a tcp based channel.
44 */
45
46 typedef struct TcpState TcpState;
47
48 typedef struct TcpFdList {
49 TcpState *statePtr;
50 int fd;
51 struct TcpFdList *next;
52 } TcpFdList;
53
54 struct TcpState {
55 Tcl_Channel channel; /* Channel associated with this file. */
56 int testFlags; /* bit field for tests. Is set by testsocket
57 * test procedure */
58 TcpFdList fds; /* The file descriptors of the sockets. */
59 int flags; /* ORed combination of the bitfields defined
60 * below. */
61 int interest; /* Event types of interest */
62
63 /*
64 * Only needed for server sockets
65 */
66
67 Tcl_TcpAcceptProc *acceptProc;
68 /* Proc to call on accept. */
69 void *acceptProcData; /* The data for the accept proc. */
70
71 /*
72 * Only needed for client sockets
73 */
74
75 struct addrinfo *addrlist; /* Addresses to connect to. */
76 struct addrinfo *addr; /* Iterator over addrlist. */
77 struct addrinfo *myaddrlist;/* Local address. */
78 struct addrinfo *myaddr; /* Iterator over myaddrlist. */
79 int filehandlers; /* Caches FileHandlers that get set up while
80 * an async socket is not yet connected. */
81 int connectError; /* Cache SO_ERROR of async socket. */
82 int cachedBlocking; /* Cache blocking mode of async socket. */
83 };
84
85 /*
86 * These bits may be ORed together into the "flags" field of a TcpState
87 * structure.
88 */
89
90 #define TCP_NONBLOCKING (1<<0) /* Socket with non-blocking I/O */
91 #define TCP_ASYNC_CONNECT (1<<1) /* Async connect in progress. */
92 #define TCP_ASYNC_PENDING (1<<4) /* TcpConnect was called to
93 * process an async connect. This
94 * flag indicates that reentry is
95 * still pending */
96 #define TCP_ASYNC_FAILED (1<<5) /* An async connect finally failed */
97
98 /*
99 * These bits may be ORed together into the "testFlags" field of a TcpState
100 * structure.
101 */
102
103 #define TCP_ASYNC_TEST_MODE (1<<0) /* Async testing activated. Do not
104 * automatically continue connection
105 * process. */
106
107 /*
108 * The following defines the maximum length of the listen queue. This is the
109 * number of outstanding yet-to-be-serviced requests for a connection on a
110 * server socket, more than this number of outstanding requests and the
111 * connection request will fail.
112 */
113
114 #ifndef SOMAXCONN
115 # define SOMAXCONN 100
116 #elif (SOMAXCONN < 100)
117 # undef SOMAXCONN
118 # define SOMAXCONN 100
119 #endif /* SOMAXCONN < 100 */
120
121 /*
122 * The following defines how much buffer space the kernel should maintain for
123 * a socket.
124 */
125
126 #define SOCKET_BUFSIZE 4096
127
128 /*
129 * Static routines for this file:
130 */
131
132 static void TcpAsyncCallback(void *clientData, int mask);
133 static int TcpConnect(Tcl_Interp *interp, TcpState *state);
134 static void TcpAccept(void *data, int mask);
135 static int TcpBlockModeProc(void *data, int mode);
136 static int TcpCloseProc(void *instanceData,
137 Tcl_Interp *interp);
138 static int TcpClose2Proc(void *instanceData,
139 Tcl_Interp *interp, int flags);
140 static int TcpGetHandleProc(void *instanceData,
141 int direction, void **handlePtr);
142 static int TcpGetOptionProc(void *instanceData,
143 Tcl_Interp *interp, const char *optionName,
144 Tcl_DString *dsPtr);
145 static int TcpInputProc(void *instanceData, char *buf,
146 int toRead, int *errorCode);
147 static int TcpOutputProc(void *instanceData,
148 const char *buf, int toWrite, int *errorCode);
149 static void TcpThreadActionProc(void *instanceData, int action);
150 static void TcpWatchProc(void *instanceData, int mask);
151 static int WaitForConnect(TcpState *statePtr, int *errorCodePtr);
152 static void WrapNotify(void *clientData, int mask);
153
154 /*
155 * This structure describes the channel type structure for TCP socket
156 * based IO:
157 */
158
159 static const Tcl_ChannelType tcpChannelType = {
160 "tcp", /* Type name. */
161 TCL_CHANNEL_VERSION_5, /* v5 channel */
162 #ifndef TCL_NO_DEPRECATED
163 TcpCloseProc, /* Close proc. */
164 #else
165 TCL_CLOSE2PROC, /* Close proc. */
166 #endif
167 TcpInputProc, /* Input proc. */
168 TcpOutputProc, /* Output proc. */
169 NULL, /* Seek proc. */
170 NULL, /* Set option proc. */
171 TcpGetOptionProc, /* Get option proc. */
172 TcpWatchProc, /* Initialize notifier. */
173 TcpGetHandleProc, /* Get OS handles out of channel. */
174 TcpClose2Proc, /* Close2 proc. */
175 TcpBlockModeProc, /* Set blocking or non-blocking mode.*/
176 NULL, /* flush proc. */
177 NULL, /* handler proc. */
178 NULL, /* wide seek proc. */
179 TcpThreadActionProc, /* thread action proc. */
180 NULL /* truncate proc. */
181 };
182
183 /*
184 * The following variable holds the network name of this host.
185 */
186
187 static TclInitProcessGlobalValueProc InitializeHostName;
188 static ProcessGlobalValue hostName =
189 {0, 0, NULL, NULL, InitializeHostName, NULL, NULL};
190
191 #if 0
192 /* printf debugging */
193 void
194 printaddrinfo(
195 struct addrinfo *addrlist,
196 char *prefix)
197 {
198 char host[NI_MAXHOST], port[NI_MAXSERV];
199 struct addrinfo *ai;
200
201 for (ai = addrlist; ai != NULL; ai = ai->ai_next) {
202 getnameinfo(ai->ai_addr, ai->ai_addrlen,
203 host, sizeof(host), port, sizeof(port),
204 NI_NUMERICHOST|NI_NUMERICSERV);
205 fprintf(stderr,"%s: %s:%s\n", prefix, host, port);
206 }
207 }
208 #endif
209 /*
210 * ----------------------------------------------------------------------
211 *
212 * InitializeHostName --
213 *
214 * This routine sets the process global value of the name of the local
215 * host on which the process is running.
216 *
217 * Results:
218 * None.
219 *
220 * ----------------------------------------------------------------------
221 */
222
223 static void
InitializeHostName(char ** valuePtr,unsigned int * lengthPtr,Tcl_Encoding * encodingPtr)224 InitializeHostName(
225 char **valuePtr,
226 unsigned int *lengthPtr,
227 Tcl_Encoding *encodingPtr)
228 {
229 const char *native = NULL;
230
231 #ifndef NO_UNAME
232 struct utsname u;
233 struct hostent *hp;
234
235 memset(&u, (int) 0, sizeof(struct utsname));
236 if (uname(&u) >= 0) { /* INTL: Native. */
237 hp = TclpGetHostByName(u.nodename); /* INTL: Native. */
238 if (hp == NULL) {
239 /*
240 * Sometimes the nodename is fully qualified, but gets truncated
241 * as it exceeds SYS_NMLN. See if we can just get the immediate
242 * nodename and get a proper answer that way.
243 */
244
245 char *dot = strchr(u.nodename, '.');
246
247 if (dot != NULL) {
248 char *node = (char *)ckalloc(dot - u.nodename + 1);
249
250 memcpy(node, u.nodename, dot - u.nodename);
251 node[dot - u.nodename] = '\0';
252 hp = TclpGetHostByName(node);
253 ckfree(node);
254 }
255 }
256 if (hp != NULL) {
257 native = hp->h_name;
258 } else {
259 native = u.nodename;
260 }
261 }
262 #else /* !NO_UNAME */
263 /*
264 * Uname doesn't exist; try gethostname instead.
265 *
266 * There is no portable macro for the maximum length of host names
267 * returned by gethostbyname(). We should only trust SYS_NMLN if it is at
268 * least 255 + 1 bytes to comply with DNS host name limits.
269 *
270 * Note: SYS_NMLN is a restriction on "uname" not on gethostbyname!
271 *
272 * For example HP-UX 10.20 has SYS_NMLN == 9, while gethostbyname() can
273 * return a fully qualified name from DNS of up to 255 bytes.
274 *
275 * Fix suggested by Viktor Dukhovni (viktor@esm.com)
276 */
277
278 # if defined(SYS_NMLN) && (SYS_NMLEN >= 256)
279 char buffer[SYS_NMLEN];
280 # else
281 char buffer[256];
282 # endif
283
284 if (gethostname(buffer, sizeof(buffer)) >= 0) { /* INTL: Native. */
285 native = buffer;
286 }
287 #endif /* NO_UNAME */
288
289 *encodingPtr = Tcl_GetEncoding(NULL, NULL);
290 if (native) {
291 *lengthPtr = strlen(native);
292 *valuePtr = (char *)ckalloc(*lengthPtr + 1);
293 memcpy(*valuePtr, native, *lengthPtr + 1);
294 } else {
295 *lengthPtr = 0;
296 *valuePtr = (char *)ckalloc(1);
297 *valuePtr[0] = '\0';
298 }
299 }
300
301 /*
302 * ----------------------------------------------------------------------
303 *
304 * Tcl_GetHostName --
305 *
306 * Returns the name of the local host.
307 *
308 * Results:
309 * A string containing the network name for this machine, or an empty
310 * string if we can't figure out the name. The caller must not modify or
311 * free this string.
312 *
313 * Side effects:
314 * Caches the name to return for future calls.
315 *
316 * ----------------------------------------------------------------------
317 */
318
319 const char *
Tcl_GetHostName(void)320 Tcl_GetHostName(void)
321 {
322 return Tcl_GetString(TclGetProcessGlobalValue(&hostName));
323 }
324
325 /*
326 * ----------------------------------------------------------------------
327 *
328 * TclpHasSockets --
329 *
330 * Detect if sockets are available on this platform.
331 *
332 * Results:
333 * Returns TCL_OK.
334 *
335 * Side effects:
336 * None.
337 *
338 * ----------------------------------------------------------------------
339 */
340
341 int
TclpHasSockets(TCL_UNUSED (Tcl_Interp *))342 TclpHasSockets(
343 TCL_UNUSED(Tcl_Interp *))
344 {
345 return TCL_OK;
346 }
347
348 /*
349 * ----------------------------------------------------------------------
350 *
351 * TclpFinalizeSockets --
352 *
353 * Performs per-thread socket subsystem finalization.
354 *
355 * Results:
356 * None.
357 *
358 * Side effects:
359 * None.
360 *
361 * ----------------------------------------------------------------------
362 */
363
364 void
TclpFinalizeSockets(void)365 TclpFinalizeSockets(void)
366 {
367 return;
368 }
369
370 /*
371 * ----------------------------------------------------------------------
372 *
373 * TcpBlockModeProc --
374 *
375 * This function is invoked by the generic IO level to set blocking and
376 * nonblocking mode on a TCP socket based channel.
377 *
378 * Results:
379 * 0 if successful, errno when failed.
380 *
381 * Side effects:
382 * Sets the device into blocking or nonblocking mode.
383 *
384 * ----------------------------------------------------------------------
385 */
386
387 static int
TcpBlockModeProc(void * instanceData,int mode)388 TcpBlockModeProc(
389 void *instanceData, /* Socket state. */
390 int mode) /* The mode to set. Can be one of
391 * TCL_MODE_BLOCKING or
392 * TCL_MODE_NONBLOCKING. */
393 {
394 TcpState *statePtr = (TcpState *)instanceData;
395
396 if (mode == TCL_MODE_BLOCKING) {
397 CLEAR_BITS(statePtr->flags, TCP_NONBLOCKING);
398 } else {
399 SET_BITS(statePtr->flags, TCP_NONBLOCKING);
400 }
401 if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
402 statePtr->cachedBlocking = mode;
403 return 0;
404 }
405 if (TclUnixSetBlockingMode(statePtr->fds.fd, mode) < 0) {
406 return errno;
407 }
408 return 0;
409 }
410
411 /*
412 * ----------------------------------------------------------------------
413 *
414 * WaitForConnect --
415 *
416 * Check the state of an async connect process. If a connection attempt
417 * terminated, process it, which may finalize it or may start the next
418 * attempt. If a connect error occures, it is saved in
419 * statePtr->connectError to be reported by 'fconfigure -error'.
420 *
421 * There are two modes of operation, defined by errorCodePtr:
422 * * non-NULL: Called by explicite read/write command. Blocks if the
423 * socket is blocking.
424 * May return two error codes:
425 * * EWOULDBLOCK: if connect is still in progress
426 * * ENOTCONN: if connect failed. This would be the error message
427 * of a rect or sendto syscall so this is emulated here.
428 * * NULL: Called by a backround operation. Do not block and do not
429 * return any error code.
430 *
431 * Results:
432 * 0 if the connection has completed, -1 if still in progress or there is
433 * an error.
434 *
435 * Side effects:
436 * Processes socket events off the system queue. May process
437 * asynchroneous connects.
438 *
439 *----------------------------------------------------------------------
440 */
441
442 static int
WaitForConnect(TcpState * statePtr,int * errorCodePtr)443 WaitForConnect(
444 TcpState *statePtr, /* State of the socket. */
445 int *errorCodePtr)
446 {
447 int timeout;
448
449 /*
450 * Check if an async connect failed already and error reporting is
451 * demanded, return the error ENOTCONN
452 */
453
454 if (errorCodePtr != NULL && GOT_BITS(statePtr->flags, TCP_ASYNC_FAILED)) {
455 *errorCodePtr = ENOTCONN;
456 return -1;
457 }
458
459 /*
460 * Check if an async connect is running. If not return ok
461 */
462
463 if (!GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
464 return 0;
465 }
466
467 /*
468 * In socket test mode do not continue with the connect.
469 * Exceptions are:
470 * - Call by recv/send and blocking socket
471 * (errorCodePtr != NULL && !GOT_BITS(flags, TCP_NONBLOCKING))
472 */
473
474 if (GOT_BITS(statePtr->testFlags, TCP_ASYNC_TEST_MODE)
475 && !(errorCodePtr != NULL
476 && !GOT_BITS(statePtr->flags, TCP_NONBLOCKING))) {
477 *errorCodePtr = EWOULDBLOCK;
478 return -1;
479 }
480
481 if (errorCodePtr == NULL || GOT_BITS(statePtr->flags, TCP_NONBLOCKING)) {
482 timeout = 0;
483 } else {
484 timeout = -1;
485 }
486 do {
487 if (TclUnixWaitForFile(statePtr->fds.fd,
488 TCL_WRITABLE | TCL_EXCEPTION, timeout) != 0) {
489 TcpConnect(NULL, statePtr);
490 }
491
492 /*
493 * Do this only once in the nonblocking case and repeat it until the
494 * socket is final when blocking.
495 */
496 } while (timeout == -1 && GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT));
497
498 if (errorCodePtr != NULL) {
499 if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
500 *errorCodePtr = EAGAIN;
501 return -1;
502 } else if (statePtr->connectError != 0) {
503 *errorCodePtr = ENOTCONN;
504 return -1;
505 }
506 }
507 return 0;
508 }
509
510 /*
511 *----------------------------------------------------------------------
512 *
513 * TcpInputProc --
514 *
515 * This function is invoked by the generic IO level to read input from a
516 * TCP socket based channel.
517 *
518 * NOTE: We cannot share code with FilePipeInputProc because here we must
519 * use recv to obtain the input from the channel, not read.
520 *
521 * Results:
522 * The number of bytes read is returned or -1 on error. An output
523 * argument contains the POSIX error code on error, or zero if no error
524 * occurred.
525 *
526 * Side effects:
527 * Reads input from the input device of the channel.
528 *
529 *----------------------------------------------------------------------
530 */
531
532 static int
TcpInputProc(void * instanceData,char * buf,int bufSize,int * errorCodePtr)533 TcpInputProc(
534 void *instanceData, /* Socket state. */
535 char *buf, /* Where to store data read. */
536 int bufSize, /* How much space is available in the
537 * buffer? */
538 int *errorCodePtr) /* Where to store error code. */
539 {
540 TcpState *statePtr = (TcpState *)instanceData;
541 int bytesRead;
542
543 *errorCodePtr = 0;
544 if (WaitForConnect(statePtr, errorCodePtr) != 0) {
545 return -1;
546 }
547 bytesRead = recv(statePtr->fds.fd, buf, (size_t) bufSize, 0);
548 if (bytesRead >= 0) {
549 return bytesRead;
550 }
551 if (errno == ECONNRESET) {
552 /*
553 * Turn ECONNRESET into a soft EOF condition.
554 */
555
556 return 0;
557 }
558 *errorCodePtr = errno;
559 return -1;
560 }
561
562 /*
563 *----------------------------------------------------------------------
564 *
565 * TcpOutputProc --
566 *
567 * This function is invoked by the generic IO level to write output to a
568 * TCP socket based channel.
569 *
570 * NOTE: We cannot share code with FilePipeOutputProc because here we
571 * must use send, not write, to get reliable error reporting.
572 *
573 * Results:
574 * The number of bytes written is returned. An output argument is set to
575 * a POSIX error code if an error occurred, or zero.
576 *
577 * Side effects:
578 * Writes output on the output device of the channel.
579 *
580 *----------------------------------------------------------------------
581 */
582
583 static int
TcpOutputProc(void * instanceData,const char * buf,int toWrite,int * errorCodePtr)584 TcpOutputProc(
585 void *instanceData, /* Socket state. */
586 const char *buf, /* The data buffer. */
587 int toWrite, /* How many bytes to write? */
588 int *errorCodePtr) /* Where to store error code. */
589 {
590 TcpState *statePtr = (TcpState *)instanceData;
591 int written;
592
593 *errorCodePtr = 0;
594 if (WaitForConnect(statePtr, errorCodePtr) != 0) {
595 return -1;
596 }
597 written = send(statePtr->fds.fd, buf, (size_t) toWrite, 0);
598
599 if (written >= 0) {
600 return written;
601 }
602 *errorCodePtr = errno;
603 return -1;
604 }
605
606 /*
607 *----------------------------------------------------------------------
608 *
609 * TcpCloseProc --
610 *
611 * This function is invoked by the generic IO level to perform
612 * channel-type-specific cleanup when a TCP socket based channel is
613 * closed.
614 *
615 * Results:
616 * 0 if successful, the value of errno if failed.
617 *
618 * Side effects:
619 * Closes the socket of the channel.
620 *
621 *----------------------------------------------------------------------
622 */
623
624 static int
TcpCloseProc(void * instanceData,TCL_UNUSED (Tcl_Interp *))625 TcpCloseProc(
626 void *instanceData, /* The socket to close. */
627 TCL_UNUSED(Tcl_Interp *))
628 {
629 TcpState *statePtr = (TcpState *)instanceData;
630 int errorCode = 0;
631 TcpFdList *fds;
632
633 /*
634 * Delete a file handler that may be active for this socket if this is a
635 * server socket - the file handler was created automatically by Tcl as
636 * part of the mechanism to accept new client connections. Channel
637 * handlers are already deleted in the generic IO channel closing code
638 * that called this function, so we do not have to delete them here.
639 */
640
641 for (fds = &statePtr->fds; fds != NULL; fds = fds->next) {
642 if (fds->fd < 0) {
643 continue;
644 }
645 Tcl_DeleteFileHandler(fds->fd);
646 if (close(fds->fd) < 0) {
647 errorCode = errno;
648 }
649
650 }
651 fds = statePtr->fds.next;
652 while (fds != NULL) {
653 TcpFdList *next = fds->next;
654
655 ckfree(fds);
656 fds = next;
657 }
658 if (statePtr->addrlist != NULL) {
659 freeaddrinfo(statePtr->addrlist);
660 }
661 if (statePtr->myaddrlist != NULL) {
662 freeaddrinfo(statePtr->myaddrlist);
663 }
664 ckfree(statePtr);
665 return errorCode;
666 }
667
668 /*
669 *----------------------------------------------------------------------
670 *
671 * TcpClose2Proc --
672 *
673 * This function is called by the generic IO level to perform the channel
674 * type specific part of a half-close: namely, a shutdown() on a socket.
675 *
676 * Results:
677 * 0 if successful, the value of errno if failed.
678 *
679 * Side effects:
680 * Shuts down one side of the socket.
681 *
682 *----------------------------------------------------------------------
683 */
684
685 static int
TcpClose2Proc(void * instanceData,TCL_UNUSED (Tcl_Interp *),int flags)686 TcpClose2Proc(
687 void *instanceData, /* The socket to close. */
688 TCL_UNUSED(Tcl_Interp *),
689 int flags) /* Flags that indicate which side to close. */
690 {
691 TcpState *statePtr = (TcpState *)instanceData;
692 int readError = 0;
693 int writeError = 0;
694
695 /*
696 * Shutdown the OS socket handle.
697 */
698 if ((flags & (TCL_CLOSE_READ|TCL_CLOSE_WRITE)) == 0) {
699 return TcpCloseProc(instanceData, NULL);
700 }
701 if ((flags & TCL_CLOSE_READ) && (shutdown(statePtr->fds.fd, SHUT_RD) < 0)) {
702 readError = errno;
703 }
704 if ((flags & TCL_CLOSE_WRITE) && (shutdown(statePtr->fds.fd, SHUT_WR) < 0)) {
705 writeError = errno;
706 }
707 return (readError != 0) ? readError : writeError;
708 }
709
710 /*
711 *----------------------------------------------------------------------
712 *
713 * TcpHostPortList --
714 *
715 * This function is called by the -gethostname and -getpeername switches
716 * of TcpGetOptionProc() to add three list elements with the textual
717 * representation of the given address to the given DString.
718 *
719 * Results:
720 * None.
721 *
722 * Side effects:
723 * Adds three elements do dsPtr
724 *
725 *----------------------------------------------------------------------
726 */
727
728 #ifndef NEED_FAKE_RFC2553
729 #if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
730 #pragma GCC diagnostic push
731 #pragma GCC diagnostic ignored "-Wstrict-aliasing"
732 #endif
733 static inline int
IPv6AddressNeedsNumericRendering(struct in6_addr addr)734 IPv6AddressNeedsNumericRendering(
735 struct in6_addr addr)
736 {
737 if (IN6_ARE_ADDR_EQUAL(&addr, &in6addr_any)) {
738 return 1;
739 }
740
741 /*
742 * The IN6_IS_ADDR_V4MAPPED macro has a problem with aliasing warnings on
743 * at least some versions of OSX.
744 */
745
746 if (!IN6_IS_ADDR_V4MAPPED(&addr)) {
747 return 0;
748 }
749
750 return (addr.s6_addr[12] == 0 && addr.s6_addr[13] == 0
751 && addr.s6_addr[14] == 0 && addr.s6_addr[15] == 0);
752 }
753 #if defined (__clang__) || ((__GNUC__) && ((__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ > 5))))
754 #pragma GCC diagnostic pop
755 #endif
756 #endif /* NEED_FAKE_RFC2553 */
757
758 static void
TcpHostPortList(Tcl_Interp * interp,Tcl_DString * dsPtr,address addr,socklen_t salen)759 TcpHostPortList(
760 Tcl_Interp *interp,
761 Tcl_DString *dsPtr,
762 address addr,
763 socklen_t salen)
764 {
765 #define SUPPRESS_RDNS_VAR "::tcl::unsupported::noReverseDNS"
766 char host[NI_MAXHOST], nhost[NI_MAXHOST], nport[NI_MAXSERV];
767 int flags = 0;
768
769 getnameinfo(&addr.sa, salen, nhost, sizeof(nhost), nport, sizeof(nport),
770 NI_NUMERICHOST | NI_NUMERICSERV);
771 Tcl_DStringAppendElement(dsPtr, nhost);
772
773 /*
774 * We don't want to resolve INADDR_ANY and sin6addr_any; they can
775 * sometimes cause problems (and never have a name).
776 */
777
778 if (addr.sa.sa_family == AF_INET) {
779 if (addr.sa4.sin_addr.s_addr == INADDR_ANY) {
780 flags |= NI_NUMERICHOST;
781 }
782 #ifndef NEED_FAKE_RFC2553
783 } else if (addr.sa.sa_family == AF_INET6) {
784 if (IPv6AddressNeedsNumericRendering(addr.sa6.sin6_addr)) {
785 flags |= NI_NUMERICHOST;
786 }
787 #endif /* NEED_FAKE_RFC2553 */
788 }
789
790 /*
791 * Check if reverse DNS has been switched off globally.
792 */
793
794 if (interp != NULL &&
795 Tcl_GetVar2(interp, SUPPRESS_RDNS_VAR, NULL, 0) != NULL) {
796 flags |= NI_NUMERICHOST;
797 }
798 if (getnameinfo(&addr.sa, salen, host, sizeof(host), NULL, 0,
799 flags) == 0) {
800 /*
801 * Reverse mapping worked.
802 */
803
804 Tcl_DStringAppendElement(dsPtr, host);
805 } else {
806 /*
807 * Reverse mapping failed - use the numeric rep once more.
808 */
809
810 Tcl_DStringAppendElement(dsPtr, nhost);
811 }
812 Tcl_DStringAppendElement(dsPtr, nport);
813 }
814
815 /*
816 *----------------------------------------------------------------------
817 *
818 * TcpGetOptionProc --
819 *
820 * Computes an option value for a TCP socket based channel, or a list of
821 * all options and their values.
822 *
823 * Note: This code is based on code contributed by John Haxby.
824 *
825 * Results:
826 * A standard Tcl result. The value of the specified option or a list of
827 * all options and their values is returned in the supplied DString. Sets
828 * Error message if needed.
829 *
830 * Side effects:
831 * None.
832 *
833 *----------------------------------------------------------------------
834 */
835
836 static int
TcpGetOptionProc(void * instanceData,Tcl_Interp * interp,const char * optionName,Tcl_DString * dsPtr)837 TcpGetOptionProc(
838 void *instanceData, /* Socket state. */
839 Tcl_Interp *interp, /* For error reporting - can be NULL. */
840 const char *optionName, /* Name of the option to retrieve the value
841 * for, or NULL to get all options and their
842 * values. */
843 Tcl_DString *dsPtr) /* Where to store the computed value;
844 * initialized by caller. */
845 {
846 TcpState *statePtr = (TcpState *)instanceData;
847 size_t len = 0;
848
849 WaitForConnect(statePtr, NULL);
850
851 if (optionName != NULL) {
852 len = strlen(optionName);
853 }
854
855 if ((len > 1) && (optionName[1] == 'e') &&
856 (strncmp(optionName, "-error", len) == 0)) {
857 socklen_t optlen = sizeof(int);
858
859 if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
860 /*
861 * Suppress errors as long as we are not done.
862 */
863
864 errno = 0;
865 } else if (statePtr->connectError != 0) {
866 errno = statePtr->connectError;
867 statePtr->connectError = 0;
868 } else {
869 int err;
870
871 getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR, (char *) &err,
872 &optlen);
873 errno = err;
874 }
875 if (errno != 0) {
876 Tcl_DStringAppend(dsPtr, Tcl_ErrnoMsg(errno), -1);
877 }
878 return TCL_OK;
879 }
880
881 if ((len > 1) && (optionName[1] == 'c') &&
882 (strncmp(optionName, "-connecting", len) == 0)) {
883 Tcl_DStringAppend(dsPtr,
884 GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT) ? "1" : "0", -1);
885 return TCL_OK;
886 }
887
888 if ((len == 0) || ((len > 1) && (optionName[1] == 'p') &&
889 (strncmp(optionName, "-peername", len) == 0))) {
890 address peername;
891 socklen_t size = sizeof(peername);
892
893 if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
894 /*
895 * In async connect output an empty string
896 */
897
898 if (len == 0) {
899 Tcl_DStringAppendElement(dsPtr, "-peername");
900 Tcl_DStringAppendElement(dsPtr, "");
901 } else {
902 return TCL_OK;
903 }
904 } else if (getpeername(statePtr->fds.fd, &peername.sa, &size) >= 0) {
905 /*
906 * Peername fetch succeeded - output list
907 */
908
909 if (len == 0) {
910 Tcl_DStringAppendElement(dsPtr, "-peername");
911 Tcl_DStringStartSublist(dsPtr);
912 }
913 TcpHostPortList(interp, dsPtr, peername, size);
914 if (len) {
915 return TCL_OK;
916 }
917 Tcl_DStringEndSublist(dsPtr);
918 } else {
919 /*
920 * getpeername failed - but if we were asked for all the options
921 * (len==0), don't flag an error at that point because it could be
922 * an fconfigure request on a server socket (which have no peer).
923 * Same must be done on win&mac.
924 */
925
926 if (len) {
927 if (interp) {
928 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
929 "can't get peername: %s",
930 Tcl_PosixError(interp)));
931 }
932 return TCL_ERROR;
933 }
934 }
935 }
936
937 if ((len == 0) || ((len > 1) && (optionName[1] == 's') &&
938 (strncmp(optionName, "-sockname", len) == 0))) {
939 TcpFdList *fds;
940 address sockname;
941 socklen_t size;
942 int found = 0;
943
944 if (len == 0) {
945 Tcl_DStringAppendElement(dsPtr, "-sockname");
946 Tcl_DStringStartSublist(dsPtr);
947 }
948 if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
949 /*
950 * In async connect output an empty string
951 */
952
953 found = 1;
954 } else {
955 for (fds = &statePtr->fds; fds != NULL; fds = fds->next) {
956 size = sizeof(sockname);
957 if (getsockname(fds->fd, &(sockname.sa), &size) >= 0) {
958 found = 1;
959 TcpHostPortList(interp, dsPtr, sockname, size);
960 }
961 }
962 }
963 if (found) {
964 if (len) {
965 return TCL_OK;
966 }
967 Tcl_DStringEndSublist(dsPtr);
968 } else {
969 if (interp) {
970 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
971 "can't get sockname: %s", Tcl_PosixError(interp)));
972 }
973 return TCL_ERROR;
974 }
975 }
976
977 if (len > 0) {
978 return Tcl_BadChannelOption(interp, optionName,
979 "connecting peername sockname");
980 }
981
982 return TCL_OK;
983 }
984
985 /*
986 * ----------------------------------------------------------------------
987 *
988 * TcpThreadActionProc --
989 *
990 * Handles detach/attach for asynchronously connecting socket.
991 *
992 * Reassigning the file handler associated with thread-related channel
993 * notification, responsible for callbacks (signaling that asynchronous
994 * connection attempt has succeeded or failed).
995 *
996 * Results:
997 * None.
998 *
999 * ----------------------------------------------------------------------
1000 */
1001
1002 static void
TcpThreadActionProc(void * instanceData,int action)1003 TcpThreadActionProc(
1004 void *instanceData,
1005 int action)
1006 {
1007 TcpState *statePtr = (TcpState *)instanceData;
1008
1009 if (GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT)) {
1010 /*
1011 * Async-connecting socket must get reassigned handler if it have been
1012 * transferred to another thread. Remove the handler if the socket is
1013 * not managed by this thread anymore and create new handler (TSD related)
1014 * so the callback will run in the correct thread, bug [f583715154].
1015 */
1016 switch (action) {
1017 case TCL_CHANNEL_THREAD_REMOVE:
1018 CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
1019 Tcl_DeleteFileHandler(statePtr->fds.fd);
1020 break;
1021 case TCL_CHANNEL_THREAD_INSERT:
1022 Tcl_CreateFileHandler(statePtr->fds.fd,
1023 TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback, statePtr);
1024 SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
1025 break;
1026 }
1027 }
1028 }
1029
1030 /*
1031 * ----------------------------------------------------------------------
1032 *
1033 * TcpWatchProc --
1034 *
1035 * Initialize the notifier to watch the fd from this channel.
1036 *
1037 * Results:
1038 * None.
1039 *
1040 * Side effects:
1041 * Sets up the notifier so that a future event on the channel will be
1042 * seen by Tcl.
1043 *
1044 * ----------------------------------------------------------------------
1045 */
1046
1047 static void
WrapNotify(void * clientData,int mask)1048 WrapNotify(
1049 void *clientData,
1050 int mask)
1051 {
1052 TcpState *statePtr = (TcpState *) clientData;
1053 int newmask = mask & statePtr->interest;
1054
1055 if (newmask == 0) {
1056 /*
1057 * There was no overlap between the states the channel is interested
1058 * in notifications for, and the states that are reported present on
1059 * the file descriptor by select(). The only way that can happen is
1060 * when the channel is interested in a writable condition, and only a
1061 * readable state is reported present (see TcpWatchProc() below). In
1062 * that case, signal back to the caller the writable state, which is
1063 * really an error condition. As an extra check on that assumption,
1064 * check for a non-zero value of errno before reporting an artificial
1065 * writable state.
1066 */
1067
1068 if (errno == 0) {
1069 return;
1070 }
1071 newmask = TCL_WRITABLE;
1072 }
1073 Tcl_NotifyChannel(statePtr->channel, newmask);
1074 }
1075
1076 static void
TcpWatchProc(void * instanceData,int mask)1077 TcpWatchProc(
1078 void *instanceData, /* The socket state. */
1079 int mask) /* Events of interest; an OR-ed combination of
1080 * TCL_READABLE, TCL_WRITABLE and
1081 * TCL_EXCEPTION. */
1082 {
1083 TcpState *statePtr = (TcpState *)instanceData;
1084
1085 if (statePtr->acceptProc != NULL) {
1086 /*
1087 * Make sure we don't mess with server sockets since they will never
1088 * be readable or writable at the Tcl level. This keeps Tcl scripts
1089 * from interfering with the -accept behavior (bug #3394732).
1090 */
1091
1092 return;
1093 }
1094
1095 if (GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING)) {
1096 /*
1097 * Async sockets use a FileHandler internally while connecting, so we
1098 * need to cache this request until the connection has succeeded.
1099 */
1100
1101 statePtr->filehandlers = mask;
1102 } else if (mask) {
1103
1104 /*
1105 * Whether it is a bug or feature or otherwise, it is a fact of life
1106 * that on at least some Linux kernels select() fails to report that a
1107 * socket file descriptor is writable when the other end of the socket
1108 * is closed. This is in contrast to the guarantees Tcl makes that
1109 * its channels become writable and fire writable events on an error
1110 * conditon. This has caused a leak of file descriptors in a state of
1111 * background flushing. See Tcl ticket 1758a0b603.
1112 *
1113 * As a workaround, when our caller indicates an interest in writable
1114 * notifications, we must tell the notifier built around select() that
1115 * we are interested in the readable state of the file descriptor as
1116 * well, as that is the only reliable means to get notified of error
1117 * conditions. Then it is the task of WrapNotify() above to untangle
1118 * the meaning of these channel states and report the chan events as
1119 * best it can. We save a copy of the mask passed in to assist with
1120 * that.
1121 */
1122
1123 statePtr->interest = mask;
1124 Tcl_CreateFileHandler(statePtr->fds.fd, mask|TCL_READABLE,
1125 (Tcl_FileProc *) WrapNotify, statePtr);
1126 } else {
1127 Tcl_DeleteFileHandler(statePtr->fds.fd);
1128 }
1129 }
1130
1131 /*
1132 * ----------------------------------------------------------------------
1133 *
1134 * TcpGetHandleProc --
1135 *
1136 * Called from Tcl_GetChannelHandle to retrieve OS handles from inside a
1137 * TCP socket based channel.
1138 *
1139 * Results:
1140 * Returns TCL_OK with the fd in handlePtr, or TCL_ERROR if there is no
1141 * handle for the specified direction.
1142 *
1143 * Side effects:
1144 * None.
1145 *
1146 * ----------------------------------------------------------------------
1147 */
1148
1149 static int
TcpGetHandleProc(void * instanceData,TCL_UNUSED (int),void ** handlePtr)1150 TcpGetHandleProc(
1151 void *instanceData, /* The socket state. */
1152 TCL_UNUSED(int) /*direction*/,
1153 void **handlePtr) /* Where to store the handle. */
1154 {
1155 TcpState *statePtr = (TcpState *)instanceData;
1156
1157 *handlePtr = INT2PTR(statePtr->fds.fd);
1158 return TCL_OK;
1159 }
1160
1161 /*
1162 * ----------------------------------------------------------------------
1163 *
1164 * TcpAsyncCallback --
1165 *
1166 * Called by the event handler that TcpConnect sets up internally for
1167 * [socket -async] to get notified when the asynchronous connection
1168 * attempt has succeeded or failed.
1169 *
1170 * ----------------------------------------------------------------------
1171 */
1172
1173 static void
TcpAsyncCallback(void * clientData,TCL_UNUSED (int))1174 TcpAsyncCallback(
1175 void *clientData, /* The socket state. */
1176 TCL_UNUSED(int) /*mask*/)
1177 {
1178 TcpConnect(NULL, (TcpState *)clientData);
1179 }
1180
1181 /*
1182 * ----------------------------------------------------------------------
1183 *
1184 * TcpConnect --
1185 *
1186 * This function opens a new socket in client mode.
1187 *
1188 * Results:
1189 * TCL_OK, if the socket was successfully connected or an asynchronous
1190 * connection is in progress. If an error occurs, TCL_ERROR is returned
1191 * and an error message is left in interp.
1192 *
1193 * Side effects:
1194 * Opens a socket.
1195 *
1196 * Remarks:
1197 * A single host name may resolve to more than one IP address, e.g. for
1198 * an IPv4/IPv6 dual stack host. For handling asynchronously connecting
1199 * sockets in the background for such hosts, this function can act as a
1200 * coroutine. On the first call, it sets up the control variables for the
1201 * two nested loops over the local and remote addresses. Once the first
1202 * connection attempt is in progress, it sets up itself as a writable
1203 * event handler for that socket, and returns. When the callback occurs,
1204 * control is transferred to the "reenter" label, right after the initial
1205 * return and the loops resume as if they had never been interrupted.
1206 * For synchronously connecting sockets, the loops work the usual way.
1207 *
1208 * ----------------------------------------------------------------------
1209 */
1210
1211 static int
TcpConnect(Tcl_Interp * interp,TcpState * statePtr)1212 TcpConnect(
1213 Tcl_Interp *interp, /* For error reporting; can be NULL. */
1214 TcpState *statePtr)
1215 {
1216 socklen_t optlen;
1217 int async_callback = GOT_BITS(statePtr->flags, TCP_ASYNC_PENDING);
1218 int ret = -1, error = EHOSTUNREACH;
1219 int async = GOT_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
1220 static const int reuseaddr = 1;
1221
1222 if (async_callback) {
1223 goto reenter;
1224 }
1225
1226 for (statePtr->addr = statePtr->addrlist; statePtr->addr != NULL;
1227 statePtr->addr = statePtr->addr->ai_next) {
1228 for (statePtr->myaddr = statePtr->myaddrlist;
1229 statePtr->myaddr != NULL;
1230 statePtr->myaddr = statePtr->myaddr->ai_next) {
1231
1232 /*
1233 * No need to try combinations of local and remote addresses of
1234 * different families.
1235 */
1236
1237 if (statePtr->myaddr->ai_family != statePtr->addr->ai_family) {
1238 continue;
1239 }
1240
1241 /*
1242 * Close the socket if it is still open from the last unsuccessful
1243 * iteration.
1244 */
1245
1246 if (statePtr->fds.fd >= 0) {
1247 close(statePtr->fds.fd);
1248 statePtr->fds.fd = -1;
1249 errno = 0;
1250 }
1251
1252 statePtr->fds.fd = socket(statePtr->addr->ai_family, SOCK_STREAM,
1253 0);
1254 if (statePtr->fds.fd < 0) {
1255 continue;
1256 }
1257
1258 /*
1259 * Set the close-on-exec flag so that the socket will not get
1260 * inherited by child processes.
1261 */
1262
1263 fcntl(statePtr->fds.fd, F_SETFD, FD_CLOEXEC);
1264
1265 /*
1266 * Set kernel space buffering
1267 */
1268
1269 TclSockMinimumBuffers(INT2PTR(statePtr->fds.fd), SOCKET_BUFSIZE);
1270
1271 if (async) {
1272 ret = TclUnixSetBlockingMode(statePtr->fds.fd,
1273 TCL_MODE_NONBLOCKING);
1274 if (ret < 0) {
1275 continue;
1276 }
1277 }
1278
1279 /*
1280 * Must reset the error variable here, before we use it for the
1281 * first time in this iteration.
1282 */
1283
1284 error = 0;
1285
1286 (void) setsockopt(statePtr->fds.fd, SOL_SOCKET, SO_REUSEADDR,
1287 (char *) &reuseaddr, sizeof(reuseaddr));
1288 ret = bind(statePtr->fds.fd, statePtr->myaddr->ai_addr,
1289 statePtr->myaddr->ai_addrlen);
1290 if (ret < 0) {
1291 error = errno;
1292 continue;
1293 }
1294
1295 /*
1296 * Attempt to connect. The connect may fail at present with an
1297 * EINPROGRESS but at a later time it will complete. The caller
1298 * will set up a file handler on the socket if she is interested
1299 * in being informed when the connect completes.
1300 */
1301
1302 ret = connect(statePtr->fds.fd, statePtr->addr->ai_addr,
1303 statePtr->addr->ai_addrlen);
1304 if (ret < 0) {
1305 error = errno;
1306 }
1307 if (ret < 0 && errno == EINPROGRESS) {
1308 Tcl_CreateFileHandler(statePtr->fds.fd,
1309 TCL_WRITABLE | TCL_EXCEPTION, TcpAsyncCallback,
1310 statePtr);
1311 errno = EWOULDBLOCK;
1312 SET_BITS(statePtr->flags, TCP_ASYNC_PENDING);
1313 return TCL_OK;
1314
1315 reenter:
1316 CLEAR_BITS(statePtr->flags, TCP_ASYNC_PENDING);
1317 Tcl_DeleteFileHandler(statePtr->fds.fd);
1318
1319 /*
1320 * Read the error state from the socket to see if the async
1321 * connection has succeeded or failed. As this clears the
1322 * error condition, we cache the status in the socket state
1323 * struct for later retrieval by [fconfigure -error].
1324 */
1325
1326 optlen = sizeof(int);
1327
1328 getsockopt(statePtr->fds.fd, SOL_SOCKET, SO_ERROR,
1329 (char *) &error, &optlen);
1330 errno = error;
1331 }
1332 if (error == 0) {
1333 goto out;
1334 }
1335 }
1336 }
1337
1338 out:
1339 statePtr->connectError = error;
1340 CLEAR_BITS(statePtr->flags, TCP_ASYNC_CONNECT);
1341 if (async_callback) {
1342 /*
1343 * An asynchonous connection has finally succeeded or failed.
1344 */
1345
1346 TcpWatchProc(statePtr, statePtr->filehandlers);
1347 TclUnixSetBlockingMode(statePtr->fds.fd, statePtr->cachedBlocking);
1348
1349 if (error != 0) {
1350 SET_BITS(statePtr->flags, TCP_ASYNC_FAILED);
1351 }
1352
1353 /*
1354 * We need to forward the writable event that brought us here, bcasue
1355 * upon reading of getsockopt(SO_ERROR), at least some OSes clear the
1356 * writable state from the socket, and so a subsequent select() on
1357 * behalf of a script level [fileevent] would not fire. It doesn't
1358 * hurt that this is also called in the successful case and will save
1359 * the event mechanism one roundtrip through select().
1360 */
1361
1362 if (statePtr->cachedBlocking == TCL_MODE_NONBLOCKING) {
1363 Tcl_NotifyChannel(statePtr->channel, TCL_WRITABLE);
1364 }
1365 }
1366 if (error != 0) {
1367 /*
1368 * Failure for either a synchronous connection, or an async one that
1369 * failed before it could enter background mode, e.g. because an
1370 * invalid -myaddr was given.
1371 */
1372
1373 if (interp != NULL) {
1374 errno = error;
1375 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1376 "couldn't open socket: %s", Tcl_PosixError(interp)));
1377 }
1378 return TCL_ERROR;
1379 }
1380 return TCL_OK;
1381 }
1382
1383 /*
1384 *----------------------------------------------------------------------
1385 *
1386 * Tcl_OpenTcpClient --
1387 *
1388 * Opens a TCP client socket and creates a channel around it.
1389 *
1390 * Results:
1391 * The channel or NULL if failed. An error message is returned in the
1392 * interpreter on failure.
1393 *
1394 * Side effects:
1395 * Opens a client socket and creates a new channel.
1396 *
1397 *----------------------------------------------------------------------
1398 */
1399
1400 Tcl_Channel
Tcl_OpenTcpClient(Tcl_Interp * interp,int port,const char * host,const char * myaddr,int myport,int async)1401 Tcl_OpenTcpClient(
1402 Tcl_Interp *interp, /* For error reporting; can be NULL. */
1403 int port, /* Port number to open. */
1404 const char *host, /* Host on which to open port. */
1405 const char *myaddr, /* Client-side address */
1406 int myport, /* Client-side port */
1407 int async) /* If nonzero, attempt to do an asynchronous
1408 * connect. Otherwise we do a blocking
1409 * connect. */
1410 {
1411 TcpState *statePtr;
1412 const char *errorMsg = NULL;
1413 struct addrinfo *addrlist = NULL, *myaddrlist = NULL;
1414 char channelName[SOCK_CHAN_LENGTH];
1415
1416 /*
1417 * Do the name lookups for the local and remote addresses.
1418 */
1419
1420 if (!TclCreateSocketAddress(interp, &addrlist, host, port, 0, &errorMsg)
1421 || !TclCreateSocketAddress(interp, &myaddrlist, myaddr, myport, 1,
1422 &errorMsg)) {
1423 if (addrlist != NULL) {
1424 freeaddrinfo(addrlist);
1425 }
1426 if (interp != NULL) {
1427 Tcl_SetObjResult(interp, Tcl_ObjPrintf(
1428 "couldn't open socket: %s", errorMsg));
1429 }
1430 return NULL;
1431 }
1432
1433 /*
1434 * Allocate a new TcpState for this socket.
1435 */
1436
1437 statePtr = (TcpState *)ckalloc(sizeof(TcpState));
1438 memset(statePtr, 0, sizeof(TcpState));
1439 statePtr->flags = async ? TCP_ASYNC_CONNECT : 0;
1440 statePtr->cachedBlocking = TCL_MODE_BLOCKING;
1441 statePtr->addrlist = addrlist;
1442 statePtr->myaddrlist = myaddrlist;
1443 statePtr->fds.fd = -1;
1444
1445 /*
1446 * Create a new client socket and wrap it in a channel.
1447 */
1448
1449 if (TcpConnect(interp, statePtr) != TCL_OK) {
1450 TcpCloseProc(statePtr, NULL);
1451 return NULL;
1452 }
1453
1454 sprintf(channelName, SOCK_TEMPLATE, (long) statePtr);
1455
1456 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1457 statePtr, TCL_READABLE | TCL_WRITABLE);
1458 if (Tcl_SetChannelOption(interp, statePtr->channel, "-translation",
1459 "auto crlf") == TCL_ERROR) {
1460 Tcl_Close(NULL, statePtr->channel);
1461 return NULL;
1462 }
1463 return statePtr->channel;
1464 }
1465
1466 /*
1467 *----------------------------------------------------------------------
1468 *
1469 * Tcl_MakeTcpClientChannel --
1470 *
1471 * Creates a Tcl_Channel from an existing client TCP socket.
1472 *
1473 * Results:
1474 * The Tcl_Channel wrapped around the preexisting TCP socket.
1475 *
1476 * Side effects:
1477 * None.
1478 *
1479 *----------------------------------------------------------------------
1480 */
1481
1482 Tcl_Channel
Tcl_MakeTcpClientChannel(void * sock)1483 Tcl_MakeTcpClientChannel(
1484 void *sock) /* The socket to wrap up into a channel. */
1485 {
1486 return (Tcl_Channel) TclpMakeTcpClientChannelMode(sock,
1487 TCL_READABLE | TCL_WRITABLE);
1488 }
1489
1490 /*
1491 *----------------------------------------------------------------------
1492 *
1493 * TclpMakeTcpClientChannelMode --
1494 *
1495 * Creates a Tcl_Channel from an existing client TCP socket
1496 * with given mode.
1497 *
1498 * Results:
1499 * The Tcl_Channel wrapped around the preexisting TCP socket.
1500 *
1501 * Side effects:
1502 * None.
1503 *
1504 *----------------------------------------------------------------------
1505 */
1506
1507 void *
TclpMakeTcpClientChannelMode(void * sock,int mode)1508 TclpMakeTcpClientChannelMode(
1509 void *sock, /* The socket to wrap up into a channel. */
1510 int mode) /* ORed combination of TCL_READABLE and
1511 * TCL_WRITABLE to indicate file mode. */
1512 {
1513 TcpState *statePtr;
1514 char channelName[SOCK_CHAN_LENGTH];
1515
1516 statePtr = (TcpState *)ckalloc(sizeof(TcpState));
1517 memset(statePtr, 0, sizeof(TcpState));
1518 statePtr->fds.fd = PTR2INT(sock);
1519 statePtr->flags = 0;
1520
1521 sprintf(channelName, SOCK_TEMPLATE, (long)statePtr);
1522
1523 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1524 statePtr, mode);
1525 if (Tcl_SetChannelOption(NULL, statePtr->channel, "-translation",
1526 "auto crlf") == TCL_ERROR) {
1527 Tcl_Close(NULL, statePtr->channel);
1528 return NULL;
1529 }
1530 return statePtr->channel;
1531 }
1532
1533 /*
1534 *----------------------------------------------------------------------
1535 *
1536 * Tcl_OpenTcpServerEx --
1537 *
1538 * Opens a TCP server socket and creates a channel around it.
1539 *
1540 * Results:
1541 * The channel or NULL if failed. If an error occurred, an error message
1542 * is left in the interp's result if interp is not NULL.
1543 *
1544 * Side effects:
1545 * Opens a server socket and creates a new channel.
1546 *
1547 *----------------------------------------------------------------------
1548 */
1549
1550 Tcl_Channel
Tcl_OpenTcpServerEx(Tcl_Interp * interp,const char * service,const char * myHost,unsigned int flags,Tcl_TcpAcceptProc * acceptProc,void * acceptProcData)1551 Tcl_OpenTcpServerEx(
1552 Tcl_Interp *interp, /* For error reporting - may be NULL. */
1553 const char *service, /* Port number to open. */
1554 const char *myHost, /* Name of local host. */
1555 unsigned int flags, /* Flags. */
1556 Tcl_TcpAcceptProc *acceptProc,
1557 /* Callback for accepting connections from new
1558 * clients. */
1559 void *acceptProcData) /* Data for the callback. */
1560 {
1561 int status = 0, sock = -1, optvalue, port, chosenport;
1562 struct addrinfo *addrlist = NULL, *addrPtr; /* socket address */
1563 TcpState *statePtr = NULL;
1564 char channelName[SOCK_CHAN_LENGTH];
1565 const char *errorMsg = NULL;
1566 TcpFdList *fds = NULL, *newfds;
1567
1568 /*
1569 * Try to record and return the most meaningful error message, i.e. the
1570 * one from the first socket that went the farthest before it failed.
1571 */
1572
1573 enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP;
1574 int my_errno = 0;
1575
1576 /*
1577 * If we were called with port 0 to listen on a random port number, we
1578 * copy the port number from the first member of the addrinfo list to all
1579 * subsequent members, so that IPv4 and IPv6 listen on the same port. This
1580 * might fail to bind() with EADDRINUSE if a port is free on the first
1581 * address family in the list but already used on the other. In this case
1582 * we revert everything we've done so far and start from scratch hoping
1583 * that next time we'll find a port number that is usable on all address
1584 * families. We try this at most MAXRETRY times to avoid an endless loop
1585 * if all ports are taken.
1586 */
1587
1588 int retry = 0;
1589 #define MAXRETRY 10
1590
1591 repeat:
1592 if (retry > 0) {
1593 if (statePtr != NULL) {
1594 TcpCloseProc(statePtr, NULL);
1595 statePtr = NULL;
1596 }
1597 if (addrlist != NULL) {
1598 freeaddrinfo(addrlist);
1599 addrlist = NULL;
1600 }
1601 if (retry >= MAXRETRY) {
1602 goto error;
1603 }
1604 }
1605 retry++;
1606 chosenport = 0;
1607
1608 if (TclSockGetPort(interp, service, "tcp", &port) != TCL_OK) {
1609 errorMsg = "invalid port number";
1610 goto error;
1611 }
1612
1613 if (!TclCreateSocketAddress(interp, &addrlist, myHost, port, 1,
1614 &errorMsg)) {
1615 my_errno = errno;
1616 goto error;
1617 }
1618
1619 for (addrPtr = addrlist; addrPtr != NULL; addrPtr = addrPtr->ai_next) {
1620 sock = socket(addrPtr->ai_family, addrPtr->ai_socktype,
1621 addrPtr->ai_protocol);
1622 if (sock == -1) {
1623 if (howfar < SOCKET) {
1624 howfar = SOCKET;
1625 my_errno = errno;
1626 }
1627 continue;
1628 }
1629
1630 /*
1631 * Set the close-on-exec flag so that the socket will not get
1632 * inherited by child processes.
1633 */
1634
1635 fcntl(sock, F_SETFD, FD_CLOEXEC);
1636
1637 /*
1638 * Set kernel space buffering
1639 */
1640
1641 TclSockMinimumBuffers(INT2PTR(sock), SOCKET_BUFSIZE);
1642
1643 /*
1644 * Set up to reuse server addresses and/or ports if requested.
1645 */
1646
1647 if (GOT_BITS(flags, TCL_TCPSERVER_REUSEADDR)) {
1648 optvalue = 1;
1649 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
1650 (char *) &optvalue, sizeof(optvalue));
1651 }
1652
1653 if (GOT_BITS(flags, TCL_TCPSERVER_REUSEPORT)) {
1654 #ifndef SO_REUSEPORT
1655 /*
1656 * If the platform doesn't support the SO_REUSEPORT flag we can't
1657 * do much beside erroring out.
1658 */
1659
1660 errorMsg = "SO_REUSEPORT isn't supported by this platform";
1661 goto error;
1662 #else
1663 optvalue = 1;
1664 (void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
1665 (char *) &optvalue, sizeof(optvalue));
1666 #endif
1667 }
1668
1669 /*
1670 * Make sure we use the same port number when opening two server
1671 * sockets for IPv4 and IPv6 on a random port.
1672 *
1673 * As sockaddr_in6 uses the same offset and size for the port member
1674 * as sockaddr_in, we can handle both through the IPv4 API.
1675 */
1676
1677 if (port == 0 && chosenport != 0) {
1678 ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
1679 htons(chosenport);
1680 }
1681
1682 #ifdef IPV6_V6ONLY
1683 /*
1684 * Missing on: Solaris 2.8
1685 */
1686
1687 if (addrPtr->ai_family == AF_INET6) {
1688 int v6only = 1;
1689
1690 (void) setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY,
1691 &v6only, sizeof(v6only));
1692 }
1693 #endif /* IPV6_V6ONLY */
1694
1695 status = bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen);
1696 if (status == -1) {
1697 if (howfar < BIND) {
1698 howfar = BIND;
1699 my_errno = errno;
1700 }
1701 close(sock);
1702 sock = -1;
1703 if (port == 0 && errno == EADDRINUSE) {
1704 goto repeat;
1705 }
1706 continue;
1707 }
1708 if (port == 0 && chosenport == 0) {
1709 address sockname;
1710 socklen_t namelen = sizeof(sockname);
1711
1712 /*
1713 * Synchronize port numbers when binding to port 0 of multiple
1714 * addresses.
1715 */
1716
1717 if (getsockname(sock, &sockname.sa, &namelen) >= 0) {
1718 chosenport = ntohs(sockname.sa4.sin_port);
1719 }
1720 }
1721 status = listen(sock, SOMAXCONN);
1722 if (status < 0) {
1723 if (howfar < LISTEN) {
1724 howfar = LISTEN;
1725 my_errno = errno;
1726 }
1727 close(sock);
1728 sock = -1;
1729 if (port == 0 && errno == EADDRINUSE) {
1730 goto repeat;
1731 }
1732 continue;
1733 }
1734 if (statePtr == NULL) {
1735 /*
1736 * Allocate a new TcpState for this socket.
1737 */
1738
1739 statePtr = (TcpState *)ckalloc(sizeof(TcpState));
1740 memset(statePtr, 0, sizeof(TcpState));
1741 statePtr->acceptProc = acceptProc;
1742 statePtr->acceptProcData = acceptProcData;
1743 sprintf(channelName, SOCK_TEMPLATE, (long) statePtr);
1744 newfds = &statePtr->fds;
1745 } else {
1746 newfds = (TcpFdList *)ckalloc(sizeof(TcpFdList));
1747 memset(newfds, (int) 0, sizeof(TcpFdList));
1748 fds->next = newfds;
1749 }
1750 newfds->fd = sock;
1751 newfds->statePtr = statePtr;
1752 fds = newfds;
1753
1754 /*
1755 * Set up the callback mechanism for accepting connections from new
1756 * clients.
1757 */
1758
1759 Tcl_CreateFileHandler(sock, TCL_READABLE, TcpAccept, fds);
1760 }
1761
1762 error:
1763 if (addrlist != NULL) {
1764 freeaddrinfo(addrlist);
1765 }
1766 if (statePtr != NULL) {
1767 statePtr->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1768 statePtr, 0);
1769 return statePtr->channel;
1770 }
1771 if (interp != NULL) {
1772 Tcl_Obj *errorObj = Tcl_NewStringObj("couldn't open socket: ", -1);
1773
1774 if (errorMsg == NULL) {
1775 errno = my_errno;
1776 Tcl_AppendToObj(errorObj, Tcl_PosixError(interp), -1);
1777 } else {
1778 Tcl_AppendToObj(errorObj, errorMsg, -1);
1779 }
1780 Tcl_SetObjResult(interp, errorObj);
1781 }
1782 if (sock != -1) {
1783 close(sock);
1784 }
1785 return NULL;
1786 }
1787
1788 /*
1789 *----------------------------------------------------------------------
1790 *
1791 * TcpAccept --
1792 * Accept a TCP socket connection. This is called by the event loop.
1793 *
1794 * Results:
1795 * None.
1796 *
1797 * Side effects:
1798 * Creates a new connection socket. Calls the registered callback for the
1799 * connection acceptance mechanism.
1800 *
1801 *----------------------------------------------------------------------
1802 */
1803
1804 static void
TcpAccept(void * data,TCL_UNUSED (int))1805 TcpAccept(
1806 void *data, /* Callback token. */
1807 TCL_UNUSED(int) /*mask*/)
1808 {
1809 TcpFdList *fds = (TcpFdList *)data; /* Client data of server socket. */
1810 int newsock; /* The new client socket */
1811 TcpState *newSockState; /* State for new socket. */
1812 address addr; /* The remote address */
1813 socklen_t len; /* For accept interface */
1814 char channelName[SOCK_CHAN_LENGTH];
1815 char host[NI_MAXHOST], port[NI_MAXSERV];
1816
1817 len = sizeof(addr);
1818 newsock = accept(fds->fd, &addr.sa, &len);
1819 if (newsock < 0) {
1820 return;
1821 }
1822
1823 /*
1824 * Set close-on-exec flag to prevent the newly accepted socket from being
1825 * inherited by child processes.
1826 */
1827
1828 (void) fcntl(newsock, F_SETFD, FD_CLOEXEC);
1829
1830 newSockState = (TcpState *)ckalloc(sizeof(TcpState));
1831 memset(newSockState, 0, sizeof(TcpState));
1832 newSockState->flags = 0;
1833 newSockState->fds.fd = newsock;
1834
1835 sprintf(channelName, SOCK_TEMPLATE, (long) newSockState);
1836 newSockState->channel = Tcl_CreateChannel(&tcpChannelType, channelName,
1837 newSockState, TCL_READABLE | TCL_WRITABLE);
1838
1839 Tcl_SetChannelOption(NULL, newSockState->channel, "-translation",
1840 "auto crlf");
1841
1842 if (fds->statePtr->acceptProc != NULL) {
1843 getnameinfo(&addr.sa, len, host, sizeof(host), port, sizeof(port),
1844 NI_NUMERICHOST|NI_NUMERICSERV);
1845 fds->statePtr->acceptProc(fds->statePtr->acceptProcData,
1846 newSockState->channel, host, atoi(port));
1847 }
1848 }
1849
1850 /*
1851 * Local Variables:
1852 * mode: c
1853 * c-basic-offset: 4
1854 * fill-column: 78
1855 * tab-width: 8
1856 * indent-tabs-mode: nil
1857 * End:
1858 */
1859