File size: 4,224 Bytes
d1ceb73 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
# Copyright (c) Microsoft Corporation. All rights reserved.
# Licensed under the MIT License. See LICENSE in the project root
# for license information.
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 binding to a specific port, make sure that the user doesn't have
# to wait until the OS times out the socket to be able to use that port
# again.if the server or the adapter crash or are force-killed.
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): # pragma: no cover
pass # Not available everywhere
server.bind((host, port))
if timeout is not None:
server.settimeout(timeout)
server.listen(backlog)
except Exception: # pragma: no cover
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)
# Set TCP keepalive on an open socket.
# It activates after 1 second (TCP_KEEPIDLE,) of idleness,
# then sends a keepalive ping once every 3 seconds (TCP_KEEPINTVL),
# and closes the connection after 5 failed ping (TCP_KEEPCNT), or 15 seconds
try:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
except (AttributeError, OSError): # pragma: no cover
pass # May not be available everywhere.
try:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
except (AttributeError, OSError): # pragma: no cover
pass # May not be available everywhere.
try:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 3)
except (AttributeError, OSError): # pragma: no cover
pass # May not be available everywhere.
try:
sock.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 5)
except (AttributeError, OSError): # pragma: no cover
pass # May not be available everywhere.
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: # pragma: no cover
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: # pragma: no cover
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):
# Listener socket has been closed.
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
|