"""
This C(ython) extension module provides an interface to the libsctp library and associated socket API.
>>> from __future__ import absolute_import; import socket as _socket
>>> from qmsk.net.socket.addr import sockaddr_in
>>> s = _socket.socket(_socket.AF_INET, _socket.SOCK_SEQPACKET, 132)
>>> sctp_bindx(s.fileno(), [sockaddr_in('127.0.0.1', 1337), sockaddr_in('127.0.0.2')], 0x01)
>>>
"""
from qmsk.net.sctp.sock cimport *
from qmsk.net.socket.addr cimport sockaddr
from qmsk.net.socket cimport 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
def sctp_bindx (int sd, object addrs, int flags) :
"""
Bind the given SOCK_SEQPACKET to the given set of sock.addr.sockaddr's.
sd the system socket FD
addresses the list of qmsk.net.sock.addr.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 c_sctp_bindx(sd, <platform.sockaddr *> addr_buf, len(addrs), flags) < 0 :
raise_errno('sctp_bindx')
def sctp_connectx (int sd, object addrs) :
"""
Connect the given SOCK_SEQPACKET to the given set of remote sock.addr.sockaddr's.
sd the system socket FD
addresses the list of qmsk.net.sock.addr.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 c_sctp_connectx(sd, <platform.sockaddr *> addr_buf, len(addrs)) < 0 :
raise_errno('sctp_connectx')