socket.py 9.47 KB
Newer Older
1 2 3 4 5 6
# 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.
Tim Peters's avatar
Tim Peters committed
7
On other systems, it only supports IP. Functions specific for a
8
socket are available as methods of the socket object.
9 10 11 12

Functions:

socket() -- create a new socket object
13
socketpair() -- create a pair of new socket objects [*]
14 15 16 17 18 19 20 21 22 23
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() -- mape 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)
24 25
socket.getdefaulttimeout() -- get the default timeout value
socket.setdefaulttimeout() -- set the default timeout value
26
create_connection() -- connects to an address, with an optional timeout
27 28 29 30 31 32 33

 [*] not available on all platforms!

Special objects:

SocketType -- type object for socket objects
error -- exception raised for I/O errors
34
has_ipv6 -- boolean value indicating if IPv6 is supported
35 36 37 38 39 40 41 42 43 44

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.
"""

45
import _socket
46
from _socket import *
47

48
import os, sys, io
49

50 51 52 53 54
try:
    from errno import EBADF
except ImportError:
    EBADF = 9

55 56
__all__ = ["getfqdn"]
__all__.extend(os._get_exports_list(_socket))
57 58 59


_realsocket = socket
60

61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
# 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."
79
    __all__.append("errorTab")
80

81

82 83
# True if os.dup() can duplicate socket descriptors.
# (On Windows at least, os.dup only works on files)
84
_can_dup_socket = hasattr(_socket.socket, "dup")
85 86

if _can_dup_socket:
87 88 89 90 91 92 93 94
    def fromfd(fd, family=AF_INET, type=SOCK_STREAM, proto=0):
        nfd = os.dup(fd)
        return socket(family, type, proto, fileno=nfd)

class socket(_socket.socket):

    """A subclass of _socket.socket adding the makefile() method."""

95
    __slots__ = ["__weakref__", "_io_refs", "_closed"]
96
    if not _can_dup_socket:
97 98
        __slots__.append("_base")

99 100 101 102 103
    def __init__(self, family=AF_INET, type=SOCK_STREAM, proto=0, fileno=None):
        if fileno is None:
            _socket.socket.__init__(self, family, type, proto)
        else:
            _socket.socket.__init__(self, family, type, proto, fileno)
104 105
        self._io_refs = 0
        self._closed = False
106

107 108 109 110
    def __repr__(self):
        """Wrap __repr__() to reveal the real class name."""
        s = _socket.socket.__repr__(self)
        if s.startswith("<socket object"):
111 112 113 114
            s = "<%s.%s%s%s" % (self.__class__.__module__,
                                self.__class__.__name__,
                                (self._closed and " [closed] ") or "",
                                s[7:])
115 116 117 118 119 120 121
        return s

    def accept(self):
        """Wrap accept() to give the connection the right type."""
        conn, addr = _socket.socket.accept(self)
        fd = conn.fileno()
        nfd = fd
122
        if _can_dup_socket:
123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150
            nfd = os.dup(fd)
        wrapper = socket(self.family, self.type, self.proto, fileno=nfd)
        if fd == nfd:
            wrapper._base = conn  # Keep the base alive
        else:
            conn.close()
        return wrapper, addr

    def makefile(self, mode="r", buffering=None, *,
                 encoding=None, newline=None):
        """Return an I/O stream connected to the socket.

        The arguments are as for io.open() after the filename,
        except the only mode characters supported are 'r', 'w' and 'b'.
        The semantics are similar too.  (XXX refactor to share code?)
        """
        for c in mode:
            if c not in {"r", "w", "b"}:
                raise ValueError("invalid mode %r (only r, w, b allowed)")
        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"
151 152
        raw = SocketIO(self, rawmode)
        self._io_refs += 1
153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175
        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")
            raw.name = self.fileno()
            raw.mode = mode
            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:
            buffer.name = self.fileno()
            buffer.mode = mode
            return buffer
        text = io.TextIOWrapper(buffer, encoding, newline)
        text.name = self.fileno()
176
        text.mode = mode
177 178
        return text

179 180 181 182 183 184
    def _decref_socketios(self):
        if self._io_refs > 0:
            self._io_refs -= 1
        if self._closed:
            self.close()

185
    def close(self):
186 187
        self._closed = True
        if self._io_refs < 1:
188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213
            self._real_close()

    # _real_close calls close on the _socket.socket base class.

    if not _can_dup_socket:
        def _real_close(self):
            _socket.socket.close(self)
            base = getattr(self, "_base", None)
            if base is not None:
                self._base = None
                base.close()
    else:
        def _real_close(self):
            _socket.socket.close(self)


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.
    """

    # XXX More docs

214
    def __init__(self, sock, mode):
215 216
        if mode not in ("r", "w", "rw"):
            raise ValueError("invalid mode: %r" % mode)
217 218 219
        io.RawIOBase.__init__(self)
        self._sock = sock
        self._mode = mode
220 221
        self._reading = "r" in mode
        self._writing = "w" in mode
222 223

    def readinto(self, b):
224 225
        self._checkClosed()
        self._checkReadable()
226 227 228
        return self._sock.recv_into(b)

    def write(self, b):
229 230
        self._checkClosed()
        self._checkWritable()
231 232 233
        return self._sock.send(b)

    def readable(self):
234
        return self._reading and not self.closed
235 236

    def writable(self):
237
        return self._writing and not self.closed
238 239 240 241 242 243 244 245 246

    def fileno(self):
        return self._sock.fileno()

    def close(self):
        if self.closed:
            return
        io.RawIOBase.close(self)

247 248 249
    def __del__(self):
        self._sock._decref_socketios()

250 251 252 253 254 255 256 257

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
258
    from gethostname() is returned.
259 260
    """
    name = name.strip()
261
    if not name or name == '0.0.0.0':
262 263 264 265 266 267 268 269 270 271 272 273 274 275 276
        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


277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303
def create_connection(address, timeout=None):
    """Connect to address (host, port) with an optional timeout.

    Provides access to socketobject timeout for higher-level
    protocols.  Passing a timeout will set the timeout on the
    socket instance (if not present, or passed as None, the
    default global timeout setting will be used).
    """

    msg = "getaddrinfo returns an empty list"
    host, port = address
    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 None:
                sock.settimeout(timeout)
            sock.connect(sa)
            return sock

        except error as err:
            msg = err
            if sock is not None:
                sock.close()

    raise error(msg)