|
|
|
|
|
|
|
|
|
import socket |
|
import sys |
|
import threading |
|
|
|
from debugpy.common import log |
|
from debugpy.common.util import hide_thread_from_debugger |
|
|
|
|
|
def create_server(host, port=0, backlog=socket.SOMAXCONN, timeout=None): |
|
"""Return a local server socket listening on the given port.""" |
|
|
|
assert backlog > 0 |
|
if host is None: |
|
host = "127.0.0.1" |
|
if port is None: |
|
port = 0 |
|
|
|
try: |
|
server = _new_sock() |
|
if port != 0: |
|
|
|
|
|
|
|
if sys.platform == "win32": |
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_EXCLUSIVEADDRUSE, 1) |
|
else: |
|
try: |
|
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) |
|
except (AttributeError, OSError): |
|
pass |
|
server.bind((host, port)) |
|
if timeout is not None: |
|
server.settimeout(timeout) |
|
server.listen(backlog) |
|
except Exception: |
|
server.close() |
|
raise |
|
return server |
|
|
|
|
|
def create_client(): |
|
"""Return a client socket that may be connected to a remote address.""" |
|
return _new_sock() |
|
|
|
|
|
def _new_sock(): |
|
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP) |
|
|
|
|
|
|
|
|
|
|
|
try: |
|
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1) |
|
except (AttributeError, OSError): |
|
pass |
|
try: |
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1) |
|
except (AttributeError, OSError): |
|
pass |
|
try: |
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3) |
|
except (AttributeError, OSError): |
|
pass |
|
try: |
|
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5) |
|
except (AttributeError, OSError): |
|
pass |
|
return sock |
|
|
|
|
|
def shut_down(sock, how=socket.SHUT_RDWR): |
|
"""Shut down the given socket.""" |
|
sock.shutdown(how) |
|
|
|
|
|
def close_socket(sock): |
|
"""Shutdown and close the socket.""" |
|
try: |
|
shut_down(sock) |
|
except Exception: |
|
pass |
|
sock.close() |
|
|
|
|
|
def serve(name, handler, host, port=0, backlog=socket.SOMAXCONN, timeout=None): |
|
"""Accepts TCP connections on the specified host and port, and invokes the |
|
provided handler function for every new connection. |
|
|
|
Returns the created server socket. |
|
""" |
|
|
|
assert backlog > 0 |
|
|
|
try: |
|
listener = create_server(host, port, backlog, timeout) |
|
except Exception: |
|
log.reraise_exception( |
|
"Error listening for incoming {0} connections on {1}:{2}:", name, host, port |
|
) |
|
host, port = listener.getsockname() |
|
log.info("Listening for incoming {0} connections on {1}:{2}...", name, host, port) |
|
|
|
def accept_worker(): |
|
while True: |
|
try: |
|
sock, (other_host, other_port) = listener.accept() |
|
except (OSError, socket.error): |
|
|
|
break |
|
|
|
log.info( |
|
"Accepted incoming {0} connection from {1}:{2}.", |
|
name, |
|
other_host, |
|
other_port, |
|
) |
|
handler(sock) |
|
|
|
thread = threading.Thread(target=accept_worker) |
|
thread.daemon = True |
|
hide_thread_from_debugger(thread) |
|
thread.start() |
|
|
|
return listener |
|
|