Forwards data between sockets a and b until EOF, error, or shutdown. Monitors wakeup_socket for a shutdown signal and checks serv.is_running() to exit gracefully when the server is stopping.
(a, b, wakeup_socket, serv)
| 51 | sent += n |
| 52 | |
| 53 | def forward_sockets(a, b, wakeup_socket, serv): |
| 54 | """Forwards data between sockets a and b until EOF, error, or shutdown. |
| 55 | |
| 56 | Monitors wakeup_socket for a shutdown signal and checks serv.is_running() |
| 57 | to exit gracefully when the server is stopping. |
| 58 | """ |
| 59 | # Prefix messages with e.g.: |
| 60 | # forward_sockets(a{remote=127.0.0.1:36935, local=127.0.0.1:9050} <-> b{local=127.0.0.1:33424, remote=127.0.0.1:8333}) |
| 61 | log_prefix = ("forward_sockets(" |
| 62 | f"a{{remote={format_sock(a, local=False)}, local={format_sock(a, local=True)}}} <-> " |
| 63 | f"b{{local={format_sock(b, local=True)}, remote={format_sock(b, local=False)}}}): ") |
| 64 | |
| 65 | # Mark as non-blocking so that we do not end up in a deadlock-like situation |
| 66 | # where we block and wait on data from `a` while there is data ready to be |
| 67 | # received on `b` and forwarded to `a`. And at the same time the application |
| 68 | # at `a` is not sending anything because it waits for the data from `b` to |
| 69 | # respond. |
| 70 | a.setblocking(False) |
| 71 | b.setblocking(False) |
| 72 | sockets = [a, b, wakeup_socket] |
| 73 | while True: |
| 74 | # Blocking select with timeout |
| 75 | rlist, _, xlist = select.select(sockets, [], sockets, 2) |
| 76 | if not serv.is_running(): |
| 77 | logger.debug(f"{log_prefix}Exit due to shutdown") |
| 78 | return |
| 79 | if len(xlist) > 0: |
| 80 | raise IOError(f"{log_prefix}Exceptional condition on socket") |
| 81 | for s in rlist: |
| 82 | try: |
| 83 | data = s.recv(4096) |
| 84 | if data is None or len(data) == 0: |
| 85 | return |
| 86 | if s == a: |
| 87 | sendall(b, data) |
| 88 | elif s == b: |
| 89 | sendall(a, data) |
| 90 | except (BrokenPipeError, ConnectionResetError) as e: |
| 91 | logger.debug(f"{log_prefix}cannot send or receive data on socket {'a' if s == a else 'b'}: {str(e)}") |
| 92 | return |
| 93 | |
| 94 | # Implementation classes |
| 95 | class Socks5Configuration(): |
no test coverage detected