qmsk/net/socket/sctp.pyx
changeset 24 f18b5787c46c
child 49 e2f79e68418a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/qmsk/net/socket/sctp.pyx	Tue Aug 18 23:02:30 2009 +0300
@@ -0,0 +1,112 @@
+"""
+    This C(ython) extension module provides an interface to the libsctp library and associated socket API.
+    
+    >>> from __future__ import absolute_import;
+    >>> from qmsk.net.socket.af_inet import sockaddr_in
+    >>> from qmsk.net.socket.constants import *
+    >>> s = sctp_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP)
+    >>> s.sctp_bindx([sockaddr_in('127.0.0.1', 1337), sockaddr_in('127.0.0.2')], 0x01)
+    >>>
+
+"""
+
+from qmsk.net.socket.sctp cimport *
+from qmsk.net.socket.address cimport sockaddr
+
+cimport qmsk.net.socket.platform as platform
+cimport qmsk.net.libc as libc
+
+from qmsk.net.py cimport raise_errno
+
+cdef size_t addrsoup_len (object addrs) except -1 :
+    """
+        Calculate the length of the addr_buf required to store the given addrsoup
+    """
+
+    cdef sockaddr addr
+    cdef size_t addr_size = 0
+
+    # whoever decided that sctp_bindx takes an array of mixed sockaddr_in/sockaddr_in6's should be shot
+    for addr in addrs :
+        addr_size += addr._get_sockaddr_len()
+    
+    return addr_size
+
+cdef addrsoup_store (object addrs, char *addr_buf) :
+    """
+        Store the sockaddr_*'s for the given addresses into the given buffer, which should be addrsoup_len() bytes long
+    """
+
+    cdef sockaddr addr
+    cdef char *addr_ptr = addr_buf
+
+    # fill it
+    cdef platform.sockaddr *sa
+    cdef platform.socklen_t sa_len
+
+    for addr in addrs :
+        # get address's sockaddr info
+        addr._get_sockaddr(&sa, &sa_len)
+        
+        # copy to buffer
+        libc.memcpy(addr_ptr, sa, sa_len)
+        
+        # move to next
+        addr_ptr += sa_len
+
+cdef class sctp_socket (socket.socket) :
+
+    def __init__ (self, int family = platform.AF_INET, int socktype = platform.SOCK_SEQPACKET, int protocol = IPPROTO_SCTP, int fd = -1) :
+        """
+            Same behaviour as socket.__init__, but different defaults.
+        """
+
+        socket.socket.__init__(self, family, socktype, protocol, fd)
+
+    def sctp_bindx (self, object addrs, int flags) :
+        """
+            Bind this IPPROTO_SCTP socket to the given set of local addresses.
+
+            This may be called multiple times on a socket, even after bind(), to change the set of local addresses.
+            This may affect ongoing associations, or only new associations.
+
+                addresses   the list of sockaddr's
+                flags       one of SCTP_BINDX_ADD/REM_ADDR
+            
+        """
+
+        # ensure that addrs stays the same... ?
+        addrs = tuple(addrs)
+
+        # alloc buffer to hold all the sockaddr_*'s
+        cdef char *addr_buf = <char *> libc.alloca(addrsoup_len(addrs))
+
+        # store
+        addrsoup_store(addrs, addr_buf)
+
+        # then call
+        if sctp_bindx(self.fd, <platform.sockaddr *> addr_buf, len(addrs), flags) :
+            raise_errno('sctp_bindx')
+
+    def sctp_connectx (self, int sd, object addrs) :
+        """
+            Establish an association with the given set of remote sockaddr's.
+
+                addresses   the list of sockaddr's
+            
+        """
+
+        # ensure that addrs stays the same... ?
+        addrs = tuple(addrs)
+
+        # alloc buffer to hold all the sockaddr_*'s
+        cdef char *addr_buf = <char *> libc.alloca(addrsoup_len(addrs))
+
+        # store
+        addrsoup_store(addrs, addr_buf)
+
+        # then call
+        if sctp_connectx(self.fd, <platform.sockaddr *> addr_buf, len(addrs)) :
+            raise_errno('sctp_connectx')
+
+