123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968 |
- # Wrapper module for _socket, providing some additional facilities
- # implemented in Python.
- """\
- This module provides socket operations and some related functions.
- On Unix, it supports IP (Internet Protocol) and Unix domain sockets.
- On other systems, it only supports IP. Functions specific for a
- socket are available as methods of the socket object.
- Functions:
- socket() -- create a new socket object
- socketpair() -- create a pair of new socket objects [*]
- fromfd() -- create a socket object from an open file descriptor [*]
- send_fds() -- Send file descriptor to the socket.
- recv_fds() -- Receive file descriptors from the socket.
- fromshare() -- create a socket object from data received from socket.share() [*]
- gethostname() -- return the current hostname
- gethostbyname() -- map a hostname to its IP number
- gethostbyaddr() -- map an IP number or hostname to DNS info
- getservbyname() -- map a service name and a protocol name to a port number
- getprotobyname() -- map a protocol name (e.g. 'tcp') to a number
- ntohs(), ntohl() -- convert 16, 32 bit int from network to host byte order
- htons(), htonl() -- convert 16, 32 bit int from host to network byte order
- inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format
- inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)
- socket.getdefaulttimeout() -- get the default timeout value
- socket.setdefaulttimeout() -- set the default timeout value
- create_connection() -- connects to an address, with an optional timeout and
- optional source address.
- create_server() -- create a TCP socket and bind it to a specified address.
- [*] not available on all platforms!
- Special objects:
- SocketType -- type object for socket objects
- error -- exception raised for I/O errors
- has_ipv6 -- boolean value indicating if IPv6 is supported
- IntEnum constants:
- AF_INET, AF_UNIX -- socket domains (first argument to socket() call)
- SOCK_STREAM, SOCK_DGRAM, SOCK_RAW -- socket types (second argument)
- Integer constants:
- Many other constants may be defined; these may be used in calls to
- the setsockopt() and getsockopt() methods.
- """
- import _socket
- from _socket import *
- import os, sys, io, selectors
- from enum import IntEnum, IntFlag
- try:
- import errno
- except ImportError:
- errno = None
- EBADF = getattr(errno, 'EBADF', 9)
- EAGAIN = getattr(errno, 'EAGAIN', 11)
- EWOULDBLOCK = getattr(errno, 'EWOULDBLOCK', 11)
- __all__ = ["fromfd", "getfqdn", "create_connection", "create_server",
- "has_dualstack_ipv6", "AddressFamily", "SocketKind"]
- __all__.extend(os._get_exports_list(_socket))
- # Set up the socket.AF_* socket.SOCK_* constants as members of IntEnums for
- # nicer string representations.
- # Note that _socket only knows about the integer values. The public interface
- # in this module understands the enums and translates them back from integers
- # where needed (e.g. .family property of a socket object).
- IntEnum._convert_(
- 'AddressFamily',
- __name__,
- lambda C: C.isupper() and C.startswith('AF_'))
- IntEnum._convert_(
- 'SocketKind',
- __name__,
- lambda C: C.isupper() and C.startswith('SOCK_'))
- IntFlag._convert_(
- 'MsgFlag',
- __name__,
- lambda C: C.isupper() and C.startswith('MSG_'))
- IntFlag._convert_(
- 'AddressInfo',
- __name__,
- lambda C: C.isupper() and C.startswith('AI_'))
- _LOCALHOST = '127.0.0.1'
- _LOCALHOST_V6 = '::1'
- def _intenum_converter(value, enum_klass):
- """Convert a numeric family value to an IntEnum member.
- If it's not a known member, return the numeric value itself.
- """
- try:
- return enum_klass(value)
- except ValueError:
- return value
- # WSA error codes
- if sys.platform.lower().startswith("win"):
- errorTab = {}
- errorTab[6] = "Specified event object handle is invalid."
- errorTab[8] = "Insufficient memory available."
- errorTab[87] = "One or more parameters are invalid."
- errorTab[995] = "Overlapped operation aborted."
- errorTab[996] = "Overlapped I/O event object not in signaled state."
- errorTab[997] = "Overlapped operation will complete later."
- errorTab[10004] = "The operation was interrupted."
- errorTab[10009] = "A bad file handle was passed."
- errorTab[10013] = "Permission denied."
- errorTab[10014] = "A fault occurred on the network??" # WSAEFAULT
- errorTab[10022] = "An invalid operation was attempted."
- errorTab[10024] = "Too many open files."
- errorTab[10035] = "The socket operation would block."
- errorTab[10036] = "A blocking operation is already in progress."
- errorTab[10037] = "Operation already in progress."
- errorTab[10038] = "Socket operation on nonsocket."
- errorTab[10039] = "Destination address required."
- errorTab[10040] = "Message too long."
- errorTab[10041] = "Protocol wrong type for socket."
- errorTab[10042] = "Bad protocol option."
- errorTab[10043] = "Protocol not supported."
- errorTab[10044] = "Socket type not supported."
- errorTab[10045] = "Operation not supported."
- errorTab[10046] = "Protocol family not supported."
- errorTab[10047] = "Address family not supported by protocol family."
- errorTab[10048] = "The network address is in use."
- errorTab[10049] = "Cannot assign requested address."
- errorTab[10050] = "Network is down."
- errorTab[10051] = "Network is unreachable."
- errorTab[10052] = "Network dropped connection on reset."
- errorTab[10053] = "Software caused connection abort."
- errorTab[10054] = "The connection has been reset."
- errorTab[10055] = "No buffer space available."
- errorTab[10056] = "Socket is already connected."
- errorTab[10057] = "Socket is not connected."
- errorTab[10058] = "The network has been shut down."
- errorTab[10059] = "Too many references."
- errorTab[10060] = "The operation timed out."
- errorTab[10061] = "Connection refused."
- errorTab[10062] = "Cannot translate name."
- errorTab[10063] = "The name is too long."
- errorTab[10064] = "The host is down."
- errorTab[10065] = "The host is unreachable."
- errorTab[10066] = "Directory not empty."
- errorTab[10067] = "Too many processes."
- errorTab[10068] = "User quota exceeded."
- errorTab[10069] = "Disk quota exceeded."
- errorTab[10070] = "Stale file handle reference."
- errorTab[10071] = "Item is remote."
- errorTab[10091] = "Network subsystem is unavailable."
- errorTab[10092] = "Winsock.dll version out of range."
- errorTab[10093] = "Successful WSAStartup not yet performed."
- errorTab[10101] = "Graceful shutdown in progress."
- errorTab[10102] = "No more results from WSALookupServiceNext."
- errorTab[10103] = "Call has been canceled."
- errorTab[10104] = "Procedure call table is invalid."
- errorTab[10105] = "Service provider is invalid."
- errorTab[10106] = "Service provider failed to initialize."
- errorTab[10107] = "System call failure."
- errorTab[10108] = "Service not found."
- errorTab[10109] = "Class type not found."
- errorTab[10110] = "No more results from WSALookupServiceNext."
- errorTab[10111] = "Call was canceled."
- errorTab[10112] = "Database query was refused."
- errorTab[11001] = "Host not found."
- errorTab[11002] = "Nonauthoritative host not found."
- errorTab[11003] = "This is a nonrecoverable error."
- errorTab[11004] = "Valid name, no data record requested type."
- errorTab[11005] = "QoS receivers."
- errorTab[11006] = "QoS senders."
- errorTab[11007] = "No QoS senders."
- errorTab[11008] = "QoS no receivers."
- errorTab[11009] = "QoS request confirmed."
- errorTab[11010] = "QoS admission error."
- errorTab[11011] = "QoS policy failure."
- errorTab[11012] = "QoS bad style."
- errorTab[11013] = "QoS bad object."
- errorTab[11014] = "QoS traffic control error."
- errorTab[11015] = "QoS generic error."
- errorTab[11016] = "QoS service type error."
- errorTab[11017] = "QoS flowspec error."
- errorTab[11018] = "Invalid QoS provider buffer."
- errorTab[11019] = "Invalid QoS filter style."
- errorTab[11020] = "Invalid QoS filter style."
- errorTab[11021] = "Incorrect QoS filter count."
- errorTab[11022] = "Invalid QoS object length."
- errorTab[11023] = "Incorrect QoS flow count."
- errorTab[11024] = "Unrecognized QoS object."
- errorTab[11025] = "Invalid QoS policy object."
- errorTab[11026] = "Invalid QoS flow descriptor."
- errorTab[11027] = "Invalid QoS provider-specific flowspec."
- errorTab[11028] = "Invalid QoS provider-specific filterspec."
- errorTab[11029] = "Invalid QoS shape discard mode object."
- errorTab[11030] = "Invalid QoS shaping rate object."
- errorTab[11031] = "Reserved policy QoS element type."
- __all__.append("errorTab")
- class _GiveupOnSendfile(Exception): pass
- class socket(_socket.socket):
- """A subclass of _socket.socket adding the makefile() method."""
- __slots__ = ["__weakref__", "_io_refs", "_closed"]
- def __init__(self, family=-1, type=-1, proto=-1, fileno=None):
- # For user code address family and type values are IntEnum members, but
- # for the underlying _socket.socket they're just integers. The
- # constructor of _socket.socket converts the given argument to an
- # integer automatically.
- if fileno is None:
- if family == -1:
- family = AF_INET
- if type == -1:
- type = SOCK_STREAM
- if proto == -1:
- proto = 0
- _socket.socket.__init__(self, family, type, proto, fileno)
- self._io_refs = 0
- self._closed = False
- def __enter__(self):
- return self
- def __exit__(self, *args):
- if not self._closed:
- self.close()
- def __repr__(self):
- """Wrap __repr__() to reveal the real class name and socket
- address(es).
- """
- closed = getattr(self, '_closed', False)
- s = "<%s.%s%s fd=%i, family=%s, type=%s, proto=%i" \
- % (self.__class__.__module__,
- self.__class__.__qualname__,
- " [closed]" if closed else "",
- self.fileno(),
- self.family,
- self.type,
- self.proto)
- if not closed:
- # getsockname and getpeername may not be available on WASI.
- try:
- laddr = self.getsockname()
- if laddr:
- s += ", laddr=%s" % str(laddr)
- except (error, AttributeError):
- pass
- try:
- raddr = self.getpeername()
- if raddr:
- s += ", raddr=%s" % str(raddr)
- except (error, AttributeError):
- pass
- s += '>'
- return s
- def __getstate__(self):
- raise TypeError(f"cannot pickle {self.__class__.__name__!r} object")
- def dup(self):
- """dup() -> socket object
- Duplicate the socket. Return a new socket object connected to the same
- system resource. The new socket is non-inheritable.
- """
- fd = dup(self.fileno())
- sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
- sock.settimeout(self.gettimeout())
- return sock
- def accept(self):
- """accept() -> (socket object, address info)
- Wait for an incoming connection. Return a new socket
- representing the connection, and the address of the client.
- For IP sockets, the address info is a pair (hostaddr, port).
- """
- fd, addr = self._accept()
- sock = socket(self.family, self.type, self.proto, fileno=fd)
- # Issue #7995: if no default timeout is set and the listening
- # socket had a (non-zero) timeout, force the new socket in blocking
- # mode to override platform-specific socket flags inheritance.
- if getdefaulttimeout() is None and self.gettimeout():
- sock.setblocking(True)
- return sock, addr
- def makefile(self, mode="r", buffering=None, *,
- encoding=None, errors=None, newline=None):
- """makefile(...) -> an I/O stream connected to the socket
- The arguments are as for io.open() after the filename, except the only
- supported mode values are 'r' (default), 'w' and 'b'.
- """
- # XXX refactor to share code?
- if not set(mode) <= {"r", "w", "b"}:
- raise ValueError("invalid mode %r (only r, w, b allowed)" % (mode,))
- writing = "w" in mode
- reading = "r" in mode or not writing
- assert reading or writing
- binary = "b" in mode
- rawmode = ""
- if reading:
- rawmode += "r"
- if writing:
- rawmode += "w"
- raw = SocketIO(self, rawmode)
- self._io_refs += 1
- if buffering is None:
- buffering = -1
- if buffering < 0:
- buffering = io.DEFAULT_BUFFER_SIZE
- if buffering == 0:
- if not binary:
- raise ValueError("unbuffered streams must be binary")
- return raw
- if reading and writing:
- buffer = io.BufferedRWPair(raw, raw, buffering)
- elif reading:
- buffer = io.BufferedReader(raw, buffering)
- else:
- assert writing
- buffer = io.BufferedWriter(raw, buffering)
- if binary:
- return buffer
- encoding = io.text_encoding(encoding)
- text = io.TextIOWrapper(buffer, encoding, errors, newline)
- text.mode = mode
- return text
- if hasattr(os, 'sendfile'):
- def _sendfile_use_sendfile(self, file, offset=0, count=None):
- self._check_sendfile_params(file, offset, count)
- sockno = self.fileno()
- try:
- fileno = file.fileno()
- except (AttributeError, io.UnsupportedOperation) as err:
- raise _GiveupOnSendfile(err) # not a regular file
- try:
- fsize = os.fstat(fileno).st_size
- except OSError as err:
- raise _GiveupOnSendfile(err) # not a regular file
- if not fsize:
- return 0 # empty file
- # Truncate to 1GiB to avoid OverflowError, see bpo-38319.
- blocksize = min(count or fsize, 2 ** 30)
- timeout = self.gettimeout()
- if timeout == 0:
- raise ValueError("non-blocking sockets are not supported")
- # poll/select have the advantage of not requiring any
- # extra file descriptor, contrarily to epoll/kqueue
- # (also, they require a single syscall).
- if hasattr(selectors, 'PollSelector'):
- selector = selectors.PollSelector()
- else:
- selector = selectors.SelectSelector()
- selector.register(sockno, selectors.EVENT_WRITE)
- total_sent = 0
- # localize variable access to minimize overhead
- selector_select = selector.select
- os_sendfile = os.sendfile
- try:
- while True:
- if timeout and not selector_select(timeout):
- raise TimeoutError('timed out')
- if count:
- blocksize = count - total_sent
- if blocksize <= 0:
- break
- try:
- sent = os_sendfile(sockno, fileno, offset, blocksize)
- except BlockingIOError:
- if not timeout:
- # Block until the socket is ready to send some
- # data; avoids hogging CPU resources.
- selector_select()
- continue
- except OSError as err:
- if total_sent == 0:
- # We can get here for different reasons, the main
- # one being 'file' is not a regular mmap(2)-like
- # file, in which case we'll fall back on using
- # plain send().
- raise _GiveupOnSendfile(err)
- raise err from None
- else:
- if sent == 0:
- break # EOF
- offset += sent
- total_sent += sent
- return total_sent
- finally:
- if total_sent > 0 and hasattr(file, 'seek'):
- file.seek(offset)
- else:
- def _sendfile_use_sendfile(self, file, offset=0, count=None):
- raise _GiveupOnSendfile(
- "os.sendfile() not available on this platform")
- def _sendfile_use_send(self, file, offset=0, count=None):
- self._check_sendfile_params(file, offset, count)
- if self.gettimeout() == 0:
- raise ValueError("non-blocking sockets are not supported")
- if offset:
- file.seek(offset)
- blocksize = min(count, 8192) if count else 8192
- total_sent = 0
- # localize variable access to minimize overhead
- file_read = file.read
- sock_send = self.send
- try:
- while True:
- if count:
- blocksize = min(count - total_sent, blocksize)
- if blocksize <= 0:
- break
- data = memoryview(file_read(blocksize))
- if not data:
- break # EOF
- while True:
- try:
- sent = sock_send(data)
- except BlockingIOError:
- continue
- else:
- total_sent += sent
- if sent < len(data):
- data = data[sent:]
- else:
- break
- return total_sent
- finally:
- if total_sent > 0 and hasattr(file, 'seek'):
- file.seek(offset + total_sent)
- def _check_sendfile_params(self, file, offset, count):
- if 'b' not in getattr(file, 'mode', 'b'):
- raise ValueError("file should be opened in binary mode")
- if not self.type & SOCK_STREAM:
- raise ValueError("only SOCK_STREAM type sockets are supported")
- if count is not None:
- if not isinstance(count, int):
- raise TypeError(
- "count must be a positive integer (got {!r})".format(count))
- if count <= 0:
- raise ValueError(
- "count must be a positive integer (got {!r})".format(count))
- def sendfile(self, file, offset=0, count=None):
- """sendfile(file[, offset[, count]]) -> sent
- Send a file until EOF is reached by using high-performance
- os.sendfile() and return the total number of bytes which
- were sent.
- *file* must be a regular file object opened in binary mode.
- If os.sendfile() is not available (e.g. Windows) or file is
- not a regular file socket.send() will be used instead.
- *offset* tells from where to start reading the file.
- If specified, *count* is the total number of bytes to transmit
- as opposed to sending the file until EOF is reached.
- File position is updated on return or also in case of error in
- which case file.tell() can be used to figure out the number of
- bytes which were sent.
- The socket must be of SOCK_STREAM type.
- Non-blocking sockets are not supported.
- """
- try:
- return self._sendfile_use_sendfile(file, offset, count)
- except _GiveupOnSendfile:
- return self._sendfile_use_send(file, offset, count)
- def _decref_socketios(self):
- if self._io_refs > 0:
- self._io_refs -= 1
- if self._closed:
- self.close()
- def _real_close(self, _ss=_socket.socket):
- # This function should not reference any globals. See issue #808164.
- _ss.close(self)
- def close(self):
- # This function should not reference any globals. See issue #808164.
- self._closed = True
- if self._io_refs <= 0:
- self._real_close()
- def detach(self):
- """detach() -> file descriptor
- Close the socket object without closing the underlying file descriptor.
- The object cannot be used after this call, but the file descriptor
- can be reused for other purposes. The file descriptor is returned.
- """
- self._closed = True
- return super().detach()
- @property
- def family(self):
- """Read-only access to the address family for this socket.
- """
- return _intenum_converter(super().family, AddressFamily)
- @property
- def type(self):
- """Read-only access to the socket type.
- """
- return _intenum_converter(super().type, SocketKind)
- if os.name == 'nt':
- def get_inheritable(self):
- return os.get_handle_inheritable(self.fileno())
- def set_inheritable(self, inheritable):
- os.set_handle_inheritable(self.fileno(), inheritable)
- else:
- def get_inheritable(self):
- return os.get_inheritable(self.fileno())
- def set_inheritable(self, inheritable):
- os.set_inheritable(self.fileno(), inheritable)
- get_inheritable.__doc__ = "Get the inheritable flag of the socket"
- set_inheritable.__doc__ = "Set the inheritable flag of the socket"
- def fromfd(fd, family, type, proto=0):
- """ fromfd(fd, family, type[, proto]) -> socket object
- Create a socket object from a duplicate of the given file
- descriptor. The remaining arguments are the same as for socket().
- """
- nfd = dup(fd)
- return socket(family, type, proto, nfd)
- if hasattr(_socket.socket, "sendmsg"):
- import array
- def send_fds(sock, buffers, fds, flags=0, address=None):
- """ send_fds(sock, buffers, fds[, flags[, address]]) -> integer
- Send the list of file descriptors fds over an AF_UNIX socket.
- """
- return sock.sendmsg(buffers, [(_socket.SOL_SOCKET,
- _socket.SCM_RIGHTS, array.array("i", fds))])
- __all__.append("send_fds")
- if hasattr(_socket.socket, "recvmsg"):
- import array
- def recv_fds(sock, bufsize, maxfds, flags=0):
- """ recv_fds(sock, bufsize, maxfds[, flags]) -> (data, list of file
- descriptors, msg_flags, address)
- Receive up to maxfds file descriptors returning the message
- data and a list containing the descriptors.
- """
- # Array of ints
- fds = array.array("i")
- msg, ancdata, flags, addr = sock.recvmsg(bufsize,
- _socket.CMSG_LEN(maxfds * fds.itemsize))
- for cmsg_level, cmsg_type, cmsg_data in ancdata:
- if (cmsg_level == _socket.SOL_SOCKET and cmsg_type == _socket.SCM_RIGHTS):
- fds.frombytes(cmsg_data[:
- len(cmsg_data) - (len(cmsg_data) % fds.itemsize)])
- return msg, list(fds), flags, addr
- __all__.append("recv_fds")
- if hasattr(_socket.socket, "share"):
- def fromshare(info):
- """ fromshare(info) -> socket object
- Create a socket object from the bytes object returned by
- socket.share(pid).
- """
- return socket(0, 0, 0, info)
- __all__.append("fromshare")
- if hasattr(_socket, "socketpair"):
- def socketpair(family=None, type=SOCK_STREAM, proto=0):
- """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
- Create a pair of socket objects from the sockets returned by the platform
- socketpair() function.
- The arguments are the same as for socket() except the default family is
- AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
- """
- if family is None:
- try:
- family = AF_UNIX
- except NameError:
- family = AF_INET
- a, b = _socket.socketpair(family, type, proto)
- a = socket(family, type, proto, a.detach())
- b = socket(family, type, proto, b.detach())
- return a, b
- else:
- # Origin: https://gist.github.com/4325783, by Geert Jansen. Public domain.
- def socketpair(family=AF_INET, type=SOCK_STREAM, proto=0):
- if family == AF_INET:
- host = _LOCALHOST
- elif family == AF_INET6:
- host = _LOCALHOST_V6
- else:
- raise ValueError("Only AF_INET and AF_INET6 socket address families "
- "are supported")
- if type != SOCK_STREAM:
- raise ValueError("Only SOCK_STREAM socket type is supported")
- if proto != 0:
- raise ValueError("Only protocol zero is supported")
- # We create a connected TCP socket. Note the trick with
- # setblocking(False) that prevents us from having to create a thread.
- lsock = socket(family, type, proto)
- try:
- lsock.bind((host, 0))
- lsock.listen()
- # On IPv6, ignore flow_info and scope_id
- addr, port = lsock.getsockname()[:2]
- csock = socket(family, type, proto)
- try:
- csock.setblocking(False)
- try:
- csock.connect((addr, port))
- except (BlockingIOError, InterruptedError):
- pass
- csock.setblocking(True)
- ssock, _ = lsock.accept()
- except:
- csock.close()
- raise
- finally:
- lsock.close()
- return (ssock, csock)
- __all__.append("socketpair")
- socketpair.__doc__ = """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
- Create a pair of socket objects from the sockets returned by the platform
- socketpair() function.
- The arguments are the same as for socket() except the default family is AF_UNIX
- if defined on the platform; otherwise, the default is AF_INET.
- """
- _blocking_errnos = { EAGAIN, EWOULDBLOCK }
- class SocketIO(io.RawIOBase):
- """Raw I/O implementation for stream sockets.
- This class supports the makefile() method on sockets. It provides
- the raw I/O interface on top of a socket object.
- """
- # One might wonder why not let FileIO do the job instead. There are two
- # main reasons why FileIO is not adapted:
- # - it wouldn't work under Windows (where you can't used read() and
- # write() on a socket handle)
- # - it wouldn't work with socket timeouts (FileIO would ignore the
- # timeout and consider the socket non-blocking)
- # XXX More docs
- def __init__(self, sock, mode):
- if mode not in ("r", "w", "rw", "rb", "wb", "rwb"):
- raise ValueError("invalid mode: %r" % mode)
- io.RawIOBase.__init__(self)
- self._sock = sock
- if "b" not in mode:
- mode += "b"
- self._mode = mode
- self._reading = "r" in mode
- self._writing = "w" in mode
- self._timeout_occurred = False
- def readinto(self, b):
- """Read up to len(b) bytes into the writable buffer *b* and return
- the number of bytes read. If the socket is non-blocking and no bytes
- are available, None is returned.
- If *b* is non-empty, a 0 return value indicates that the connection
- was shutdown at the other end.
- """
- self._checkClosed()
- self._checkReadable()
- if self._timeout_occurred:
- raise OSError("cannot read from timed out object")
- while True:
- try:
- return self._sock.recv_into(b)
- except timeout:
- self._timeout_occurred = True
- raise
- except error as e:
- if e.errno in _blocking_errnos:
- return None
- raise
- def write(self, b):
- """Write the given bytes or bytearray object *b* to the socket
- and return the number of bytes written. This can be less than
- len(b) if not all data could be written. If the socket is
- non-blocking and no bytes could be written None is returned.
- """
- self._checkClosed()
- self._checkWritable()
- try:
- return self._sock.send(b)
- except error as e:
- # XXX what about EINTR?
- if e.errno in _blocking_errnos:
- return None
- raise
- def readable(self):
- """True if the SocketIO is open for reading.
- """
- if self.closed:
- raise ValueError("I/O operation on closed socket.")
- return self._reading
- def writable(self):
- """True if the SocketIO is open for writing.
- """
- if self.closed:
- raise ValueError("I/O operation on closed socket.")
- return self._writing
- def seekable(self):
- """True if the SocketIO is open for seeking.
- """
- if self.closed:
- raise ValueError("I/O operation on closed socket.")
- return super().seekable()
- def fileno(self):
- """Return the file descriptor of the underlying socket.
- """
- self._checkClosed()
- return self._sock.fileno()
- @property
- def name(self):
- if not self.closed:
- return self.fileno()
- else:
- return -1
- @property
- def mode(self):
- return self._mode
- def close(self):
- """Close the SocketIO object. This doesn't close the underlying
- socket, except if all references to it have disappeared.
- """
- if self.closed:
- return
- io.RawIOBase.close(self)
- self._sock._decref_socketios()
- self._sock = None
- def getfqdn(name=''):
- """Get fully qualified domain name from name.
- An empty argument is interpreted as meaning the local host.
- First the hostname returned by gethostbyaddr() is checked, then
- possibly existing aliases. In case no FQDN is available and `name`
- was given, it is returned unchanged. If `name` was empty, '0.0.0.0' or '::',
- hostname from gethostname() is returned.
- """
- name = name.strip()
- if not name or name in ('0.0.0.0', '::'):
- name = gethostname()
- try:
- hostname, aliases, ipaddrs = gethostbyaddr(name)
- except error:
- pass
- else:
- aliases.insert(0, hostname)
- for name in aliases:
- if '.' in name:
- break
- else:
- name = hostname
- return name
- _GLOBAL_DEFAULT_TIMEOUT = object()
- def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
- source_address=None, *, all_errors=False):
- """Connect to *address* and return the socket object.
- Convenience function. Connect to *address* (a 2-tuple ``(host,
- port)``) and return the socket object. Passing the optional
- *timeout* parameter will set the timeout on the socket instance
- before attempting to connect. If no *timeout* is supplied, the
- global default timeout setting returned by :func:`getdefaulttimeout`
- is used. If *source_address* is set it must be a tuple of (host, port)
- for the socket to bind as a source address before making the connection.
- A host of '' or port 0 tells the OS to use the default. When a connection
- cannot be created, raises the last error if *all_errors* is False,
- and an ExceptionGroup of all errors if *all_errors* is True.
- """
- host, port = address
- exceptions = []
- for res in getaddrinfo(host, port, 0, SOCK_STREAM):
- af, socktype, proto, canonname, sa = res
- sock = None
- try:
- sock = socket(af, socktype, proto)
- if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
- sock.settimeout(timeout)
- if source_address:
- sock.bind(source_address)
- sock.connect(sa)
- # Break explicitly a reference cycle
- exceptions.clear()
- return sock
- except error as exc:
- if not all_errors:
- exceptions.clear() # raise only the last error
- exceptions.append(exc)
- if sock is not None:
- sock.close()
- if len(exceptions):
- try:
- if not all_errors:
- raise exceptions[0]
- raise ExceptionGroup("create_connection failed", exceptions)
- finally:
- # Break explicitly a reference cycle
- exceptions.clear()
- else:
- raise error("getaddrinfo returns an empty list")
- def has_dualstack_ipv6():
- """Return True if the platform supports creating a SOCK_STREAM socket
- which can handle both AF_INET and AF_INET6 (IPv4 / IPv6) connections.
- """
- if not has_ipv6 \
- or not hasattr(_socket, 'IPPROTO_IPV6') \
- or not hasattr(_socket, 'IPV6_V6ONLY'):
- return False
- try:
- with socket(AF_INET6, SOCK_STREAM) as sock:
- sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 0)
- return True
- except error:
- return False
- def create_server(address, *, family=AF_INET, backlog=None, reuse_port=False,
- dualstack_ipv6=False):
- """Convenience function which creates a SOCK_STREAM type socket
- bound to *address* (a 2-tuple (host, port)) and return the socket
- object.
- *family* should be either AF_INET or AF_INET6.
- *backlog* is the queue size passed to socket.listen().
- *reuse_port* dictates whether to use the SO_REUSEPORT socket option.
- *dualstack_ipv6*: if true and the platform supports it, it will
- create an AF_INET6 socket able to accept both IPv4 or IPv6
- connections. When false it will explicitly disable this option on
- platforms that enable it by default (e.g. Linux).
- >>> with create_server(('', 8000)) as server:
- ... while True:
- ... conn, addr = server.accept()
- ... # handle new connection
- """
- if reuse_port and not hasattr(_socket, "SO_REUSEPORT"):
- raise ValueError("SO_REUSEPORT not supported on this platform")
- if dualstack_ipv6:
- if not has_dualstack_ipv6():
- raise ValueError("dualstack_ipv6 not supported on this platform")
- if family != AF_INET6:
- raise ValueError("dualstack_ipv6 requires AF_INET6 family")
- sock = socket(family, SOCK_STREAM)
- try:
- # Note about Windows. We don't set SO_REUSEADDR because:
- # 1) It's unnecessary: bind() will succeed even in case of a
- # previous closed socket on the same address and still in
- # TIME_WAIT state.
- # 2) If set, another socket is free to bind() on the same
- # address, effectively preventing this one from accepting
- # connections. Also, it may set the process in a state where
- # it'll no longer respond to any signals or graceful kills.
- # See: https://learn.microsoft.com/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse
- if os.name not in ('nt', 'cygwin') and \
- hasattr(_socket, 'SO_REUSEADDR'):
- try:
- sock.setsockopt(SOL_SOCKET, SO_REUSEADDR, 1)
- except error:
- # Fail later on bind(), for platforms which may not
- # support this option.
- pass
- if reuse_port:
- sock.setsockopt(SOL_SOCKET, SO_REUSEPORT, 1)
- if has_ipv6 and family == AF_INET6:
- if dualstack_ipv6:
- sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 0)
- elif hasattr(_socket, "IPV6_V6ONLY") and \
- hasattr(_socket, "IPPROTO_IPV6"):
- sock.setsockopt(IPPROTO_IPV6, IPV6_V6ONLY, 1)
- try:
- sock.bind(address)
- except error as err:
- msg = '%s (while attempting to bind on address %r)' % \
- (err.strerror, address)
- raise error(err.errno, msg) from None
- if backlog is None:
- sock.listen()
- else:
- sock.listen(backlog)
- return sock
- except error:
- sock.close()
- raise
- def getaddrinfo(host, port, family=0, type=0, proto=0, flags=0):
- """Resolve host and port into list of address info entries.
- Translate the host/port argument into a sequence of 5-tuples that contain
- all the necessary arguments for creating a socket connected to that service.
- host is a domain name, a string representation of an IPv4/v6 address or
- None. port is a string service name such as 'http', a numeric port number or
- None. By passing None as the value of host and port, you can pass NULL to
- the underlying C API.
- The family, type and proto arguments can be optionally specified in order to
- narrow the list of addresses returned. Passing zero as a value for each of
- these arguments selects the full range of results.
- """
- # We override this function since we want to translate the numeric family
- # and socket type values to enum constants.
- addrlist = []
- for res in _socket.getaddrinfo(host, port, family, type, proto, flags):
- af, socktype, proto, canonname, sa = res
- addrlist.append((_intenum_converter(af, AddressFamily),
- _intenum_converter(socktype, SocketKind),
- proto, canonname, sa))
- return addrlist
|