diff --git a/grumpy-runtime-src/lib/_socket.py b/grumpy-runtime-src/lib/_socket.py new file mode 100644 index 00000000..e34afaef --- /dev/null +++ b/grumpy-runtime-src/lib/_socket.py @@ -0,0 +1,337 @@ +# Copyright 2016 Google Inc. All Rights Reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +from '__go__/net' import ( + IPv4 as _IPv4, IP as _IP, LookupAddr as _LookupAddr, LookupIP as + _LookupIP, ParseIP as _ParseIP) +from '__go__/syscall' import ( + AF_INET, + AF_INET6, + AF_UNIX, + SHUT_RD, + SHUT_RDWR, + SHUT_WR, + SO_REUSEADDR, + SOL_SOCKET, + SOCK_DGRAM, + SOCK_RAW, + SOCK_SEQPACKET, + SOCK_STREAM, + Accept as _Accept, + Bind as _Bind, + Close as _Close, + Connect as _Connect, + Getpeername as _Getpeername, + Getsockname as _Getsockname, + Listen as _Listen, + Recvfrom as _Recvfrom, + Sendto as _Sendto, + SetNonblock as _SetNonblock, + SetsockoptInt as _SetsockoptInt, + SetsockoptTimeval as _SetsockoptTimeval, + Shutdown as _Shutdown, + SockaddrInet4 as _SockaddrInet4, + SockaddrInet6 as _SockaddrInet6, + SockaddrUnix as _SockaddrUnix, + Socket as _Socket, + Timespec as _Timespec) +import math + + +#TIPC_* +#has_ipv6 # boolean value indicating if IPv6 is supported +# UNIX +#SO_* +#SOMAXCONN +#MSG_* +#SOL_* +#IPPROTO_* +#IPPORT_* +#INADDR_* +#IP_* +#IPV6_* +#EAI_* +#AI_* +#NI_* +#TCP_* +# Windows +#SIO_* +#RCVALL_* + +#SHUT_RD +#SHUT_WR +#SHUT_RDWR + + +class error(IOError): + pass + + +class gaierror(error): + pass + + +class herror(error): + pass + + +class timeout(error): + pass + + +class socket(object): + + def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fd=None): + if fd is None: + fd, err = _Socket(family, type, proto) + if err: + raise error(err.Error()) + self._fd = fd + self.family = family + self.type = type + self.proto = proto + + def accept(self): + fd, sockaddr, err = _Accept(self._fd) + if err: + raise error(err.Error()) + return (socket(self.family, self.type, self.proto, fd), + self._get_address(sockaddr)) + + def bind(self, address): + sockaddr = self._parse_address(address) + err = _Bind(self._fd, sockaddr) + if err: + raise error(err.Error()) + + def close(self): + _Close(self._fd) + + def connect(self, address): + self.connect_ex(address) + + def connect_ex(self, address): + addr = self._parse_address(address) + err = _Connect(self._fd, addr) + if err: + raise error(err) + + def fileno(self): + return self._fd + + def listen(self, backlog): + err = _Listen(self._fd, backlog) + if err: + raise error(err.Error()) + + def getpeername(self): + sockaddr, err = _Getpeername(self._fd) + if err: + raise error(err.Error()) + return self._get_address(sockaddr) + + def getsockname(self): + sockaddr, err = _Getsockname(self._fd) + if err: + raise error(err.Error()) + return self._get_address(sockaddr) + + def getsockopt(self, level, optname, buflen=None): + val, err = _GetsockoptInt(self._fd, level, optname) + if err: + raise error(err) + return val + + def recv(self, bufsize, flags=0): + data, _ = self.recvfrom(bufsize, flags) + return data + + def recv_into(self, buffer, nbytes=0, flags=0): + n, _ = self.recvfrom_into(buffer, nbytes, flags) + return n + + def recvfrom(self, bufsize, flags=0): + buffer = bytearray(bufsize) + n, addr = self.recvfrom_into(buffer, bufsize, flags) + return str(buffer[:n]), addr + + def recvfrom_into(self, buffer, nbytes=0, flags=0): + n, _, err = _Recvfrom(self._fd, buffer, flags) + if err: + raise error(err.Error()) + return n, None + + def setsockopt(self, level, optname, value): + err = _SetsockoptInt(self._fd, level, optname, value) + if err: + raise error(err.Error()) + + def send(self, string, flags=0): + sockaddr, err = _Getsockname(self._fd) + if err: + raise error(err) + err = _Sendto(self._fd, string, flags, sockaddr) + if err: + raise error(err) + return len(string) + + def sendto(self, string, flags_or_address, address=None): + raise NotImplementedError + + def sendall(self, string, flags=0): + return self.send(string, flags) + + def setblocking(self, flag): + err = _SetNonblock(fd, int(not flag)) + if err: + raise error(err.Error()) + + def settimeout(self, value): + if value is None: + timevalue = None + else: + timeval = _Timeval.new() + frac, integer = math.modf(value) + timeval.Sec = int(integer) + timeval.Usec = int(frac * 1000000.0) + err = _SetsockoptTimeval(self._fd, level, SO_RCVTIMEO, timeval) + if err: + raise error(err) + + def gettimeout(self): + raise NotImplementedError + + def shutdown(self, how): + err = _Shutdown(self._fd, how) + if err: + raise error(err) + + def _parse_address(self, address): + if self.family == AF_UNIX: + sockaddr = _SockaddrUnix.new() + sockaddr.Name, = address + return sockaddr + host, port = address + if not host: + host = '127.0.0.1' + ip = _ParseIP(host) + if ip: + ips = [ip] + else: + ips, err = _LookupIP(host) + if err: + raise error(err.Error()) + if self.family == AF_INET: + convert = _IP.To4 + else: + convert = _IP.To6 + for ip in ips: + ip = convert(ip) + if ip: + break + else: + raise error('cannot resolve address') + if self.family == AF_INET: + sockaddr = _SockaddrInet4.new() + else: + sockaddr = _SockaddrInet6.new() + sockaddr.Port = port + sockaddr.Addr[:] = ip + return sockaddr + + def _get_address(self, sockaddr): + if isinstance(sockaddr, type(_SockaddrUnix.new())): + return (sockaddr.Name,) + return _IPv4(*sockaddr.Addr).String(), sockaddr.Port + + +def fromfd(fd, family, type, proto=None): + return socket(family, type, proto, fd) + + +def gethostbyname(hostname): + raise NotImplementedError + + +def gethostbyaddr(ipaddr): + names, err = _LookupAddr(ipaddr) + if err: + return error(err) + return names[0], [], [ipaddr] + + +def gethostname(): + raise NotImplementedError + + +def getprotobyname(proto): + raise NotImplementedError + + +# --> port number +def getservbyname(servicename, protocolname=None): + raise NotImplementedError + + +def getservbyport(portnumber, protocolname=None): + raise NotImplementedError + + +def socketpair(family=None, type=None, proto=None): + raise NotImplementedError + + +def ntohs(n): + raise NotImplementedError + + +def ntohl(n): + raise NotImplementedError + + +def htons(n): + raise NotImplementedError + + +def htonl(n): + raise NotImplementedError + + +# --> List of (family, socktype, proto, canonname, sockaddr) +def getaddrinfo(host, port, family=None, socktype=None, proto=None, flags=None): + raise NotImplementedError + + +# --> (host, port) +def getnameinfo(sockaddr, flags): + raise NotImplementedError + + +# -> 32-bit packed IP representation +def inet_aton(ipaddr): + return ''.join(chr(int(n)) for n in ipaddr.split('.')) + + +# -> IP address string +def inet_ntoa(ipaddr): + return ''.join(ord(c) for c in ipaddr) + + +# -> None | float +def getdefaulttimeout(): + raise NotImplementedError + + +def setdefaulttimeout(to): + raise NotImplementedError \ No newline at end of file diff --git a/grumpy-runtime-src/third_party/stdlib/socket.py b/grumpy-runtime-src/third_party/stdlib/socket.py new file mode 100644 index 00000000..8dd7872f --- /dev/null +++ b/grumpy-runtime-src/third_party/stdlib/socket.py @@ -0,0 +1,581 @@ +# 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 [*] +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) +ssl() -- secure socket layer support (only available if configured) +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. + + [*] 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 + +Integer constants: + +AF_INET, AF_UNIX -- socket domains (first argument to socket() call) +SOCK_STREAM, SOCK_DGRAM, SOCK_RAW -- socket types (second argument) + +Many other constants may be defined; these may be used in calls to +the setsockopt() and getsockopt() methods. +""" + +import _socket +#from _socket import * +for _k, _v in _socket.__dict__.iteritems(): + if not _k.startswith('_'): + globals()[_k] = _v +from functools import partial +from types import MethodType + +#try: +# import _ssl +#except ImportError: +# # no SSL support +# pass +#else: +# def ssl(sock, keyfile=None, certfile=None): +# # we do an internal import here because the ssl +# # module imports the socket module +# import ssl as _realssl +# warnings.warn("socket.ssl() is deprecated. Use ssl.wrap_socket() instead.", +# DeprecationWarning, stacklevel=2) +# return _realssl.sslwrap_simple(sock, keyfile, certfile) +# +# # we need to import the same constants we used to... +# from _ssl import SSLError as sslerror +# from _ssl import \ +# RAND_add, \ +# RAND_status, \ +# SSL_ERROR_ZERO_RETURN, \ +# SSL_ERROR_WANT_READ, \ +# SSL_ERROR_WANT_WRITE, \ +# SSL_ERROR_WANT_X509_LOOKUP, \ +# SSL_ERROR_SYSCALL, \ +# SSL_ERROR_SSL, \ +# SSL_ERROR_WANT_CONNECT, \ +# SSL_ERROR_EOF, \ +# SSL_ERROR_INVALID_ERROR_CODE +# try: +# from _ssl import RAND_egd +# except ImportError: +# # LibreSSL does not provide RAND_egd +# pass + +import os, sys, warnings + +try: + from cStringIO import StringIO +except ImportError: + from StringIO import StringIO + +try: + import errno +except ImportError: + errno = None +EBADF = getattr(errno, 'EBADF', 9) +EINTR = getattr(errno, 'EINTR', 4) + +__all__ = ["getfqdn", "create_connection"] +__all__.extend(dir(_socket)) +#__all__.extend(os._get_exports_list(_socket)) + + +_realsocket = socket + +# WSA error codes +#if sys.platform.lower().startswith("win"): +# errorTab = {} +# 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[10035] = "The socket operation would block" +# errorTab[10036] = "A blocking operation is already in progress." +# errorTab[10048] = "The network address is in use." +# errorTab[10054] = "The connection has been reset." +# errorTab[10058] = "The network has been shut down." +# errorTab[10060] = "The operation timed out." +# errorTab[10061] = "Connection refused." +# errorTab[10063] = "The name is too long." +# errorTab[10064] = "The host is down." +# errorTab[10065] = "The host is unreachable." +# __all__.append("errorTab") + + + +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, hostname + from gethostname() is returned. + """ + name = name.strip() + if not name or name == '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 + + +_socketmethods = ( + 'bind', 'connect', 'connect_ex', 'fileno', 'listen', + 'getpeername', 'getsockname', 'getsockopt', 'setsockopt', + 'sendall', 'setblocking', + 'settimeout', 'gettimeout', 'shutdown') + +#if os.name == "nt": +# _socketmethods = _socketmethods + ('ioctl',) +# +#if sys.platform == "riscos": +# _socketmethods = _socketmethods + ('sleeptaskw',) + +# All the method names that must be delegated to either the real socket +# object or the _closedsocket object. +_delegate_methods = ("recv", "recvfrom", "recv_into", "recvfrom_into", + "send", "sendto") + +class _closedsocket(object): + __slots__ = [] + def _dummy(*args): + raise error(EBADF, 'Bad file descriptor') + # All _delegate_methods must also be initialized here. + send = recv = recv_into = sendto = recvfrom = recvfrom_into = _dummy + __getattr__ = _dummy + +# Wrapper around platform socket objects. This implements +# a platform-independent dup() functionality. The +# implementation currently relies on reference counting +# to close the underlying socket object. +class _socketobject(object): + + #__doc__ = _realsocket.__doc__ + + __slots__ = ["_sock", "__weakref__"] + list(_delegate_methods) + + def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, _sock=None): + if _sock is None: + _sock = _realsocket(family, type, proto) + self._sock = _sock + for method in _delegate_methods: + setattr(self, method, getattr(_sock, method)) + + def close(self, _closedsocket=_closedsocket, + _delegate_methods=_delegate_methods, setattr=setattr): + # This function should not reference any globals. See issue #808164. + self._sock = _closedsocket() + dummy = self._sock._dummy + for method in _delegate_methods: + setattr(self, method, dummy) + #close.__doc__ = _realsocket.close.__doc__ + + def accept(self): + sock, addr = self._sock.accept() + return _socketobject(_sock=sock), addr + #accept.__doc__ = _realsocket.accept.__doc__ + + def dup(self): + """dup() -> socket object + + Return a new socket object connected to the same system resource.""" + return _socketobject(_sock=self._sock) + + def makefile(self, mode='r', bufsize=-1): + """makefile([mode[, bufsize]]) -> file object + + Return a regular file object corresponding to the socket. The mode + and bufsize arguments are as for the built-in open() function.""" + return _fileobject(self._sock, mode, bufsize) + + family = property(lambda self: self._sock.family, doc="the socket family") + type = property(lambda self: self._sock.type, doc="the socket type") + proto = property(lambda self: self._sock.proto, doc="the socket protocol") + +def meth(name,self,*args): + return getattr(self._sock,name)(*args) + +for _m in _socketmethods: + p = partial(meth,_m) + p.__name__ = _m + #p.__doc__ = getattr(_realsocket,_m).__doc__ + m = MethodType(p,None,_socketobject) + setattr(_socketobject,_m,m) + +socket = SocketType = _socketobject + +class _fileobject(object): + """Faux file object attached to a socket object.""" + + default_bufsize = 8192 + name = "" + + __slots__ = ["mode", "bufsize", "softspace", + # "closed" is a property, see below + "_sock", "_rbufsize", "_wbufsize", "_rbuf", "_wbuf", "_wbuf_len", + "_close"] + + def __init__(self, sock, mode='rb', bufsize=-1, close=False): + self._sock = sock + self.mode = mode # Not actually used in this version + if bufsize < 0: + bufsize = self.default_bufsize + self.bufsize = bufsize + self.softspace = False + # _rbufsize is the suggested recv buffer size. It is *strictly* + # obeyed within readline() for recv calls. If it is larger than + # default_bufsize it will be used for recv calls within read(). + if bufsize == 0: + self._rbufsize = 1 + elif bufsize == 1: + self._rbufsize = self.default_bufsize + else: + self._rbufsize = bufsize + self._wbufsize = bufsize + # We use StringIO for the read buffer to avoid holding a list + # of variously sized string objects which have been known to + # fragment the heap due to how they are malloc()ed and often + # realloc()ed down much smaller than their original allocation. + self._rbuf = StringIO() + self._wbuf = [] # A list of strings + self._wbuf_len = 0 + self._close = close + + def _getclosed(self): + return self._sock is None + closed = property(_getclosed, doc="True if the file is closed") + + def close(self): + try: + if self._sock: + self.flush() + finally: + if self._close: + self._sock.close() + self._sock = None + + def __del__(self): + try: + self.close() + except: + # close() may fail if __init__ didn't complete + pass + + def flush(self): + if self._wbuf: + data = "".join(self._wbuf) + self._wbuf = [] + self._wbuf_len = 0 + buffer_size = max(self._rbufsize, self.default_bufsize) + data_size = len(data) + write_offset = 0 + view = data #memoryview(data) + try: + while write_offset < data_size: + self._sock.sendall(view[write_offset:write_offset+buffer_size]) + write_offset += buffer_size + finally: + if write_offset < data_size: + remainder = data[write_offset:] + del view, data # explicit free + self._wbuf.append(remainder) + self._wbuf_len = len(remainder) + + def fileno(self): + return self._sock.fileno() + + def write(self, data): + data = str(data) # XXX Should really reject non-string non-buffers + if not data: + return + self._wbuf.append(data) + self._wbuf_len += len(data) + if (self._wbufsize == 0 or + (self._wbufsize == 1 and '\n' in data) or + (self._wbufsize > 1 and self._wbuf_len >= self._wbufsize)): + self.flush() + + def writelines(self, list): + # XXX We could do better here for very long lists + # XXX Should really reject non-string non-buffers + lines = filter(None, map(str, list)) + self._wbuf_len += sum(map(len, lines)) + self._wbuf.extend(lines) + if (self._wbufsize <= 1 or + self._wbuf_len >= self._wbufsize): + self.flush() + + def read(self, size=-1): + # Use max, disallow tiny reads in a loop as they are very inefficient. + # We never leave read() with any leftover data from a new recv() call + # in our internal buffer. + rbufsize = max(self._rbufsize, self.default_bufsize) + # Our use of StringIO rather than lists of string objects returned by + # recv() minimizes memory usage and fragmentation that occurs when + # rbufsize is large compared to the typical return value of recv(). + buf = self._rbuf + buf.seek(0, 2) # seek end + if size < 0: + # Read until EOF + self._rbuf = StringIO() # reset _rbuf. we consume it via buf. + while True: + try: + data = self._sock.recv(rbufsize) + except error, e: + if e.args[0] == EINTR: + continue + raise + if not data: + break + buf.write(data) + return buf.getvalue() + else: + # Read until size bytes or EOF seen, whichever comes first + buf_len = buf.tell() + if buf_len >= size: + # Already have size bytes in our buffer? Extract and return. + buf.seek(0) + rv = buf.read(size) + self._rbuf = StringIO() + self._rbuf.write(buf.read()) + return rv + + self._rbuf = StringIO() # reset _rbuf. we consume it via buf. + while True: + left = size - buf_len + # recv() will malloc the amount of memory given as its + # parameter even though it often returns much less data + # than that. The returned data string is short lived + # as we copy it into a StringIO and free it. This avoids + # fragmentation issues on many platforms. + try: + data = self._sock.recv(left) + except error, e: + if e.args[0] == EINTR: + continue + raise + if not data: + break + n = len(data) + if n == size and not buf_len: + # Shortcut. Avoid buffer data copies when: + # - We have no data in our buffer. + # AND + # - Our call to recv returned exactly the + # number of bytes we were asked to read. + return data + if n == left: + buf.write(data) + del data # explicit free + break + assert n <= left, "recv(%d) returned %d bytes" % (left, n) + buf.write(data) + buf_len += n + del data # explicit free + #assert buf_len == buf.tell() + return buf.getvalue() + + def readline(self, size=-1): + buf = self._rbuf + buf.seek(0, 2) # seek end + if buf.tell() > 0: + # check if we already have it in our buffer + buf.seek(0) + bline = buf.readline(size) + if bline.endswith('\n') or len(bline) == size: + self._rbuf = StringIO() + self._rbuf.write(buf.read()) + return bline + del bline + if size < 0: + # Read until \n or EOF, whichever comes first + if self._rbufsize <= 1: + # Speed up unbuffered case + buf.seek(0) + buffers = [buf.read()] + self._rbuf = StringIO() # reset _rbuf. we consume it via buf. + data = None + recv = self._sock.recv + while True: + try: + while data != "\n": + data = recv(1) + if not data: + break + buffers.append(data) + except error, e: + # The try..except to catch EINTR was moved outside the + # recv loop to avoid the per byte overhead. + if e.args[0] == EINTR: + continue + raise + break + return "".join(buffers) + + buf.seek(0, 2) # seek end + self._rbuf = StringIO() # reset _rbuf. we consume it via buf. + while True: + try: + data = self._sock.recv(self._rbufsize) + except error, e: + if e.args[0] == EINTR: + continue + raise + if not data: + break + nl = data.find('\n') + if nl >= 0: + nl += 1 + buf.write(data[:nl]) + self._rbuf.write(data[nl:]) + del data + break + buf.write(data) + return buf.getvalue() + else: + # Read until size bytes or \n or EOF seen, whichever comes first + buf.seek(0, 2) # seek end + buf_len = buf.tell() + if buf_len >= size: + buf.seek(0) + rv = buf.read(size) + self._rbuf = StringIO() + self._rbuf.write(buf.read()) + return rv + self._rbuf = StringIO() # reset _rbuf. we consume it via buf. + while True: + try: + data = self._sock.recv(self._rbufsize) + except error, e: + if e.args[0] == EINTR: + continue + raise + if not data: + break + left = size - buf_len + # did we just receive a newline? + nl = data.find('\n', 0, left) + if nl >= 0: + nl += 1 + # save the excess data to _rbuf + self._rbuf.write(data[nl:]) + if buf_len: + buf.write(data[:nl]) + break + else: + # Shortcut. Avoid data copy through buf when returning + # a substring of our first recv(). + return data[:nl] + n = len(data) + if n == size and not buf_len: + # Shortcut. Avoid data copy through buf when + # returning exactly all of our first recv(). + return data + if n >= left: + buf.write(data[:left]) + self._rbuf.write(data[left:]) + break + buf.write(data) + buf_len += n + #assert buf_len == buf.tell() + return buf.getvalue() + + def readlines(self, sizehint=0): + total = 0 + list = [] + while True: + line = self.readline() + if not line: + break + list.append(line) + total += len(line) + if sizehint and total >= sizehint: + break + return list + + # Iterator protocols + + def __iter__(self): + return self + + def next(self): + line = self.readline() + if not line: + raise StopIteration + return line + +_GLOBAL_DEFAULT_TIMEOUT = object() + +def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT, + source_address=None): + """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. + """ + + host, port = address + err = None + 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) + return sock + + except error as _: + err = _ + if sock is not None: + sock.close() + + if err is not None: + raise err + else: + raise error("getaddrinfo returns an empty list") \ No newline at end of file