[socket] add sockaddr_un (still dysfunctional\!) + doc fixes
authorTero Marttila <terom@fixme.fi>
Fri, 21 Aug 2009 00:29:25 +0300
changeset 27 12468e38227e
parent 26 d8a71a675862
child 28 020c89baaa33
[socket] add sockaddr_un (still dysfunctional\!) + doc fixes
qmsk/net/socket/__init__.py
qmsk/net/socket/address.pxd
qmsk/net/socket/address.pyx
qmsk/net/socket/af_unix.pxd
qmsk/net/socket/af_unix.pyx
qmsk/net/socket/platform.pxd
qmsk/net/socket/socket.pyx
--- a/qmsk/net/socket/__init__.py	Wed Aug 19 00:12:07 2009 +0300
+++ b/qmsk/net/socket/__init__.py	Fri Aug 21 00:29:25 2009 +0300
@@ -13,6 +13,8 @@
         sockaddr        - corresponds to the `struct sockaddr` used in socket API calls. This is an abstract type
                           that cannot itself be instantated, see `sockaddr_in`/`sockaddr_in6`/`endpoint`.
 
+            XXX: these are only abstract at the internet level. They do not apply to e.g. UNIX socket addresses!
+
         addrinfo        - corresponds to the `struct addrinfo` used by the GAI API. Hold a concrete `sockaddr`
 
         endpoint        - abstract internet hostname+service address as handled by getaddrinfo. Maps to a series of `addrinfo`'s.
@@ -47,6 +49,12 @@
         MSG_*           - send/recv message flags
 
         etc.
+
+    TODO:
+        * release GIL for operations
+        * expose some misc. functions (e.g. [hn]ton[slq]) via platform?
+        * define more constants
+        * consider some sockaddr_in::sin_addr/sockaddr_in6::sin6_addr -level interfaces?
 """
 
 ## XXX: these shadow the modules... how do we want to provide these?
--- a/qmsk/net/socket/address.pxd	Wed Aug 19 00:12:07 2009 +0300
+++ b/qmsk/net/socket/address.pxd	Fri Aug 21 00:29:25 2009 +0300
@@ -13,8 +13,8 @@
 cdef class sockaddr :
     """
         A network-level socket address
-
-        XXX: rename to 'address'
+        
+        XXX: not abstract enough. Functions/properties like getnameinfo/addr/port do not work for e.g. sockaddr_un
 
         >>> sockaddr().family
         0
--- a/qmsk/net/socket/address.pyx	Wed Aug 19 00:12:07 2009 +0300
+++ b/qmsk/net/socket/address.pyx	Fri Aug 21 00:29:25 2009 +0300
@@ -240,6 +240,25 @@
     cpdef getaddrinfo (self, int family, int socktype, int protocol = 0, int flags = platform.AI_PASSIVE) :
         """
             Look up our hostname/service using the given socket parameters, and return a sequence of addrinfo objects.
+
+                family          - the address family to use, one of AF_*. May be AF_UNSPEC.
+                socktype        - the socket type to use, one of SOCK_*.
+                protocol        - the protocol to use, one of IPPROTO_* or zero to pick a suitable protocol
+                                  for the given socktype.
+                flags           - bitmask of AI_* flags for getaddrinfo()
+
+                    AI_NUMERICHOST  - self.hostname is a literal address, do not perform any network host address lookups
+                    AI_NUMERICSERV  - self.service is a literal port number, do not lookup service names
+                    AI_CANONNAME    - return addrinfo objects with .canonname set to the official name of the host
+                    AI_PASSIVE      - intended for use by server applications, return addrinfos with an unspecified
+                                      .addr if no self.hostname is not given.
+                    AI_ADDRCONFIG   - only return addrinfos with a .addrs of a given address family if the system has at
+                                      least one local address of that address family configured.
+                    AI_V4MAPPED     - if family=AF_INET6, and no matching IPv6 addresses could be found, return IPv4-mapped
+                                      IPv6 addresses.
+                    AI_ALL          - if used together with AI_V4MAPPED, then return both IPv6 and IPv4-mapped IPv6
+                                      addresses.
+
         """
         
         # XXX: Cython doesn't support proper compound value literals...
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmsk/net/socket/af_unix.pxd	Fri Aug 21 00:29:25 2009 +0300
@@ -0,0 +1,21 @@
+"""
+    AF_UNIX-specific stuff
+"""
+
+from qmsk.net.socket.address cimport *
+
+
+cdef class sockaddr_un (sockaddr) :
+    """
+        AF_UNIX struct sockaddr_un
+        
+        XXX: doesn't support the abstract namespace
+    """
+
+    # the struct sockaddr_in
+    cdef platform.sockaddr_un sockaddr
+
+
+    cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1
+    cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmsk/net/socket/af_unix.pyx	Fri Aug 21 00:29:25 2009 +0300
@@ -0,0 +1,86 @@
+cimport qmsk.net.py as py
+
+cdef class sockaddr_un (sockaddr) :
+
+    def __init__ (self, char *addr) :
+        """
+            Construct using given literal IPv4 address and TCP/UDP port
+
+                addr        - IPv4 address, defaults to INADDR_ANY (0.0.0.0)
+                port        - TCP/UDP port, defaults to 0 (ephemeral)
+        """
+
+        if len(addr) > sizeof(self.sockaddr.sun_path) - 1 :
+            raise ValueError("AF_UNIX path is too long: " + addr)
+ 
+        # zero
+        libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr))
+
+        # store our family
+        # XXX: this should be a class attribute...
+        self._init_family(platform.AF_UNIX)
+
+        # constant af
+        self.sockaddr.sun_family = self.family
+        
+        # set the sun_path
+        memcpy(self.sockaddr.sun_path, addr, len(addr))
+        self.sockaddr.sun_path[len(addr)] = '\0'
+        
+    cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 :
+        if sa_ptr :
+            sa_ptr[0] = <platform.sockaddr *> &self.sockaddr
+
+        if sa_len :
+            sa_len[0] = sizeof(self.sockaddr)
+
+        return 0
+
+    cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 :
+        assert sa_len == sizeof(self.sockaddr)
+
+        libc.memcpy(&self.sockaddr, sa, sa_len)
+
+    property path :
+        """
+            The string path
+
+            XXX: abstract namespace
+        """
+
+        def __get__ (self) :
+            return self.sockaddr.sun_path
+
+    def __cmp__ (self, other_obj) :
+        """
+            A sockaddr_un is equal to any other sockaddr_un which has the same path
+            
+            >>> assert sockaddr_un() == sockaddr_un()
+            >>> assert sockaddr_un('/foo/bar') == sockaddr_un('/foo/bar')
+            >>> addr = sockaddr_un(); assert addr == addr
+        """
+
+        if not isinstance(other_obj, sockaddr_un) :
+            return <object> py.Py_NotImplemented
+
+        cdef sockaddr_un other = other_obj
+        cdef platform.sockaddr_un *sa1 = &self.sockaddr, *sa2 = &other.sockaddr
+
+        if other is self :
+            return 0
+
+        return (
+                libc.memcmp(<void *> &sa1.sin_path, <void *> &sa2.sin_path, sizeof(sa1.sin_path))
+        )
+
+    def __str__ (self) :
+        """
+            Return the literal ASCII representation for this sockaddr as an '<path> string
+        
+            >>> str(sockaddr_un('/foo'))
+            '/foo'
+        """
+        
+        # format
+        return "%s" % self.path
+
--- a/qmsk/net/socket/platform.pxd	Wed Aug 19 00:12:07 2009 +0300
+++ b/qmsk/net/socket/platform.pxd	Fri Aug 21 00:29:25 2009 +0300
@@ -191,6 +191,18 @@
     uint16_t ntohs(uint16_t)
     uint32_t ntohl(uint32_t)
 
+cdef extern from "sys/un.h" :
+    enum :
+        UNIX_PATH_MAX
+
+    struct sockaddr_un :
+        sa_family_t     sun_family
+        char            sun_path[UNIX_PATH_MAX]
+    
+    # actually a macro
+    # sockaddr_un -> size_t actual length of the sockaddr
+    size_t SUN_LEN (sockaddr_un *sa)
+
 cdef extern from "netdb.h" :
     ## getaddrinfo
     struct addrinfo :
--- a/qmsk/net/socket/socket.pyx	Wed Aug 19 00:12:07 2009 +0300
+++ b/qmsk/net/socket/socket.pyx	Fri Aug 21 00:29:25 2009 +0300
@@ -497,7 +497,8 @@
 
             Returns a (name, iovs, control, flags) tuple :
                 name        - the source address of the message, or None
-                iovs        - sequence of strings containing the recieved data corresponding to the iov_lens
+                iovs        - sequence of buffers containing the recieved data corresponding to the iov_lens.
+                              This may contain fewer buffers than iov_lens if there was insufficient data to fill all buffers.
                 control     - string containing recieved control message, if any
                 flags       - recieved flags
         """