Search code examples
socketstcpcross-platform

Simulate a TCP tarpit


I want to simulate test cross-platform connection failures / timeouts, starting with blocking connect()s:

#!/usr/bin/python3

import socket

s = socket.socket()
endpoint = ('localhost', 28813)
s.bind((endpoint))
# listen for connections, accept 0 connections kept waiting (backlog)
# all other connect()s should block indefinitely
s.listen(0)

for i in range(1,1000):
    c = socket.socket()
    c.connect(endpoint)
    # print number of successfully connected sockets
    print(i)

On Linux, it prints "1" and hangs indefinitely (i.e. the behavior I want).
On Windows (Server 2012), it prints "1" and aborts with a ConnectionRefusedError.
On macOS, it prints all numbers from 1 to 128 and then hangs indefinitely.

Thus, I could accept the macOS ignores the backlog parameter and just connect enough sockets for clients to block on new connections.

How can I get Windows to also block connect() attempts?


Solution

  • On Windows, the SO_CONDITIONAL_ACCEPT socket option allows the application to have the incoming connections wait until it's accept()ed. The constant (SO_CONDITIONAL_ACCEPT=0x3002) isn't exposed in the Python module, but can be supplied manually:

    s.bind(endpoint)
    s.setsockopt(socket.SOL_SOCKET, 0x3002, 1)
    s.listen(0)
    

    It's so effective that even the first connect is kept waiting.

    On macOS, backlog=0 is reset to backlog=SOMAXCONN, backlog=1 keeps all connections except the first waiting.