Tcl Source Code

Check-in [ae02accafa]
Login
Bounty program for improvements to Tcl and certain Tcl packages.
Tcl 2019 Conference, Houston/TX, US, Nov 4-8
Send your abstracts to [email protected]
or submit via the online form by Sep 9.

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:This is patch.002 from ticket [0b9d3ba2ba], as first start of tip-456 implementation
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | tip-456
Files: files | file ages | folders
SHA1: ae02accafa567f2bad8a9f1b05ef39a0e2ed3067
User & Date: jan.nijtmans 2016-11-22 10:06:18
Context
2016-11-22
11:21
Added stub entry for tip #456. Documentation and tests still missing. Doesn't conform to TIP yet. check-in: fce8b81c46 user: jan.nijtmans tags: tip-456
10:06
This is patch.002 from ticket [0b9d3ba2ba], as first start ... check-in: ae02accafa user: jan.nijtmans tags: tip-456
2016-11-21
10:15
More internal use of size_t in stead of int. check-in: ef4da65408 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to generic/tclIOCmd.c.

1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
....
1553
1554
1555
1556
1557
1558
1559



1560
1561
1562
1563
1564
1565
1566
....
1596
1597
1598
1599
1600
1601
1602






1603
1604
1605
1606
1607
1608
1609
Tcl_SocketObjCmd(
    ClientData notUsed,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    static const char *const socketOptions[] = {
	"-async", "-myaddr", "-myport", "-server", NULL
    };
    enum socketOptions {
	SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER
    };
    int optionIndex, a, server = 0, port, myport = 0, async = 0;
    const char *host, *myaddr = NULL;
    Tcl_Obj *script = NULL;
    Tcl_Channel chan;

    if (TclpHasSockets(interp) != TCL_OK) {
	return TCL_ERROR;
    }
................................................................................
	    if (a >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"no argument given for -server option", -1));
		return TCL_ERROR;
	    }
	    script = objv[a];
	    break;



	default:
	    Tcl_Panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
	}
    }
    if (server) {
	host = myaddr;		/* NULL implies INADDR_ANY */
	if (myport != 0) {
................................................................................
    if (server) {
	AcceptCallback *acceptCallbackPtr =
		ckalloc(sizeof(AcceptCallback));

	Tcl_IncrRefCount(script);
	acceptCallbackPtr->script = script;
	acceptCallbackPtr->interp = interp;






	chan = Tcl_OpenTcpServer(interp, port, host, AcceptCallbackProc,
		acceptCallbackPtr);
	if (chan == NULL) {
	    Tcl_DecrRefCount(script);
	    ckfree(acceptCallbackPtr);
	    return TCL_ERROR;
	}






|


|

|







 







>
>
>







 







>
>
>
>
>
>







1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
....
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
....
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
Tcl_SocketObjCmd(
    ClientData notUsed,		/* Not used. */
    Tcl_Interp *interp,		/* Current interpreter. */
    int objc,			/* Number of arguments. */
    Tcl_Obj *const objv[])	/* Argument objects. */
{
    static const char *const socketOptions[] = {
	"-async", "-myaddr", "-myport", "-server", "-reuseport", NULL
    };
    enum socketOptions {
	SKT_ASYNC, SKT_MYADDR, SKT_MYPORT, SKT_SERVER, SKT_REUSEPORT
    };
    int optionIndex, a, server = 0, port, myport = 0, async = 0, reuseport = 0;
    const char *host, *myaddr = NULL;
    Tcl_Obj *script = NULL;
    Tcl_Channel chan;

    if (TclpHasSockets(interp) != TCL_OK) {
	return TCL_ERROR;
    }
................................................................................
	    if (a >= objc) {
		Tcl_SetObjResult(interp, Tcl_NewStringObj(
			"no argument given for -server option", -1));
		return TCL_ERROR;
	    }
	    script = objv[a];
	    break;
    case SKT_REUSEPORT:
        reuseport = 1;
        break;
	default:
	    Tcl_Panic("Tcl_SocketObjCmd: bad option index to SocketOptions");
	}
    }
    if (server) {
	host = myaddr;		/* NULL implies INADDR_ANY */
	if (myport != 0) {
................................................................................
    if (server) {
	AcceptCallback *acceptCallbackPtr =
		ckalloc(sizeof(AcceptCallback));

	Tcl_IncrRefCount(script);
	acceptCallbackPtr->script = script;
	acceptCallbackPtr->interp = interp;

    /* Hint for Tcl_OpenTcpServer to set socket option REUSEPORT */
    if(reuseport) {
        port |= (1 << 16);
    }

	chan = Tcl_OpenTcpServer(interp, port, host, AcceptCallbackProc,
		acceptCallbackPtr);
	if (chan == NULL) {
	    Tcl_DecrRefCount(script);
	    ckfree(acceptCallbackPtr);
	    return TCL_ERROR;
	}

Changes to unix/tclUnixSock.c.

109
110
111
112
113
114
115





116
117
118
119
120
121
122
....
1431
1432
1433
1434
1435
1436
1437




1438
1439
1440
1441
1442
1443
1444
....
1507
1508
1509
1510
1511
1512
1513











1514
1515
1516
1517
1518
1519
1520
/*
 * The following defines how much buffer space the kernel should maintain for
 * a socket.
 */

#define SOCKET_BUFSIZE	4096






/*
 * Static routines for this file:
 */

static int		TcpConnect(Tcl_Interp *interp,
                                           TcpState *state);
static void		TcpAccept(ClientData data, int mask);
................................................................................
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[SOCK_CHAN_LENGTH];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;





    /*
     * Try to record and return the most meaningful error message, i.e. the
     * one from the first socket that went the farthest before it failed.
     */

    enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP;
................................................................................
	/*
	 * Set up to reuse server addresses automatically and bind to the
	 * specified port.
	 */

	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
		(char *) &reuseaddr, sizeof(reuseaddr));












        /*
         * Make sure we use the same port number when opening two server
         * sockets for IPv4 and IPv6 on a random port.
         *
         * As sockaddr_in6 uses the same offset and size for the port member
         * as sockaddr_in, we can handle both through the IPv4 API.






>
>
>
>
>







 







>
>
>
>







 







>
>
>
>
>
>
>
>
>
>
>







109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
....
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
....
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
/*
 * The following defines how much buffer space the kernel should maintain for
 * a socket.
 */

#define SOCKET_BUFSIZE	4096

#ifdef SO_REUSEPORT
/* Bitmask to check if the setting of SO_REUSEPORT was requested by the caller. */
#define USE_SOCK_REUSEPORT (1 << 16)
#endif

/*
 * Static routines for this file:
 */

static int		TcpConnect(Tcl_Interp *interp,
                                           TcpState *state);
static void		TcpAccept(ClientData data, int mask);
................................................................................
{
    int status = 0, sock = -1, reuseaddr = 1, chosenport;
    struct addrinfo *addrlist = NULL, *addrPtr;	/* socket address */
    TcpState *statePtr = NULL;
    char channelName[SOCK_CHAN_LENGTH];
    const char *errorMsg = NULL;
    TcpFdList *fds = NULL, *newfds;
#ifdef SO_REUSEPORT
    int reuseport = port & USE_SOCK_REUSEPORT;
    CLEAR_BITS(port, USE_SOCK_REUSEPORT);
#endif

    /*
     * Try to record and return the most meaningful error message, i.e. the
     * one from the first socket that went the farthest before it failed.
     */

    enum { LOOKUP, SOCKET, BIND, LISTEN } howfar = LOOKUP;
................................................................................
	/*
	 * Set up to reuse server addresses automatically and bind to the
	 * specified port.
	 */

	(void) setsockopt(sock, SOL_SOCKET, SO_REUSEADDR,
		(char *) &reuseaddr, sizeof(reuseaddr));

#ifdef SO_REUSEPORT
    /*
     * Set up to allows multiple sockets on the same host to bind to the same port.
     * The flag can be switched on by setting the lowest bit above the valid maximum port (0xffff).
     */
    if(reuseport) {
        (void) setsockopt(sock, SOL_SOCKET, SO_REUSEPORT,
            (char *) &reuseport, sizeof(reuseport));
    }
#endif

        /*
         * Make sure we use the same port number when opening two server
         * sockets for IPv4 and IPv6 on a random port.
         *
         * As sockaddr_in6 uses the same offset and size for the port member
         * as sockaddr_in, we can handle both through the IPv4 API.

Changes to win/tclWinSock.c.

2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
	if (port == 0 && chosenport != 0) {
	    ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
		htons(chosenport);
	}

	/*
	 * Bind to the specified port. Note that we must not call
	 * setsockopt with SO_REUSEADDR because Microsoft allows addresses
	 * to be reused even if they are still in use.
	 *
	 * Bind should not be affected by the socket having already been
	 * set into nonblocking mode. If there is trouble, this is one
	 * place to look for bugs.
	 */

	if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen)






|
|







2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
	if (port == 0 && chosenport != 0) {
	    ((struct sockaddr_in *) addrPtr->ai_addr)->sin_port =
		htons(chosenport);
	}

	/*
	 * Bind to the specified port. Note that we must not call
	 * setsockopt with SO_REUSEADDR or SO_REUSEPORT because Microsoft
	 * allows addresses and ports to be reused even if they are still in use.
	 *
	 * Bind should not be affected by the socket having already been
	 * set into nonblocking mode. If there is trouble, this is one
	 * place to look for bugs.
	 */

	if (bind(sock, addrPtr->ai_addr, addrPtr->ai_addrlen)