PageRenderTime 56ms CodeModel.GetById 19ms app.highlight 32ms RepoModel.GetById 1ms app.codeStats 0ms

/kbe/res/scripts/common/Lib/socket.py

https://github.com/yhcflyy/kbengine
Python | 428 lines | 323 code | 15 blank | 90 comment | 29 complexity | f199eb68f06adea34412a742573cec01 MD5 | raw file
  1# Wrapper module for _socket, providing some additional facilities
  2# implemented in Python.
  3
  4"""\
  5This module provides socket operations and some related functions.
  6On Unix, it supports IP (Internet Protocol) and Unix domain sockets.
  7On other systems, it only supports IP. Functions specific for a
  8socket are available as methods of the socket object.
  9
 10Functions:
 11
 12socket() -- create a new socket object
 13socketpair() -- create a pair of new socket objects [*]
 14fromfd() -- create a socket object from an open file descriptor [*]
 15gethostname() -- return the current hostname
 16gethostbyname() -- map a hostname to its IP number
 17gethostbyaddr() -- map an IP number or hostname to DNS info
 18getservbyname() -- map a service name and a protocol name to a port number
 19getprotobyname() -- map a protocol name (e.g. 'tcp') to a number
 20ntohs(), ntohl() -- convert 16, 32 bit int from network to host byte order
 21htons(), htonl() -- convert 16, 32 bit int from host to network byte order
 22inet_aton() -- convert IP addr string (123.45.67.89) to 32-bit packed format
 23inet_ntoa() -- convert 32-bit packed format IP to string (123.45.67.89)
 24socket.getdefaulttimeout() -- get the default timeout value
 25socket.setdefaulttimeout() -- set the default timeout value
 26create_connection() -- connects to an address, with an optional timeout and
 27                       optional source address.
 28
 29 [*] not available on all platforms!
 30
 31Special objects:
 32
 33SocketType -- type object for socket objects
 34error -- exception raised for I/O errors
 35has_ipv6 -- boolean value indicating if IPv6 is supported
 36
 37Integer constants:
 38
 39AF_INET, AF_UNIX -- socket domains (first argument to socket() call)
 40SOCK_STREAM, SOCK_DGRAM, SOCK_RAW -- socket types (second argument)
 41
 42Many other constants may be defined; these may be used in calls to
 43the setsockopt() and getsockopt() methods.
 44"""
 45
 46import _socket
 47from _socket import *
 48
 49import os, sys, io
 50
 51try:
 52    import errno
 53except ImportError:
 54    errno = None
 55EBADF = getattr(errno, 'EBADF', 9)
 56EINTR = getattr(errno, 'EINTR', 4)
 57EAGAIN = getattr(errno, 'EAGAIN', 11)
 58EWOULDBLOCK = getattr(errno, 'EWOULDBLOCK', 11)
 59
 60__all__ = ["getfqdn", "create_connection"]
 61__all__.extend(os._get_exports_list(_socket))
 62
 63
 64_realsocket = socket
 65
 66# WSA error codes
 67if sys.platform.lower().startswith("win"):
 68    errorTab = {}
 69    errorTab[10004] = "The operation was interrupted."
 70    errorTab[10009] = "A bad file handle was passed."
 71    errorTab[10013] = "Permission denied."
 72    errorTab[10014] = "A fault occurred on the network??" # WSAEFAULT
 73    errorTab[10022] = "An invalid operation was attempted."
 74    errorTab[10035] = "The socket operation would block"
 75    errorTab[10036] = "A blocking operation is already in progress."
 76    errorTab[10048] = "The network address is in use."
 77    errorTab[10054] = "The connection has been reset."
 78    errorTab[10058] = "The network has been shut down."
 79    errorTab[10060] = "The operation timed out."
 80    errorTab[10061] = "Connection refused."
 81    errorTab[10063] = "The name is too long."
 82    errorTab[10064] = "The host is down."
 83    errorTab[10065] = "The host is unreachable."
 84    __all__.append("errorTab")
 85
 86
 87class socket(_socket.socket):
 88
 89    """A subclass of _socket.socket adding the makefile() method."""
 90
 91    __slots__ = ["__weakref__", "_io_refs", "_closed"]
 92
 93    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
 94        _socket.socket.__init__(self, family, type, proto, fileno)
 95        self._io_refs = 0
 96        self._closed = False
 97
 98    def __enter__(self):
 99        return self
100
101    def __exit__(self, *args):
102        if not self._closed:
103            self.close()
104
105    def __repr__(self):
106        """Wrap __repr__() to reveal the real class name."""
107        s = _socket.socket.__repr__(self)
108        if s.startswith("<socket object"):
109            s = "<%s.%s%s%s" % (self.__class__.__module__,
110                                self.__class__.__name__,
111                                getattr(self, '_closed', False) and " [closed] " or "",
112                                s[7:])
113        return s
114
115    def dup(self):
116        """dup() -> socket object
117
118        Return a new socket object connected to the same system resource.
119        """
120        fd = dup(self.fileno())
121        sock = self.__class__(self.family, self.type, self.proto, fileno=fd)
122        sock.settimeout(self.gettimeout())
123        return sock
124
125    def accept(self):
126        """accept() -> (socket object, address info)
127
128        Wait for an incoming connection.  Return a new socket
129        representing the connection, and the address of the client.
130        For IP sockets, the address info is a pair (hostaddr, port).
131        """
132        fd, addr = self._accept()
133        sock = socket(self.family, self.type, self.proto, fileno=fd)
134        # Issue #7995: if no default timeout is set and the listening
135        # socket had a (non-zero) timeout, force the new socket in blocking
136        # mode to override platform-specific socket flags inheritance.
137        if getdefaulttimeout() is None and self.gettimeout():
138            sock.setblocking(True)
139        return sock, addr
140
141    def makefile(self, mode="r", buffering=None, *,
142                 encoding=None, errors=None, newline=None):
143        """makefile(...) -> an I/O stream connected to the socket
144
145        The arguments are as for io.open() after the filename,
146        except the only mode characters supported are 'r', 'w' and 'b'.
147        The semantics are similar too.  (XXX refactor to share code?)
148        """
149        for c in mode:
150            if c not in {"r", "w", "b"}:
151                raise ValueError("invalid mode %r (only r, w, b allowed)")
152        writing = "w" in mode
153        reading = "r" in mode or not writing
154        assert reading or writing
155        binary = "b" in mode
156        rawmode = ""
157        if reading:
158            rawmode += "r"
159        if writing:
160            rawmode += "w"
161        raw = SocketIO(self, rawmode)
162        self._io_refs += 1
163        if buffering is None:
164            buffering = -1
165        if buffering < 0:
166            buffering = io.DEFAULT_BUFFER_SIZE
167        if buffering == 0:
168            if not binary:
169                raise ValueError("unbuffered streams must be binary")
170            return raw
171        if reading and writing:
172            buffer = io.BufferedRWPair(raw, raw, buffering)
173        elif reading:
174            buffer = io.BufferedReader(raw, buffering)
175        else:
176            assert writing
177            buffer = io.BufferedWriter(raw, buffering)
178        if binary:
179            return buffer
180        text = io.TextIOWrapper(buffer, encoding, errors, newline)
181        text.mode = mode
182        return text
183
184    def _decref_socketios(self):
185        if self._io_refs > 0:
186            self._io_refs -= 1
187        if self._closed:
188            self.close()
189
190    def _real_close(self, _ss=_socket.socket):
191        # This function should not reference any globals. See issue #808164.
192        _ss.close(self)
193
194    def close(self):
195        # This function should not reference any globals. See issue #808164.
196        self._closed = True
197        if self._io_refs <= 0:
198            self._real_close()
199
200    def detach(self):
201        """detach() -> file descriptor
202
203        Close the socket object without closing the underlying file descriptor.
204        The object cannot be used after this call, but the file descriptor
205        can be reused for other purposes.  The file descriptor is returned.
206        """
207        self._closed = True
208        return super().detach()
209
210
211def fromfd(fd, family, type, proto=0):
212    """ fromfd(fd, family, type[, proto]) -> socket object
213
214    Create a socket object from a duplicate of the given file
215    descriptor.  The remaining arguments are the same as for socket().
216    """
217    nfd = dup(fd)
218    return socket(family, type, proto, nfd)
219
220
221if hasattr(_socket, "socketpair"):
222
223    def socketpair(family=None, type=SOCK_STREAM, proto=0):
224        """socketpair([family[, type[, proto]]]) -> (socket object, socket object)
225
226        Create a pair of socket objects from the sockets returned by the platform
227        socketpair() function.
228        The arguments are the same as for socket() except the default family is
229        AF_UNIX if defined on the platform; otherwise, the default is AF_INET.
230        """
231        if family is None:
232            try:
233                family = AF_UNIX
234            except NameError:
235                family = AF_INET
236        a, b = _socket.socketpair(family, type, proto)
237        a = socket(family, type, proto, a.detach())
238        b = socket(family, type, proto, b.detach())
239        return a, b
240
241
242_blocking_errnos = { EAGAIN, EWOULDBLOCK }
243
244class SocketIO(io.RawIOBase):
245
246    """Raw I/O implementation for stream sockets.
247
248    This class supports the makefile() method on sockets.  It provides
249    the raw I/O interface on top of a socket object.
250    """
251
252    # One might wonder why not let FileIO do the job instead.  There are two
253    # main reasons why FileIO is not adapted:
254    # - it wouldn't work under Windows (where you can't used read() and
255    #   write() on a socket handle)
256    # - it wouldn't work with socket timeouts (FileIO would ignore the
257    #   timeout and consider the socket non-blocking)
258
259    # XXX More docs
260
261    def __init__(self, sock, mode):
262        if mode not in ("r", "w", "rw", "rb", "wb", "rwb"):
263            raise ValueError("invalid mode: %r" % mode)
264        io.RawIOBase.__init__(self)
265        self._sock = sock
266        if "b" not in mode:
267            mode += "b"
268        self._mode = mode
269        self._reading = "r" in mode
270        self._writing = "w" in mode
271        self._timeout_occurred = False
272
273    def readinto(self, b):
274        """Read up to len(b) bytes into the writable buffer *b* and return
275        the number of bytes read.  If the socket is non-blocking and no bytes
276        are available, None is returned.
277
278        If *b* is non-empty, a 0 return value indicates that the connection
279        was shutdown at the other end.
280        """
281        self._checkClosed()
282        self._checkReadable()
283        if self._timeout_occurred:
284            raise IOError("cannot read from timed out object")
285        while True:
286            try:
287                return self._sock.recv_into(b)
288            except timeout:
289                self._timeout_occurred = True
290                raise
291            except error as e:
292                n = e.args[0]
293                if n == EINTR:
294                    continue
295                if n in _blocking_errnos:
296                    return None
297                raise
298
299    def write(self, b):
300        """Write the given bytes or bytearray object *b* to the socket
301        and return the number of bytes written.  This can be less than
302        len(b) if not all data could be written.  If the socket is
303        non-blocking and no bytes could be written None is returned.
304        """
305        self._checkClosed()
306        self._checkWritable()
307        try:
308            return self._sock.send(b)
309        except error as e:
310            # XXX what about EINTR?
311            if e.args[0] in _blocking_errnos:
312                return None
313            raise
314
315    def readable(self):
316        """True if the SocketIO is open for reading.
317        """
318        if self.closed:
319            raise ValueError("I/O operation on closed socket.")
320        return self._reading
321
322    def writable(self):
323        """True if the SocketIO is open for writing.
324        """
325        if self.closed:
326            raise ValueError("I/O operation on closed socket.")
327        return self._writing
328
329    def seekable(self):
330        """True if the SocketIO is open for seeking.
331        """
332        if self.closed:
333            raise ValueError("I/O operation on closed socket.")
334        return super().seekable()
335
336    def fileno(self):
337        """Return the file descriptor of the underlying socket.
338        """
339        self._checkClosed()
340        return self._sock.fileno()
341
342    @property
343    def name(self):
344        if not self.closed:
345            return self.fileno()
346        else:
347            return -1
348
349    @property
350    def mode(self):
351        return self._mode
352
353    def close(self):
354        """Close the SocketIO object.  This doesn't close the underlying
355        socket, except if all references to it have disappeared.
356        """
357        if self.closed:
358            return
359        io.RawIOBase.close(self)
360        self._sock._decref_socketios()
361        self._sock = None
362
363
364def getfqdn(name=''):
365    """Get fully qualified domain name from name.
366
367    An empty argument is interpreted as meaning the local host.
368
369    First the hostname returned by gethostbyaddr() is checked, then
370    possibly existing aliases. In case no FQDN is available, hostname
371    from gethostname() is returned.
372    """
373    name = name.strip()
374    if not name or name == '0.0.0.0':
375        name = gethostname()
376    try:
377        hostname, aliases, ipaddrs = gethostbyaddr(name)
378    except error:
379        pass
380    else:
381        aliases.insert(0, hostname)
382        for name in aliases:
383            if '.' in name:
384                break
385        else:
386            name = hostname
387    return name
388
389
390_GLOBAL_DEFAULT_TIMEOUT = object()
391
392def create_connection(address, timeout=_GLOBAL_DEFAULT_TIMEOUT,
393                      source_address=None):
394    """Connect to *address* and return the socket object.
395
396    Convenience function.  Connect to *address* (a 2-tuple ``(host,
397    port)``) and return the socket object.  Passing the optional
398    *timeout* parameter will set the timeout on the socket instance
399    before attempting to connect.  If no *timeout* is supplied, the
400    global default timeout setting returned by :func:`getdefaulttimeout`
401    is used.  If *source_address* is set it must be a tuple of (host, port)
402    for the socket to bind as a source address before making the connection.
403    An host of '' or port 0 tells the OS to use the default.
404    """
405
406    host, port = address
407    err = None
408    for res in getaddrinfo(host, port, 0, SOCK_STREAM):
409        af, socktype, proto, canonname, sa = res
410        sock = None
411        try:
412            sock = socket(af, socktype, proto)
413            if timeout is not _GLOBAL_DEFAULT_TIMEOUT:
414                sock.settimeout(timeout)
415            if source_address:
416                sock.bind(source_address)
417            sock.connect(sa)
418            return sock
419
420        except error as _:
421            err = _
422            if sock is not None:
423                sock.close()
424
425    if err is not None:
426        raise err
427    else:
428        raise error("getaddrinfo returns an empty list")