[pypy-svn] r32599 - in pypy/dist/pypy: module/_socket module/_socket/test rpython/rctypes/socketmodule

arigo at codespeak.net arigo at codespeak.net
Fri Sep 22 23:20:00 CEST 2006


Author: arigo
Date: Fri Sep 22 23:19:57 2006
New Revision: 32599

Added:
   pypy/dist/pypy/module/_socket/test/test_rsocket.py   (contents, props changed)
Modified:
   pypy/dist/pypy/module/_socket/rsocket.py
   pypy/dist/pypy/rpython/rctypes/socketmodule/ctypes_socket.py
Log:
More on rsocket.  Time to switch to test-driven development...


Modified: pypy/dist/pypy/module/_socket/rsocket.py
==============================================================================
--- pypy/dist/pypy/module/_socket/rsocket.py	(original)
+++ pypy/dist/pypy/module/_socket/rsocket.py	Fri Sep 22 23:19:57 2006
@@ -7,6 +7,9 @@
 #                ------------ IN - PROGRESS -----------
 
 from pypy.rpython.objectmodel import instantiate
+from pypy.rpython.rctypes.socketmodule import ctypes_socket as _c   # MOVE ME
+from ctypes import cast, POINTER, c_char, c_char_p, pointer, byref
+from ctypes import create_string_buffer, sizeof
 
 
 class Address(object):
@@ -28,7 +31,7 @@
         # If we don't know the address family, don't raise an
         # exception -- return it as a tuple.
         family = self.addr.sa_family
-        buf = copy_buffer(cast(pointer(self.addr.sa_data), POINTER(char)),
+        buf = copy_buffer(cast(pointer(self.addr.sa_data), POINTER(c_char)),
                           self.addrlen - offsetof(_c.sockaddr_un, 'sa_data'))
         return space.newtuple([space.wrap(family),
                                space.wrap(buf.raw)])
@@ -66,7 +69,7 @@
                 if info.ai_next:
                     raise SocketError("wildcard resolved to "
                                       "multiple addresses")
-                self.raw_to_addr(cast(info.ai_addr, POINTER(char)),
+                self.raw_to_addr(cast(info.ai_addr, POINTER(c_char)),
                                  info.ai_addrlen)
             finally:
                 _c.freeaddrinfo(res)
@@ -105,7 +108,7 @@
             raise GAIError(error)
         try:
             info = res.contents
-            self.raw_to_addr(cast(info.ai_addr, POINTER(char)),
+            self.raw_to_addr(cast(info.ai_addr, POINTER(c_char)),
                              info.ai_addrlen)
         finally:
             _c.freeaddrinfo(res)
@@ -116,7 +119,7 @@
         # (with variable size numbers).
         buf = create_string_buffer(_c.NI_MAXHOST)
         error = _c.getnameinfo(byref(self.addr), self.addrlen,
-                               byref(buf), _c.NI_MAXHOST,
+                               buf, _c.NI_MAXHOST,
                                None, 0, _c.NI_NUMERICHOST)
         if error:
             raise GAIError(error)
@@ -247,7 +250,7 @@
         a = self.as_sockaddr_un()
         if _c.linux and a.sun_path[0] == '\x00':
             # Linux abstract namespace
-            buf = copy_buffer(cast(pointer(a.sun_path), POINTER(char)),
+            buf = copy_buffer(cast(pointer(a.sun_path), POINTER(c_char)),
                            self.addrlen - offsetof(_c.sockaddr_un, 'sun_path'))
             return buf.raw
         else:
@@ -293,7 +296,7 @@
 def copy_buffer(ptr, size):
     buf = create_string_buffer(size)
     for i in range(size):
-        buf[i] = ptr.contents[i]
+        buf[i] = ptr[i]
     return buf
 
 # ____________________________________________________________
@@ -306,13 +309,16 @@
         """Create a new socket."""
         fd = _c.socket(family, type, proto)
         if _c.invalid_socket(fd):
-            raise last_error()
+            raise self.error_handler()
         # PLAT RISCOS
         self.fd = fd
         self.family = family
         self.type = type
         self.proto = proto
 
+    def error_handler(self):
+        return CSocketError(_c.errno())
+
     # convert an Address into an app-level object
     def addr_as_object(self, space, address):
         return address.as_object(space)
@@ -353,9 +359,17 @@
     def connect(self, address):
         """Connect the socket to a remote address."""
         res = _c.socketconnect(self.fd, byref(address.addr), address.addrlen)
-        if res < 0:
+        if res != 0:
             raise self.error_handler()
 
+    def connect_ex(self, address):
+        """This is like connect(address), but returns an error code (the errno
+        value) instead of raising an exception when an error occurs."""
+        return _c.socketconnect(self.fd, byref(address.addr), address.addrlen)
+
+    def fileno(self):
+        return self.fd
+
     def getsockname(self):
         """Return the address of the local endpoint."""
         address = self.null_addr()
@@ -388,13 +402,65 @@
         if res < 0:
             raise self.error_handler()
 
-    def recv(self, nbytes, flags=0):
+    def recv(self, buffersize, flags=0):
         """Receive up to buffersize bytes from the socket.  For the optional
         flags argument, see the Unix manual.  When no data is available, block
         until at least one byte is available or until the remote end is closed.
         When the remote end is closed and all data is read, return the empty
         string."""
-        IN-PROGRESS
+        buf = create_string_buffer(buffersize)
+        read_bytes = _c.socketrecv(self.fd, buf, buffersize, flags)
+        if read_bytes < 0:
+            raise self.error_handler()
+        return buf[:read_bytes]
+
+    def recvfrom(self, buffersize, flags=0):
+        """Like recv(buffersize, flags) but also return the sender's
+        address."""
+        buf = create_string_buffer(buffersize)
+        address = self.null_addr()
+        addrlen = _c.socklen_t()
+        read_bytes = _c.socketrecvfrom(self.fd, buf, buffersize, flags,
+                                       byref(address.addr), byref(addrlen))
+        if read_bytes < 0:
+            raise self.error_handler()
+        address.addrlen = addrlen.value
+        return (buf[:read_bytes], address)
+
+    def send(self, data, flags=0):
+        """Send a data string to the socket.  For the optional flags
+        argument, see the Unix manual.  Return the number of bytes
+        sent; this may be less than len(data) if the network is busy."""
+        res = _c.socketsend(self.fd, data, len(data), flags)
+        if res < 0:
+            raise self.error_handler()
+        return res
+
+    def sendall(self, data, flags=0):
+        """Send a data string to the socket.  For the optional flags
+        argument, see the Unix manual.  This calls send() repeatedly
+        until all data is sent.  If an error occurs, it's impossible
+        to tell how much data has been sent."""
+        while data:
+            res = self.send(data, flags)
+            data = data[res:]
+
+    def sendto(self, data, flags, address):
+        """Like send(data, flags) but allows specifying the destination
+        address.  (Note that 'flags' is mandatory here.)"""
+        res = _c.socketsendto(self.fd, data, len(data), flags,
+                              byref(address.addr), address.addrlen)
+        if res < 0:
+            raise self.error_handler()
+        return res
+
+    def shutdown(self, how):
+        """Shut down the reading side of the socket (flag == SHUT_RD), the
+        writing side of the socket (flag == SHUT_WR), or both ends
+        (flag == SHUT_RDWR)."""
+        res = _c.socketshutdown(self.fd, how)
+        if res < 0:
+            raise self.error_handler()
 
 # ____________________________________________________________
 
@@ -405,3 +471,24 @@
     result.type = type
     result.proto = proto
     return result
+
+class BaseSocketError(Exception):
+    pass
+
+class SocketError(BaseSocketError):
+    def __init__(self, message):
+        self.message = message
+    def __str__(self):
+        return self.message
+
+class CSocketError(BaseSocketError):
+    def __init__(self, errno):
+        self.errno = errno
+    def __str__(self):
+        return _c.socket_strerror(self.errno)
+
+class GAIError(BaseSocketError):
+    def __init__(self, errno):
+        self.errno = errno
+    def __str__(self):
+        return _c.gai_strerror(self.errno)

Added: pypy/dist/pypy/module/_socket/test/test_rsocket.py
==============================================================================
--- (empty file)
+++ pypy/dist/pypy/module/_socket/test/test_rsocket.py	Fri Sep 22 23:19:57 2006
@@ -0,0 +1,14 @@
+import py
+from pypy.module._socket.rsocket import *
+
+def test_ipv4_addr():
+    a = INETAddress("localhost", 4000)
+    assert a.get_host() == "127.0.0.1"
+    assert a.get_port() == 4000
+    a = INETAddress("", 4001)
+    assert a.get_host() == "0.0.0.0"
+    assert a.get_port() == 4001
+    a = INETAddress("<broadcast>", 47002)
+    assert a.get_host() == "255.255.255.255"
+    assert a.get_port() == 47002
+    py.test.raises(GAIError, INETAddress, "no such host exists", 47003)

Modified: pypy/dist/pypy/rpython/rctypes/socketmodule/ctypes_socket.py
==============================================================================
--- pypy/dist/pypy/rpython/rctypes/socketmodule/ctypes_socket.py	(original)
+++ pypy/dist/pypy/rpython/rctypes/socketmodule/ctypes_socket.py	Fri Sep 22 23:19:57 2006
@@ -6,7 +6,7 @@
 # Not used here, but exported for other code.
 from pypy.rpython.rctypes.aerrno import geterrno
 
-from ctypes import c_ushort, c_int, c_uint, c_char_p, c_void_p
+from ctypes import c_ushort, c_int, c_uint, c_char_p, c_void_p, c_char
 from ctypes import POINTER, ARRAY, cdll, sizeof, SetPointerType
 
 # Also not used here, but exported for other code.
@@ -14,6 +14,7 @@
 
 includes = ('sys/types.h',
             'sys/socket.h',
+            'sys/un.h',
             'netinet/in.h',
             'netinet/tcp.h',
             'unistd.h',
@@ -32,7 +33,11 @@
     O_NONBLOCK = ctypes_platform.ConstantInteger('O_NONBLOCK')
     F_GETFL = ctypes_platform.ConstantInteger('F_GETFL')
     F_SETFL = ctypes_platform.ConstantInteger('F_SETFL')
-    
+
+    linux      = ctypes_platform.Defined('linux')
+    MS_WINDOWS = ctypes_platform.Defined('MS_WINDOWS')
+    INVALID_SOCKET = ctypes_platform.DefinedConstantInteger('INVALID_SOCKET')
+
 constant_names = ['AF_APPLETALK', 'AF_ASH', 'AF_ATMPVC', 'AF_ATMSVC', 'AF_AX25',
                   'AF_BLUETOOTH', 'AF_BRIDGE', 'AF_ECONET', 'AF_INET', 'AF_INET6',
                   'AF_IPX', 'AF_IRDA', 'AF_KEY', 'AF_NETBEUI', 'AF_NETLINK',
@@ -107,7 +112,7 @@
 # struct types
 CConfig.sockaddr = ctypes_platform.Struct('struct sockaddr',
                                              [('sa_family', c_int),
-                                              ])
+                                              ('sa_data', c_char * 0)])
 sockaddr_ptr = POINTER('sockaddr')
 CConfig.in_addr = ctypes_platform.Struct('struct in_addr',
                                          [('s_addr', c_uint)])
@@ -116,10 +121,15 @@
                                          ('sin_port',   c_ushort),
                                          ('sin_addr',   CConfig.in_addr)])
 
-CConfig.sockaddr_in6  = ctypes_platform.Struct('struct sockaddr_in6',
-                                               [('sin6_flowinfo', c_int),
-                                                ('sin6_scope_id', c_int),
-                                                ])
+CConfig.sockaddr_in6 = ctypes_platform.Struct('struct sockaddr_in6',
+                                              [('sin6_family', c_int),
+                                               ('sin6_flowinfo', c_int),
+                                               ('sin6_scope_id', c_int)])
+
+CConfig.sockaddr_un = ctypes_platform.Struct('struct sockaddr_un',
+                                             [('sun_family', c_int),
+                                              ('sun_path', c_char * 0)])
+
 addrinfo_ptr = POINTER("addrinfo")
 CConfig.addrinfo = ctypes_platform.Struct('struct addrinfo',
                                      [('ai_flags', c_int),
@@ -171,6 +181,17 @@
 F_GETFL = cConfig.F_GETFL
 F_SETFL = cConfig.F_SETFL
 
+linux = cConfig.linux
+MS_WINDOWS = cConfig.MS_WINDOWS
+if MS_WINDOWS:
+    def invalid_socket(fd):
+        return fd == INVALID_SOCKET
+    INVALID_SOCKET = cConfig.INVALID_SOCKET
+else:
+    def invalid_socket(fd):
+        return fd < 0
+    INVALID_SOCKET = -1
+
 uint16_t = cConfig.uint16_t
 uint32_t = cConfig.uint32_t
 size_t = cConfig.size_t
@@ -180,6 +201,7 @@
 sockaddr_size = sizeof(sockaddr)
 sockaddr_in = cConfig.sockaddr_in
 sockaddr_in6 = cConfig.sockaddr_in6
+sockaddr_un = cConfig.sockaddr_un
 in_addr = cConfig.in_addr
 in_addr_size = sizeof(in_addr)
 addrinfo = cConfig.addrinfo
@@ -217,7 +239,12 @@
 socket.argtypes = [c_int, c_int, c_int]
 socket.restype = c_int
 
-socketclose = os.close
+if MS_WINDOWS:
+    socketclose = socketdll.closesocket
+    socketclose.argtypes = [c_int]
+    socketclose.restype = c_int
+else:
+    socketclose = os.close
 
 socketconnect = socketdll.connect
 socketconnect.argtypes = [c_int, sockaddr_ptr, socklen_t]
@@ -262,10 +289,6 @@
 inet_ntoa.argtypes = [in_addr]
 inet_ntoa.restype = c_char_p
 
-close = socketdll.close
-close.argtypes = [c_int]
-close.restype = c_int
-
 socketaccept = socketdll.accept
 socketaccept.argtypes = [c_int, sockaddr_ptr, POINTER(socklen_t)]
 socketaccept.restype = c_int
@@ -367,3 +390,70 @@
 shutdown = socketdll.shutdown
 shutdown.argtypes = [c_int, c_int]
 shutdown.restype = c_int
+
+
+if MS_WINDOWS:
+    WIN32_ERROR_MESSAGES = {
+        errno.WSAEINTR:  "Interrupted system call",
+        errno.WSAEBADF:  "Bad file descriptor",
+        errno.WSAEACCES: "Permission denied",
+        errno.WSAEFAULT: "Bad address",
+        errno.WSAEINVAL: "Invalid argument",
+        errno.WSAEMFILE: "Too many open files",
+        errno.WSAEWOULDBLOCK:
+          "The socket operation could not complete without blocking",
+        errno.WSAEINPROGRESS: "Operation now in progress",
+        errno.WSAEALREADY: "Operation already in progress",
+        errno.WSAENOTSOCK: "Socket operation on non-socket",
+        errno.WSAEDESTADDRREQ: "Destination address required",
+        errno.WSAEMSGSIZE: "Message too long",
+        errno.WSAEPROTOTYPE: "Protocol wrong type for socket",
+        errno.WSAENOPROTOOPT: "Protocol not available",
+        errno.WSAEPROTONOSUPPORT: "Protocol not supported",
+        errno.WSAESOCKTNOSUPPORT: "Socket type not supported",
+        errno.WSAEOPNOTSUPP: "Operation not supported",
+        errno.WSAEPFNOSUPPORT: "Protocol family not supported",
+        errno.WSAEAFNOSUPPORT: "Address family not supported",
+        errno.WSAEADDRINUSE: "Address already in use",
+        errno.WSAEADDRNOTAVAIL: "Can't assign requested address",
+        errno.WSAENETDOWN: "Network is down",
+        errno.WSAENETUNREACH: "Network is unreachable",
+        errno.WSAENETRESET: "Network dropped connection on reset",
+        errno.WSAECONNABORTED: "Software caused connection abort",
+        errno.WSAECONNRESET: "Connection reset by peer",
+        errno.WSAENOBUFS: "No buffer space available",
+        errno.WSAEISCONN: "Socket is already connected",
+        errno.WSAENOTCONN: "Socket is not connected",
+        errno.WSAESHUTDOWN: "Can't send after socket shutdown",
+        errno.WSAETOOMANYREFS: "Too many references: can't splice",
+        errno.WSAETIMEDOUT: "Operation timed out",
+        errno.WSAECONNREFUSED: "Connection refused",
+        errno.WSAELOOP: "Too many levels of symbolic links",
+        errno.WSAENAMETOOLONG: "File name too long",
+        errno.WSAEHOSTDOWN: "Host is down",
+        errno.WSAEHOSTUNREACH: "No route to host",
+        errno.WSAENOTEMPTY: "Directory not empty",
+        errno.WSAEPROCLIM: "Too many processes",
+        errno.WSAEUSERS: "Too many users",
+        errno.WSAEDQUOT: "Disc quota exceeded",
+        errno.WSAESTALE: "Stale NFS file handle",
+        errno.WSAEREMOTE: "Too many levels of remote in path",
+        errno.WSASYSNOTREADY: "Network subsystem is unvailable",
+        errno.WSAVERNOTSUPPORTED: "WinSock version is not supported",
+        errno.WSANOTINITIALISED: "Successful WSAStartup() not yet performed",
+        errno.WSAEDISCON: "Graceful shutdown in progress",
+
+        # Resolver errors
+        # XXX Not exported by errno. Replace by the values in winsock.h
+        # errno.WSAHOST_NOT_FOUND: "No such host is known",
+        # errno.WSATRY_AGAIN: "Host not found, or server failed",
+        # errno.WSANO_RECOVERY: "Unexpected server error encountered",
+        # errno.WSANO_DATA: "Valid name without requested data",
+        # errno.WSANO_ADDRESS: "No address, look for MX record",
+        }
+
+    def socket_strerror(errno):
+        return WIN32_ERROR_MESSAGES.get(errno, "winsock error")
+else:
+    def socket_strerror(errno):
+        return strerror(errno)



More information about the Pypy-commit mailing list