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