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