--- 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
--- /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
--- /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
--- 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
--- 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
-
-# <netinet/sctp.h>
-# 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.
- """
-
-
--- 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 = <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')
-
-
--- 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 *
+#
--- 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] = <platform.sockaddr *> &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 <object> 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(<void *> &sa1.sin_port, <void *> &sa2.sin_port, sizeof(sa1.sin_port))
- or libc.memcmp(<void *> &sa1.sin_addr, <void *> &sa2.sin_addr, sizeof(sa1.sin_addr))
- )
-
- def __str__ (self) :
- """
- Return the literal ASCII representation for this sockaddr as an '<addr>:<port> 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] = <platform.sockaddr *> &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 <object> 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(<void *> &sa1.sin6_port, <void *> &sa2.sin6_port, sizeof(sa1.sin6_port))
- or libc.memcmp(<void *> &sa1.sin6_addr, <void *> &sa2.sin6_addr, sizeof(sa1.sin6_addr))
- or libc.memcmp(<void *> &sa1.sin6_scope_id, <void *> &sa2.sin6_scope_id, sizeof(sa1.sin6_scope_id))
- )
-
- def __str__ (self) :
- """
- Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> 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
--- /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
+
--- /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] = <platform.sockaddr *> &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 <object> 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(<void *> &sa1.sin_port, <void *> &sa2.sin_port, sizeof(sa1.sin_port))
+ or libc.memcmp(<void *> &sa1.sin_addr, <void *> &sa2.sin_addr, sizeof(sa1.sin_addr))
+ )
+
+ def __str__ (self) :
+ """
+ Return the literal ASCII representation for this sockaddr as an '<addr>:<port> string
+
+ >>> str(sockaddr_in())
+ '0.0.0.0:0'
+ """
+
+ # format
+ return "%s:%s" % self.getnameinfo()
+
+
--- /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
+
--- /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] = <platform.sockaddr *> &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 <object> 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(<void *> &sa1.sin6_port, <void *> &sa2.sin6_port, sizeof(sa1.sin6_port))
+ or libc.memcmp(<void *> &sa1.sin6_addr, <void *> &sa2.sin6_addr, sizeof(sa1.sin6_addr))
+ or libc.memcmp(<void *> &sa1.sin6_scope_id, <void *> &sa2.sin6_scope_id, sizeof(sa1.sin6_scope_id))
+ )
+
+ def __str__ (self) :
+ """
+ Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> 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
+ )
+
+
--- 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
+
--- /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
+
+# <netinet/sctp.h>
+# 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.
+ """
+
+
--- /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')
+
+
--- 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) :
"""
--- /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.
+"""
--- 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']),
]
)