--- /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')
+
+