# HG changeset patch # User Tero Marttila # Date 1250625750 -10800 # Node ID f18b5787c46c954740e4d9408b90bd2560cbb3c9 # Parent 15d8bb96b8d4785e0a512f9d2ae8d47d4ef9def8 reorganize socket, adding af_inet/af_inet6 modules, and moving sctp in diff -r 15d8bb96b8d4 -r f18b5787c46c inc/qmsk.net.socket.addr.pxd --- a/inc/qmsk.net.socket.addr.pxd Tue Aug 18 22:24:36 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../qmsk/net/socket/addr.pxd \ No newline at end of file diff -r 15d8bb96b8d4 -r f18b5787c46c inc/qmsk.net.socket.address.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/qmsk.net.socket.address.pxd Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,1 @@ +../qmsk/net/socket/address.pxd \ No newline at end of file diff -r 15d8bb96b8d4 -r f18b5787c46c inc/qmsk.net.socket.sctp.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/qmsk.net.socket.sctp.pxd Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,1 @@ +../qmsk/net/socket/sctp.pxd \ No newline at end of file diff -r 15d8bb96b8d4 -r f18b5787c46c inc/sctp.sock.pxd --- a/inc/sctp.sock.pxd Tue Aug 18 22:24:36 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../qmsk/net/sctp/sock.pxd \ No newline at end of file diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/sctp/sock.pxd --- a/qmsk/net/sctp/sock.pxd Tue Aug 18 22:24:36 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,277 +0,0 @@ -""" - The socket-based interface for SCTP. - - http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-15 -""" - -#from qmsk.net.libc cimport __u8, __u16, __u32, __s8, __s16, __s32, ssize_t -from qmsk.net.libc cimport * - -cimport qmsk.net.socket.platform as platform -cimport qmsk.net.socket.socket - -# -# this defines the kernel SCTP -> userspace API extensions, such as structure types etc. -cdef extern from "netinet/sctp.h" : - ## types - ctypedef __s32 sctp_assoc_t - - ## constants - # sockapi - enum : - SOL_SCTP - IPPROTO_SCTP - - # sockopts - enum : - SCTP_RTOINFO - SCTP_ASSOCINFO - SCTP_INITMSG - SCTP_NODELAY - SCTP_AUTOCLOSE - SCTP_SET_PEER_PRIMARY_ADDR - SCTP_PRIMARY_ADDR - SCTP_ADAPTATION_LAYER - SCTP_DISABLE_FRAGMENTS - SCTP_PEER_ADDR_PARAMS - SCTP_DEFAULT_SEND_PARAM - SCTP_EVENTS - SCTP_I_WANT_MAPPED_V4_ADDR - SCTP_MAXSEG - SCTP_STATUS - SCTP_GET_PEER_ADDR_INFO - SCTP_DELAYED_ACK_TIME - SCTP_CONTEXT - SCTP_FRAGMENT_INTERLEAVE - SCTP_PARTIAL_DELIVERY_POINT - SCTP_MAX_BURST - - ## send/recv-msg cmsghdr's - struct sctp_initmsg : - __u16 sinit_num_ostreams - __u16 sinit_max_instreams - __u16 sinit_max_attempts - __u16 sinit_max_init_timeo - - struct sctp_sndrcvinfo : - __u16 sinfo_stream - __u16 sinfo_ssn - __u16 sinfo_flags - __u32 sinfo_ppid - __u32 sinfo_context - __u32 sinfo_timetolive - __u32 sinfo_tsn - __u32 sinfo_cumtsn - sctp_assoc_t sinfo_assoc_id - - # XXX: missing sctp_extrcvinfo - - # sctp_sndrcvinfo.sinfo_flags values - enum sctp_sinfo_flags : - SCTP_UNORDERED # Send/receive message unordered - SCTP_ADDR_OVER # Override the primary destination - SCTP_ABORT # Send an ABORT message to the peer - SCTP_EOF # Initiate graceful shutdown process - - ## notifications - struct sctp_assoc_change : - __u16 sac_type - __u16 sac_flags - __u32 sac_length - __u16 sac_state - __u16 sac_error - __u16 sac_outbound_streams - __u16 sac_inbound_streams - sctp_assoc_t sac_assoc_id - __u8 sac_info[0] - - # sctp_assoc_change.sac_state - enum sctp_sac_state : - SCTP_COMM_UP - SCTP_COMM_LOST - SCTP_RESTART - SCTP_SHUTDOWN_COMP - SCTP_CANT_STR_ASSOC - - struct sctp_paddr_change : - __u16 spc_type - __u16 spc_flags - __u32 spc_length - platform.sockaddr_storage spc_aaddr - int spc_state - int spc_error - sctp_assoc_t spc_assoc_id - - enum sctp_spc_state : - SCTP_ADDR_AVAILABLE - SCTP_ADDR_UNREACHABLE - SCTP_ADDR_REMOVED - SCTP_ADDR_ADDED - SCTP_ADDR_MADE_PRIM - SCTP_ADDR_CONFIRMED - - struct sctp_remote_error : - __u16 sre_type - __u16 sre_flags - __u32 sre_length - __u16 sre_error - sctp_assoc_t sre_assoc_id - __u8 sre_data[0] - - - struct sctp_send_failed : - __u16 ssf_type - __u16 ssf_flags - __u32 ssf_length - __u32 ssf_error - sctp_sndrcvinfo ssf_info - sctp_assoc_t ssf_assoc_id - __u8 ssf_data[0] - - enum sctp_ssf_flags : - SCTP_DATA_UNSENT - SCTP_DATA_SENT - - struct sctp_shutdown_event : - __u16 sse_type - __u16 sse_flags - __u32 sse_length - sctp_assoc_t sse_assoc_id - - struct sctp_adaptation_event : - __u16 sai_type - __u16 sai_flags - __u32 sai_length - __u32 sai_adaptation_ind - sctp_assoc_t sai_assoc_id - - struct sctp_pdapi_event : - __u16 pdapi_type - __u16 pdapi_flags - __u32 pdapi_length - __u32 pdapi_indication - sctp_assoc_t pdapi_assoc_id - - enum : - SCTP_PARTIAL_DELIVERY_ABORTED - - struct sctp_event_subscribe : - __u8 sctp_data_io_event - __u8 sctp_association_event - __u8 sctp_address_event - __u8 sctp_send_failure_event - __u8 sctp_peer_error_event - __u8 sctp_shutdown_event - __u8 sctp_partial_delivery_event - __u8 sctp_adaptation_layer_event - - struct sn_header : - __u16 sn_type - __u16 sn_flags - __u32 sn_length - - union sctp_notification : - sn_header sn_header - - sctp_assoc_change sn_assoc_change - sctp_paddr_change sn_paddr_change - sctp_remote_error sn_remote_error - sctp_send_failed sn_send_failed - sctp_shutdown_event sn_shutdown_event - sctp_adaptation_event sn_adaptation_event - sctp_pdapi_event sn_pdapi_event - - enum sctp_sn_type : - SCTP_SN_TYPE_BASE - SCTP_ASSOC_CHANGE - SCTP_PEER_ADDR_CHANGE - SCTP_SEND_FAILED - SCTP_REMOTE_ERROR - SCTP_SHUTDOWN_EVENT - SCTP_PARTIAL_DELIVERY_EVENT - SCTP_ADAPTATION_INDICATION - - enum sctp_sn_error : - SCTP_FAILED_THRESHOLD - SCTP_RECEIVED_SACK - SCTP_HEARTBEAT_SUCCESS - SCTP_RESPONSE_TO_USER_REQ - SCTP_INTERNAL_ERROR - SCTP_SHUTDOWN_GUARD_EXPIRES - SCTP_PEER_FAULTY - - ctypedef sctp_sn_error sctp_sn_error_t - - - ### - ### 8 New Interfaces - ### - - ## 8.1 sctp_bindx - enum : - SCTP_BINDX_ADD_ADDR - SCTP_BINDX_REM_ADDR - - int sctp_bindx (int sd, platform.sockaddr *addrs, int addrcnt, int flags) - - ## 8.2 sctp_peeloff - int sctp_peeloff (int sd, sctp_assoc_t assoc_id) - - ## 8.3 sctp_getpaddrs - int sctp_getpaddrs (int sd, sctp_assoc_t assoc_id, platform.sockaddr **addrs) - ## 8.4 sctp_freepaddrs - void sctp_freepaddrs (platform.sockaddr *addrs) - - ## 8.5 sctp_getladdrs - int sctp_getladdrs (int sd, sctp_assoc_t id, platform.sockaddr **ss) - ## 8.6 sctp_freeladdrs - void sctp_freeladdrs (platform.sockaddr **ss) - - ## 8.7 sctp_sendmsg - ssize_t sctp_sendmsg ( - int sd, - void *msg, size_t len, - platform.sockaddr *dst, platform.socklen_t dstlen, - uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context - ) - - ## 8.8 sctp_Recvmsg - ssize_t sctp_recvmsg ( - int sd, - void *msg, size_t len, - platform.sockaddr *src, platform.socklen_t *srclen, - sctp_sndrcvinfo *sinfo, - int *msg_flags - ) - - - ## 8.9 sctp_connectx - # XXX: missing return-sctp_assoc_t-id argument from RFC! - int sctp_connectx (int sd, platform.sockaddr *addrs, int addrcnt) - - ## 8.10 sctp_send - int sctp_send ( - int sd, - void *msg, size_t len, - sctp_sndrcvinfo *sinfo, - int flags - ) - - ## 8.11 sctp_sendx - int sctp_sendx ( - int sd, - void *msg, size_t len, - platform.sockaddr *addrs, int addrcnt, - sctp_sndrcvinfo *sinfo, - int flags - ) - - ## 8.12 sctp_getaddrlen - int sctp_getaddrlen (platform.sa_family_t family) - -cdef class sctp_socket (qmsk.net.socket.socket.socket) : - """ - SCTP-specific methods and functionality, built on top of the generic socket interface. - """ - - diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/sctp/sock.pyx --- a/qmsk/net/sctp/sock.pyx Tue Aug 18 22:24:36 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,112 +0,0 @@ -""" - 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.address 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.sctp.sock 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 (qmsk.net.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. - """ - - qmsk.net.socket.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 = libc.alloca(addrsoup_len(addrs)) - - # store - addrsoup_store(addrs, addr_buf) - - # then call - if sctp_bindx(self.fd, 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 = libc.alloca(addrsoup_len(addrs)) - - # store - addrsoup_store(addrs, addr_buf) - - # then call - if sctp_connectx(self.fd, addr_buf, len(addrs)) : - raise_errno('sctp_connectx') - - diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/__init__.py --- a/qmsk/net/socket/__init__.py Tue Aug 18 22:24:36 2009 +0300 +++ b/qmsk/net/socket/__init__.py Tue Aug 18 23:02:30 2009 +0300 @@ -1,6 +1,62 @@ -# combine all the modules +""" + The low-level OS Socket API and related functionality, covering the Internet layer. + + All functionality provided here aims to be a thin wrapper around the native system API, so for the most part, methods + map directly to *one* syscall/libc call. + + Provided modules/types: + + address: + Abstract socket addresses. + + 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`. + + 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. + + af_inet: + AF_INET (IPv4) -specific functionality. + + sockaddr_in - AF_INET sockaddr with addr, port fields + + af_inet6: + AF_INET6 (IPv6) -specific functionality. + + sockaddr_in6 - AF_INET6 sockaddr with addr, port, flowinfo, scope_id fields + + socket: + Core socket API. + + socket - socket-related syscalls with a guaranteed 1:1 mapping between methods and library + calls. + + sctp: + SCTP-specific socket API + + sctp_socket - extension of socket.socket to support SCTP-specific socket API extensions + + constants: + Socket-related constants. + + AF_* - address families + SOCK_* - socket types + IPPROTO_* - inet protocols + MSG_* - send/recv message flags + + etc. +""" + +## XXX: these shadow the modules... how do we want to provide these? +#from qmsk.net.socket.address import sockaddr, addrinfo, endpoint +# +#from qmsk.net.socket.af_inet import sockaddr_in +#from qmsk.net.socket.af_inet6 import sockaddr_in6 +# +#from qmsk.net.socket.socket import socket +#from qmsk.net.socket.sctp import sctp_socket +# #from qmsk.net.socket.constants import * -#from qmsk.net.socket.platform import * -#from qmsk.net.socket.addr import * -#from qmsk.net.socket.socket import * +# diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/address.pyx --- a/qmsk/net/socket/address.pyx Tue Aug 18 22:24:36 2009 +0300 +++ b/qmsk/net/socket/address.pyx Tue Aug 18 23:02:30 2009 +0300 @@ -99,278 +99,12 @@ def __repr__ (self) : return "sockaddr(%d, %s, %d)" % (self.family, self.addr, self.port) -cdef class sockaddr_in (sockaddr) : - """ - AF_INET struct sockaddr_in - - >>> sa = sockaddr_in("127.0.0.1", 80) - >>> sa.addr - '127.0.0.1' - >>> sa.port - 80 - >>> str(sa) - '127.0.0.1:80' - - >>> sockaddr_in('2001::5') - Traceback (most recent call last): - ... - NameError: Invalid network address for specified address family: '2001::5' - - """ - - # the struct sockaddr_in - cdef platform.sockaddr_in sockaddr - - def __init__ (self, object addr=None, platform.in_port_t port=0) : - """ - 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) - """ - - # zero - libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr)) - - # store our family - # XXX: this should be a class attribute... - self._init_family(platform.AF_INET) - - # constant af - self.sockaddr.sin_family = self.family - - # set the sin_port - self.sockaddr.sin_port = platform.htons(port) - - if addr : - # set the sin_addr - # this automatically converts the addr from str -> char * - platform.inet_pton(self.family, addr, &self.sockaddr.sin_addr) - - else : - # set as INADDR_ANY - self.sockaddr.sin_addr.s_addr = platform.INADDR_ANY - - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : - if sa_ptr : - sa_ptr[0] = &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 port : - """ - The integer port number - - >>> sockaddr_in(port=1234).port - 1234 - """ - - def __get__ (self) : - return platform.ntohs(self.sockaddr.sin_port) - - def __cmp__ (self, other_obj) : - """ - A sockaddr_in is equal to any other sockaddr_in which has the same addr and port - - >>> assert sockaddr_in() == sockaddr_in() - >>> assert sockaddr_in('127.0.0.1', 80) == sockaddr_in('127.0.0.1', 80) - >>> addr = sockaddr_in(); assert addr == addr - """ - - if not isinstance(other_obj, sockaddr_in) : - return py.Py_NotImplemented - - cdef sockaddr_in other = other_obj - cdef platform.sockaddr_in *sa1 = &self.sockaddr, *sa2 = &other.sockaddr - - if other is self : - return 0 - - return ( - libc.memcmp( &sa1.sin_port, &sa2.sin_port, sizeof(sa1.sin_port)) - or libc.memcmp( &sa1.sin_addr, &sa2.sin_addr, sizeof(sa1.sin_addr)) - ) - - def __str__ (self) : - """ - Return the literal ASCII representation for this sockaddr as an ': string - - >>> str(sockaddr_in()) - '0.0.0.0:0' - """ - - # format - return "%s:%s" % self.getnameinfo() - -cdef class sockaddr_in6 (sockaddr) : - """ - AF_INET6 struct sockaddr_in6 - - >>> sa6 = sockaddr_in6("::1", 80) - >>> sa6.addr - '::1' - >>> sa6.port - 80 - >>> str(sa6) - '[::1]:80' - - """ - - cdef platform.sockaddr_in6 sockaddr - - def __init__ (self, object addr=None, platform.in_port_t port=0, unsigned int scope_id = 0) : - """ - Construct using given literal IPv6 address and TCP/UDP port - - addr - IPv6 address, defaults to platform.in6addr_any (::) - port - TCP/UDP port, defaults to 0 (ephemeral) - scope_id - (optional) scope ID representing interface index for link-local addresses - """ +# mapping of AF -> sockaddr, user-modifyable +cimport qmsk.net.socket.af_inet, qmsk.net.socket.af_inet6 - # zero - libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr)) - - # store our family - # XXX: this should be a class attribute... - self._init_family(platform.AF_INET6) - - # constant af - self.sockaddr.sin6_family = self.family - - # set the sin_port - self.sockaddr.sin6_port = platform.htons(port) - - if addr : - # set the sin_addr - # this automatically converts the addr from str -> char * - platform.inet_pton(self.family, addr, &self.sockaddr.sin6_addr) - - else : - # set as INADDR_ANY - self.sockaddr.sin6_addr = platform.in6addr_any - - # scope ID - self.sockaddr.sin6_scope_id = scope_id - - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : - if sa_ptr : - sa_ptr[0] = &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 port : - """ - The integer port number. - - This will represent it correctly in host byte order. - - >>> sockaddr_in6(port=1234).port - 1234 - """ - - def __get__ (self) : - return platform.ntohs(self.sockaddr.sin6_port) - - - property flowinfo : - """ - The integer flowinfo - - XXX: byteorder? - - >>> sockaddr_in6().flowinfo - 0 - """ - - def __get__ (self) : - return self.sockaddr.sin6_flowinfo - - - property scope_id : - """ - The scope ID - corresponds to an interface index for link-scope addresses. - - This should be in host byte order... - - >>> sockaddr_in6(scope_id=1337).scope_id - 1337 - """ - - def __get__ (self) : - return self.sockaddr.sin6_scope_id - - def __cmp__ (self, other_obj) : - """ - A sockaddr_in6 is equal to any other sockaddr_in6 which has the same addr, port and scope ID. - - XXX: flowinfo? - - XXX: A sockaddr_in6 is also equal to a sockaddr_in if the sockaddr_in6 represents the given v4-mapped address. - - >>> assert sockaddr_in6() == sockaddr_in6() - >>> assert sockaddr_in6('0:0:0::1', 80) == sockaddr_in6('::1', 80) - >>> assert sockaddr_in6('::127.0.0.1') == sockaddr_in('127.0.0.1') - """ - - if not isinstance(other_obj, sockaddr_in6) : - return py.Py_NotImplemented - - cdef sockaddr_in6 other = other_obj - cdef platform.sockaddr_in6 *sa1 = &self.sockaddr, *sa2 = &other.sockaddr - - if other is self : - return 0 - - return ( - libc.memcmp( &sa1.sin6_port, &sa2.sin6_port, sizeof(sa1.sin6_port)) - or libc.memcmp( &sa1.sin6_addr, &sa2.sin6_addr, sizeof(sa1.sin6_addr)) - or libc.memcmp( &sa1.sin6_scope_id, &sa2.sin6_scope_id, sizeof(sa1.sin6_scope_id)) - ) - - def __str__ (self) : - """ - Return the literal ASCII representation for this sockaddr as a '[]: string - - >>> str(sockaddr_in6()) - '[::]:0' - - >>> str(sockaddr_in6('2001:0::05:1')) - '[2001::5:1]' - - >>> str(sockaddr_in6('fe80::abcd', scope_id=5)) - '[fe80::abcd%5]' - """ - - addr, port = self.getnameinfo() - scope_id = self.scope_id - - # format with scope_id - return "[%s%s]:%s" % ( - addr, - "%%%d" % scope_id if scope_id else "", - port - ) - -# mapping of AF -> sockaddr, user-modifyable SOCKADDR_BY_FAMILY = { - platform.AF_INET: sockaddr_in, - platform.AF_INET6: sockaddr_in6, + platform.AF_INET: qmsk.net.socket.af_inet.sockaddr_in, + platform.AF_INET6: qmsk.net.socket.af_inet6.sockaddr_in6, } # build a sockaddr from the given sockaddr struct, based on sa_family diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/af_inet.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/af_inet.pxd Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,33 @@ +""" + AF_INET-specific stuff +""" + +from qmsk.net.socket.address cimport * + + +cdef class sockaddr_in (sockaddr) : + """ + AF_INET struct sockaddr_in + + >>> sa = sockaddr_in("127.0.0.1", 80) + >>> sa.addr + '127.0.0.1' + >>> sa.port + 80 + >>> str(sa) + '127.0.0.1:80' + + >>> sockaddr_in('2001::5') + Traceback (most recent call last): + ... + NameError: Invalid network address for specified address family: '2001::5' + + """ + + # the struct sockaddr_in + cdef platform.sockaddr_in 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 + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/af_inet.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/af_inet.pyx Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,94 @@ +cimport qmsk.net.py as py + +cdef class sockaddr_in (sockaddr) : + + def __init__ (self, object addr=None, platform.in_port_t port=0) : + """ + 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) + """ + + # zero + libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr)) + + # store our family + # XXX: this should be a class attribute... + self._init_family(platform.AF_INET) + + # constant af + self.sockaddr.sin_family = self.family + + # set the sin_port + self.sockaddr.sin_port = platform.htons(port) + + if addr : + # set the sin_addr + # this automatically converts the addr from str -> char * + platform.inet_pton(self.family, addr, &self.sockaddr.sin_addr) + + else : + # set as INADDR_ANY + self.sockaddr.sin_addr.s_addr = platform.INADDR_ANY + + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : + if sa_ptr : + sa_ptr[0] = &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 port : + """ + The integer port number + + >>> sockaddr_in(port=1234).port + 1234 + """ + + def __get__ (self) : + return platform.ntohs(self.sockaddr.sin_port) + + def __cmp__ (self, other_obj) : + """ + A sockaddr_in is equal to any other sockaddr_in which has the same addr and port + + >>> assert sockaddr_in() == sockaddr_in() + >>> assert sockaddr_in('127.0.0.1', 80) == sockaddr_in('127.0.0.1', 80) + >>> addr = sockaddr_in(); assert addr == addr + """ + + if not isinstance(other_obj, sockaddr_in) : + return py.Py_NotImplemented + + cdef sockaddr_in other = other_obj + cdef platform.sockaddr_in *sa1 = &self.sockaddr, *sa2 = &other.sockaddr + + if other is self : + return 0 + + return ( + libc.memcmp( &sa1.sin_port, &sa2.sin_port, sizeof(sa1.sin_port)) + or libc.memcmp( &sa1.sin_addr, &sa2.sin_addr, sizeof(sa1.sin_addr)) + ) + + def __str__ (self) : + """ + Return the literal ASCII representation for this sockaddr as an ': string + + >>> str(sockaddr_in()) + '0.0.0.0:0' + """ + + # format + return "%s:%s" % self.getnameinfo() + + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/af_inet6.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/af_inet6.pxd Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,26 @@ +""" + AF_INET6-specific stuff +""" + +from qmsk.net.socket.address cimport * + + +cdef class sockaddr_in6 (sockaddr) : + """ + AF_INET6 struct sockaddr_in6 + + >>> sa6 = sockaddr_in6("::1", 80) + >>> sa6.addr + '::1' + >>> sa6.port + 80 + >>> str(sa6) + '[::1]:80' + + """ + + cdef platform.sockaddr_in6 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 + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/af_inet6.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/af_inet6.pyx Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,146 @@ +cimport qmsk.net.py as py + +cdef class sockaddr_in6 (sockaddr) : + + def __init__ (self, object addr=None, platform.in_port_t port=0, unsigned int scope_id = 0) : + """ + Construct using given literal IPv6 address and TCP/UDP port + + addr - IPv6 address, defaults to platform.in6addr_any (::) + port - TCP/UDP port, defaults to 0 (ephemeral) + scope_id - (optional) scope ID representing interface index for link-local addresses + """ + + # zero + libc.memset(&self.sockaddr, 0, sizeof(self.sockaddr)) + + # store our family + # XXX: this should be a class attribute... + self._init_family(platform.AF_INET6) + + # constant af + self.sockaddr.sin6_family = self.family + + # set the sin_port + self.sockaddr.sin6_port = platform.htons(port) + + if addr : + # set the sin_addr + # this automatically converts the addr from str -> char * + platform.inet_pton(self.family, addr, &self.sockaddr.sin6_addr) + + else : + # set as INADDR_ANY + self.sockaddr.sin6_addr = platform.in6addr_any + + # scope ID + self.sockaddr.sin6_scope_id = scope_id + + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : + if sa_ptr : + sa_ptr[0] = &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 port : + """ + The integer port number. + + This will represent it correctly in host byte order. + + >>> sockaddr_in6(port=1234).port + 1234 + """ + + def __get__ (self) : + return platform.ntohs(self.sockaddr.sin6_port) + + + property flowinfo : + """ + The integer flowinfo + + XXX: byteorder? + + >>> sockaddr_in6().flowinfo + 0 + """ + + def __get__ (self) : + return self.sockaddr.sin6_flowinfo + + + property scope_id : + """ + The scope ID - corresponds to an interface index for link-scope addresses. + + This should be in host byte order... + + >>> sockaddr_in6(scope_id=1337).scope_id + 1337 + """ + + def __get__ (self) : + return self.sockaddr.sin6_scope_id + + def __cmp__ (self, other_obj) : + """ + A sockaddr_in6 is equal to any other sockaddr_in6 which has the same addr, port and scope ID. + + XXX: flowinfo? + + XXX: A sockaddr_in6 is also equal to a sockaddr_in if the sockaddr_in6 represents the given v4-mapped address. + + >>> assert sockaddr_in6() == sockaddr_in6() + >>> assert sockaddr_in6('0:0:0::1', 80) == sockaddr_in6('::1', 80) + >>> assert sockaddr_in6('::127.0.0.1') == sockaddr_in('127.0.0.1') + """ + + if not isinstance(other_obj, sockaddr_in6) : + return py.Py_NotImplemented + + cdef sockaddr_in6 other = other_obj + cdef platform.sockaddr_in6 *sa1 = &self.sockaddr, *sa2 = &other.sockaddr + + if other is self : + return 0 + + return ( + libc.memcmp( &sa1.sin6_port, &sa2.sin6_port, sizeof(sa1.sin6_port)) + or libc.memcmp( &sa1.sin6_addr, &sa2.sin6_addr, sizeof(sa1.sin6_addr)) + or libc.memcmp( &sa1.sin6_scope_id, &sa2.sin6_scope_id, sizeof(sa1.sin6_scope_id)) + ) + + def __str__ (self) : + """ + Return the literal ASCII representation for this sockaddr as a '[]: string + + >>> str(sockaddr_in6()) + '[::]:0' + + >>> str(sockaddr_in6('2001:0::05:1')) + '[2001::5:1]' + + >>> str(sockaddr_in6('fe80::abcd', scope_id=5)) + '[fe80::abcd%5]' + """ + + addr, port = self.getnameinfo() + scope_id = self.scope_id + + # format with scope_id + return "[%s%s]:%s" % ( + addr, + "%%%d" % scope_id if scope_id else "", + port + ) + + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/constants.pyx --- a/qmsk/net/socket/constants.pyx Tue Aug 18 22:24:36 2009 +0300 +++ b/qmsk/net/socket/constants.pyx Tue Aug 18 23:02:30 2009 +0300 @@ -81,4 +81,65 @@ NI_MAXHOST = platform.NI_MAXHOST NI_MAXSERV = platform.NI_MAXSERV +cimport qmsk.net.socket.sctp as sctp +# XXX: move to platform +SOL_SCTP = sctp.SOL_SCTP + +SCTP_RTOINFO = sctp.SCTP_RTOINFO +SCTP_ASSOCINFO = sctp.SCTP_ASSOCINFO +SCTP_INITMSG = sctp.SCTP_INITMSG +SCTP_NODELAY = sctp.SCTP_NODELAY +SCTP_AUTOCLOSE = sctp.SCTP_AUTOCLOSE +SCTP_SET_PEER_PRIMARY_ADDR = sctp.SCTP_SET_PEER_PRIMARY_ADDR +SCTP_PRIMARY_ADDR = sctp.SCTP_PRIMARY_ADDR +SCTP_ADAPTATION_LAYER = sctp.SCTP_ADAPTATION_LAYER +SCTP_DISABLE_FRAGMENTS = sctp.SCTP_DISABLE_FRAGMENTS +SCTP_PEER_ADDR_PARAMS = sctp.SCTP_PEER_ADDR_PARAMS +SCTP_DEFAULT_SEND_PARAM = sctp.SCTP_DEFAULT_SEND_PARAM +SCTP_EVENTS = sctp.SCTP_EVENTS +SCTP_I_WANT_MAPPED_V4_ADDR = sctp.SCTP_I_WANT_MAPPED_V4_ADDR +SCTP_MAXSEG = sctp.SCTP_MAXSEG +SCTP_STATUS = sctp.SCTP_STATUS +SCTP_GET_PEER_ADDR_INFO = sctp.SCTP_GET_PEER_ADDR_INFO +SCTP_DELAYED_ACK_TIME = sctp.SCTP_DELAYED_ACK_TIME +SCTP_CONTEXT = sctp.SCTP_CONTEXT +SCTP_FRAGMENT_INTERLEAVE = sctp.SCTP_FRAGMENT_INTERLEAVE +SCTP_PARTIAL_DELIVERY_POINT = sctp.SCTP_PARTIAL_DELIVERY_POINT +SCTP_MAX_BURST = sctp.SCTP_MAX_BURST + +SCTP_ADDR_AVAILABLE = sctp.SCTP_ADDR_AVAILABLE +SCTP_ADDR_UNREACHABLE = sctp.SCTP_ADDR_UNREACHABLE +SCTP_ADDR_REMOVED = sctp.SCTP_ADDR_REMOVED +SCTP_ADDR_ADDED = sctp.SCTP_ADDR_ADDED +SCTP_ADDR_MADE_PRIM = sctp.SCTP_ADDR_MADE_PRIM +SCTP_ADDR_CONFIRMED = sctp.SCTP_ADDR_CONFIRMED + + +SCTP_DATA_UNSENT = sctp.SCTP_DATA_UNSENT +SCTP_DATA_SENT = sctp.SCTP_DATA_SENT + +SCTP_PARTIAL_DELIVERY_ABORTED = sctp.SCTP_PARTIAL_DELIVERY_ABORTED + +# enum sctp_sn_type : +SCTP_SN_TYPE_BASE = sctp.SCTP_SN_TYPE_BASE +SCTP_ASSOC_CHANGE = sctp.SCTP_ASSOC_CHANGE +SCTP_PEER_ADDR_CHANGE = sctp.SCTP_PEER_ADDR_CHANGE +SCTP_SEND_FAILED = sctp.SCTP_SEND_FAILED +SCTP_REMOTE_ERROR = sctp.SCTP_REMOTE_ERROR +SCTP_SHUTDOWN_EVENT = sctp.SCTP_SHUTDOWN_EVENT +SCTP_PARTIAL_DELIVERY_EVENT = sctp.SCTP_PARTIAL_DELIVERY_EVENT +SCTP_ADAPTATION_INDICATION = sctp.SCTP_ADAPTATION_INDICATION + +# enum sctp_sn_error : +SCTP_FAILED_THRESHOLD = sctp.SCTP_FAILED_THRESHOLD +SCTP_RECEIVED_SACK = sctp.SCTP_RECEIVED_SACK +SCTP_HEARTBEAT_SUCCESS = sctp.SCTP_HEARTBEAT_SUCCESS +SCTP_RESPONSE_TO_USER_REQ = sctp.SCTP_RESPONSE_TO_USER_REQ +SCTP_INTERNAL_ERROR = sctp.SCTP_INTERNAL_ERROR +SCTP_SHUTDOWN_GUARD_EXPIRES = sctp.SCTP_SHUTDOWN_GUARD_EXPIRES +SCTP_PEER_FAULTY = sctp.SCTP_PEER_FAULTY + +SCTP_BINDX_ADD_ADDR = sctp.SCTP_BINDX_ADD_ADDR +SCTP_BINDX_REM_ADDR = sctp.SCTP_BINDX_REM_ADDR + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/sctp.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/sctp.pxd Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,277 @@ +""" + The socket-based interface for SCTP. + + http://tools.ietf.org/html/draft-ietf-tsvwg-sctpsocket-15 +""" + +#from qmsk.net.libc cimport __u8, __u16, __u32, __s8, __s16, __s32, ssize_t +from qmsk.net.libc cimport * + +cimport qmsk.net.socket.platform as platform +cimport qmsk.net.socket.socket as socket + +# +# this defines the kernel SCTP -> userspace API extensions, such as structure types etc. +cdef extern from "netinet/sctp.h" : + ## types + ctypedef __s32 sctp_assoc_t + + ## constants + # sockapi + enum : + SOL_SCTP + IPPROTO_SCTP + + # sockopts + enum : + SCTP_RTOINFO + SCTP_ASSOCINFO + SCTP_INITMSG + SCTP_NODELAY + SCTP_AUTOCLOSE + SCTP_SET_PEER_PRIMARY_ADDR + SCTP_PRIMARY_ADDR + SCTP_ADAPTATION_LAYER + SCTP_DISABLE_FRAGMENTS + SCTP_PEER_ADDR_PARAMS + SCTP_DEFAULT_SEND_PARAM + SCTP_EVENTS + SCTP_I_WANT_MAPPED_V4_ADDR + SCTP_MAXSEG + SCTP_STATUS + SCTP_GET_PEER_ADDR_INFO + SCTP_DELAYED_ACK_TIME + SCTP_CONTEXT + SCTP_FRAGMENT_INTERLEAVE + SCTP_PARTIAL_DELIVERY_POINT + SCTP_MAX_BURST + + ## send/recv-msg cmsghdr's + struct sctp_initmsg : + __u16 sinit_num_ostreams + __u16 sinit_max_instreams + __u16 sinit_max_attempts + __u16 sinit_max_init_timeo + + struct sctp_sndrcvinfo : + __u16 sinfo_stream + __u16 sinfo_ssn + __u16 sinfo_flags + __u32 sinfo_ppid + __u32 sinfo_context + __u32 sinfo_timetolive + __u32 sinfo_tsn + __u32 sinfo_cumtsn + sctp_assoc_t sinfo_assoc_id + + # XXX: missing sctp_extrcvinfo + + # sctp_sndrcvinfo.sinfo_flags values + enum sctp_sinfo_flags : + SCTP_UNORDERED # Send/receive message unordered + SCTP_ADDR_OVER # Override the primary destination + SCTP_ABORT # Send an ABORT message to the peer + SCTP_EOF # Initiate graceful shutdown process + + ## notifications + struct sctp_assoc_change : + __u16 sac_type + __u16 sac_flags + __u32 sac_length + __u16 sac_state + __u16 sac_error + __u16 sac_outbound_streams + __u16 sac_inbound_streams + sctp_assoc_t sac_assoc_id + __u8 sac_info[0] + + # sctp_assoc_change.sac_state + enum sctp_sac_state : + SCTP_COMM_UP + SCTP_COMM_LOST + SCTP_RESTART + SCTP_SHUTDOWN_COMP + SCTP_CANT_STR_ASSOC + + struct sctp_paddr_change : + __u16 spc_type + __u16 spc_flags + __u32 spc_length + platform.sockaddr_storage spc_aaddr + int spc_state + int spc_error + sctp_assoc_t spc_assoc_id + + enum sctp_spc_state : + SCTP_ADDR_AVAILABLE + SCTP_ADDR_UNREACHABLE + SCTP_ADDR_REMOVED + SCTP_ADDR_ADDED + SCTP_ADDR_MADE_PRIM + SCTP_ADDR_CONFIRMED + + struct sctp_remote_error : + __u16 sre_type + __u16 sre_flags + __u32 sre_length + __u16 sre_error + sctp_assoc_t sre_assoc_id + __u8 sre_data[0] + + + struct sctp_send_failed : + __u16 ssf_type + __u16 ssf_flags + __u32 ssf_length + __u32 ssf_error + sctp_sndrcvinfo ssf_info + sctp_assoc_t ssf_assoc_id + __u8 ssf_data[0] + + enum sctp_ssf_flags : + SCTP_DATA_UNSENT + SCTP_DATA_SENT + + struct sctp_shutdown_event : + __u16 sse_type + __u16 sse_flags + __u32 sse_length + sctp_assoc_t sse_assoc_id + + struct sctp_adaptation_event : + __u16 sai_type + __u16 sai_flags + __u32 sai_length + __u32 sai_adaptation_ind + sctp_assoc_t sai_assoc_id + + struct sctp_pdapi_event : + __u16 pdapi_type + __u16 pdapi_flags + __u32 pdapi_length + __u32 pdapi_indication + sctp_assoc_t pdapi_assoc_id + + enum : + SCTP_PARTIAL_DELIVERY_ABORTED + + struct sctp_event_subscribe : + __u8 sctp_data_io_event + __u8 sctp_association_event + __u8 sctp_address_event + __u8 sctp_send_failure_event + __u8 sctp_peer_error_event + __u8 sctp_shutdown_event + __u8 sctp_partial_delivery_event + __u8 sctp_adaptation_layer_event + + struct sn_header : + __u16 sn_type + __u16 sn_flags + __u32 sn_length + + union sctp_notification : + sn_header sn_header + + sctp_assoc_change sn_assoc_change + sctp_paddr_change sn_paddr_change + sctp_remote_error sn_remote_error + sctp_send_failed sn_send_failed + sctp_shutdown_event sn_shutdown_event + sctp_adaptation_event sn_adaptation_event + sctp_pdapi_event sn_pdapi_event + + enum sctp_sn_type : + SCTP_SN_TYPE_BASE + SCTP_ASSOC_CHANGE + SCTP_PEER_ADDR_CHANGE + SCTP_SEND_FAILED + SCTP_REMOTE_ERROR + SCTP_SHUTDOWN_EVENT + SCTP_PARTIAL_DELIVERY_EVENT + SCTP_ADAPTATION_INDICATION + + enum sctp_sn_error : + SCTP_FAILED_THRESHOLD + SCTP_RECEIVED_SACK + SCTP_HEARTBEAT_SUCCESS + SCTP_RESPONSE_TO_USER_REQ + SCTP_INTERNAL_ERROR + SCTP_SHUTDOWN_GUARD_EXPIRES + SCTP_PEER_FAULTY + + ctypedef sctp_sn_error sctp_sn_error_t + + + ### + ### 8 New Interfaces + ### + + ## 8.1 sctp_bindx + enum : + SCTP_BINDX_ADD_ADDR + SCTP_BINDX_REM_ADDR + + int sctp_bindx (int sd, platform.sockaddr *addrs, int addrcnt, int flags) + + ## 8.2 sctp_peeloff + int sctp_peeloff (int sd, sctp_assoc_t assoc_id) + + ## 8.3 sctp_getpaddrs + int sctp_getpaddrs (int sd, sctp_assoc_t assoc_id, platform.sockaddr **addrs) + ## 8.4 sctp_freepaddrs + void sctp_freepaddrs (platform.sockaddr *addrs) + + ## 8.5 sctp_getladdrs + int sctp_getladdrs (int sd, sctp_assoc_t id, platform.sockaddr **ss) + ## 8.6 sctp_freeladdrs + void sctp_freeladdrs (platform.sockaddr **ss) + + ## 8.7 sctp_sendmsg + ssize_t sctp_sendmsg ( + int sd, + void *msg, size_t len, + platform.sockaddr *dst, platform.socklen_t dstlen, + uint32_t ppid, uint32_t flags, uint16_t stream_no, uint32_t timetolive, uint32_t context + ) + + ## 8.8 sctp_Recvmsg + ssize_t sctp_recvmsg ( + int sd, + void *msg, size_t len, + platform.sockaddr *src, platform.socklen_t *srclen, + sctp_sndrcvinfo *sinfo, + int *msg_flags + ) + + + ## 8.9 sctp_connectx + # XXX: missing return-sctp_assoc_t-id argument from RFC! + int sctp_connectx (int sd, platform.sockaddr *addrs, int addrcnt) + + ## 8.10 sctp_send + int sctp_send ( + int sd, + void *msg, size_t len, + sctp_sndrcvinfo *sinfo, + int flags + ) + + ## 8.11 sctp_sendx + int sctp_sendx ( + int sd, + void *msg, size_t len, + platform.sockaddr *addrs, int addrcnt, + sctp_sndrcvinfo *sinfo, + int flags + ) + + ## 8.12 sctp_getaddrlen + int sctp_getaddrlen (platform.sa_family_t family) + +cdef class sctp_socket (socket.socket) : + """ + SCTP-specific methods and functionality, built on top of the generic socket interface. + """ + + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/sctp.pyx --- /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 = libc.alloca(addrsoup_len(addrs)) + + # store + addrsoup_store(addrs, addr_buf) + + # then call + if sctp_bindx(self.fd, 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 = libc.alloca(addrsoup_len(addrs)) + + # store + addrsoup_store(addrs, addr_buf) + + # then call + if sctp_connectx(self.fd, addr_buf, len(addrs)) : + raise_errno('sctp_connectx') + + diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/socket/socket.pyx --- a/qmsk/net/socket/socket.pyx Tue Aug 18 22:24:36 2009 +0300 +++ b/qmsk/net/socket/socket.pyx Tue Aug 18 23:02:30 2009 +0300 @@ -112,15 +112,16 @@ return self.fd - def setblocking (self, bint blocking = True) : - """ - Control the OS-level nonblocking-IO mode flag for this socket. - - blocking - True for normal blocking operation, False to use non-blocking operation - """ - - # fcntl magic - libc.fcntl_set_flag(self.fd, libc.O_NONBLOCK, not blocking) +# # XXX: does this *really* belong here? +# def setblocking (self, bint blocking = True) : +# """ +# Control the OS-level nonblocking-IO mode flag for this socket. +# +# blocking - True for normal blocking operation, False to use non-blocking operation +# """ +# +# # fcntl magic +# libc.fcntl_set_flag(self.fd, libc.O_NONBLOCK, not blocking) def bind (self, sockaddr addr) : """ diff -r 15d8bb96b8d4 -r f18b5787c46c qmsk/net/transport/__init__.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/transport/__init__.py Tue Aug 18 23:02:30 2009 +0300 @@ -0,0 +1,5 @@ +""" + Transport-layer functionality. + + This implements TCP/UDP/SCTP functionality, plus relevant Transport-Application layer stuff like TLS, SOCKS, SSH-channels, etc. +""" diff -r 15d8bb96b8d4 -r f18b5787c46c setup.py --- a/setup.py Tue Aug 18 22:24:36 2009 +0300 +++ b/setup.py Tue Aug 18 23:02:30 2009 +0300 @@ -31,8 +31,9 @@ cython_ext("qmsk.net.socket.constants", ["qmsk/net/socket/constants.pyx"]), cython_ext("qmsk.net.socket.address", ["qmsk/net/socket/address.pyx"]), cython_ext("qmsk.net.socket.socket", ["qmsk/net/socket/socket.pyx"]), - cython_ext("qmsk.net.sctp.sock", ["qmsk/net/sctp/sock.pyx"], libraries=['sctp']), - cython_ext("qmsk.net.sctp.constants", ["qmsk/net/sctp/constants.pyx"]), + cython_ext("qmsk.net.socket.af_inet", ["qmsk/net/socket/af_inet.pyx"]), + cython_ext("qmsk.net.socket.af_inet6", ["qmsk/net/socket/af_inet6.pyx"]), + cython_ext("qmsk.net.socket.sctp", ["qmsk/net/socket/sctp.pyx"], libraries=['sctp']), ] )