qmsk/net/sctp/sock.pyx
author Tero Marttila <terom@fixme.fi>
Sun, 16 Aug 2009 20:22:06 +0300
changeset 11 7ae92c2b433f
parent 10 94b0d5a208c1
child 20 0e4933d5862e
permissions -rw-r--r--
move libc+py back to qmsk.net.x
"""
    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')