--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libc.pxd Sun Aug 16 02:58:32 2009 +0300
@@ -0,0 +1,131 @@
+"""
+ Libc stuff
+"""
+
+cdef extern from "stdint.h":
+ # yes, these are "wrong"
+ ctypedef unsigned char uint8_t
+ ctypedef unsigned short uint16_t
+ ctypedef unsigned int uint32_t
+
+ ctypedef signed char int8_t
+ ctypedef signed short int16_t
+ ctypedef signed int int32_t
+
+# <linux/types.h>
+cdef extern from "linux/types.h" :
+ ctypedef uint8_t __u8
+ ctypedef uint16_t __u16
+ ctypedef uint32_t __u32
+
+ ctypedef int8_t __s8
+ ctypedef int16_t __s16
+ ctypedef int32_t __s32
+
+cdef extern from "alloca.h" :
+ void* alloca (size_t size)
+
+# <sys/socket.h>
+cdef extern from "sys/socket.h" :
+ enum :
+ SOCK_STREAM
+ SOCK_DGRAM
+ SOCK_SEQPACKET
+
+ enum :
+ PF_UNSPEC
+ PF_LOCAL
+ PF_INET
+ PF_INET6
+
+ # these are #defines
+ enum :
+ PF_UNIX
+
+ AF_UNSPEC
+ AF_LOCAL
+ AF_UNIX
+ AF_INET
+ AF_INET6
+
+ ctypedef uint16_t sa_family_t
+ ctypedef uint16_t in_port_t
+ ctypedef uint32_t in_addr_t
+
+ ## AF_INET
+ struct in_addr :
+ in_addr_t s_addr
+
+ struct sockaddr_in :
+ sa_family_t sin_family
+ in_port_t sin_port
+ in_addr sin_addr
+
+ # XXX: should these be in another cdef?
+ in_addr_t INADDR_ANY
+
+ ## AF_INET6
+ struct in6_addr :
+ pass
+
+ struct sockaddr_in6 :
+ sa_family_t sin6_family
+ in_port_t sin6_port
+ uint32_t sin6_flowinfo
+ in6_addr sin6_addr
+ uint32_t sin6_scope_id
+
+ # common in6_addr's
+ in6_addr in6addr_any
+ in6_addr in6addr_loopback
+
+ ## actually from bits/socket.h...
+ struct sockaddr :
+ sa_family_t sa_family
+
+ struct sockaddr_storage :
+ sa_family_t ss_family
+
+cdef extern from "arpa/inet.h" :
+ uint16_t htons(uint16_t)
+ uint32_t htonl(uint32_t)
+ uint16_t ntohs(uint16_t)
+ uint32_t ntohl(uint32_t)
+
+ # XXX: correct?!
+ ctypedef size_t socklen_t
+
+ ## constants
+ enum :
+ INET_ADDRSTRLEN
+ INET6_ADDRSTRLEN
+
+ char* c_inet_ntop "inet_ntop" (int af, void *sockaddr, char *buf, socklen_t len)
+ int c_inet_pton "inet_pton" (int af, char *src, void *dst)
+
+cdef extern from "netdb.h" :
+ int c_getnameinfo "getnameinfo" (
+ sockaddr *sa, socklen_t salen,
+ char *host, size_t hostlen,
+ char *serv, size_t servlen,
+ int flags
+ )
+
+ enum :
+ NI_NOFQDN
+ NI_NUMERICHOST
+ NI_NAMEREQD
+ NI_NUMERICSERV
+ NI_DGRAM
+
+ NI_MAXHOST
+ NI_MAXSERV
+
+ char* gai_strerror (int err)
+
+# python-friendly wrapper around inet_ntop
+cdef object inet_ntop (int af, void *sockaddr)
+cdef object inet_pton (int af, char *addr, void *sockaddr_out)
+
+# sockaddr, flags -> (host, service)
+cdef object getnameinfo (sockaddr *sa, socklen_t salen, int flags)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/libc.pyx Sun Aug 16 02:58:32 2009 +0300
@@ -0,0 +1,35 @@
+from libc cimport *
+
+cdef object inet_ntop (int af, void *sockaddr) :
+ """
+ Wrapper around inet_ntop, returning a PyString
+ """
+
+ # XXX: longest possible address...
+ cdef char buf[INET6_ADDRSTRLEN]
+
+ if c_inet_ntop(af, sockaddr, buf, sizeof(buf)) == NULL :
+ # XXX: errno?
+ raise OSError()
+
+ # autoconvert -> str
+ return buf
+
+cdef object inet_pton (int af, char *addr, void *sockaddr_out) :
+ if c_inet_pton(af, addr, sockaddr_out) < 0 :
+ raise OSError()
+
+cdef object getnameinfo (sockaddr *sa, socklen_t salen, int flags) :
+ cdef char hostbuf[NI_MAXHOST]
+ cdef char servbuf[NI_MAXSERV]
+ cdef int err
+
+ err = c_getnameinfo(sa, salen, hostbuf, sizeof(hostbuf), servbuf, sizeof(servbuf), flags)
+
+ if err :
+ # XXX: raise a GAIError
+ raise Exception(gai_strerror(err))
+
+ else :
+ return hostbuf, servbuf
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sctp/sock.pyx Sun Aug 16 02:58:32 2009 +0300
@@ -0,0 +1,236 @@
+"""
+ This C(ython) extension module provides an interface to the libsctp library and associated socket API.
+"""
+
+from libc cimport *
+
+# <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
+ int SOL_SCTP
+ int IPPROTO_SCTP
+
+ # sockopts
+ int SCTP_RTOINFO
+ int SCTP_ASSOCINFO
+ int SCTP_INITMSG
+ int SCTP_NODELAY
+ int SCTP_AUTOCLOSE
+ int SCTP_SET_PEER_PRIMARY_ADDR
+ int SCTP_PRIMARY_ADDR
+ int SCTP_ADAPTATION_LAYER
+ int SCTP_DISABLE_FRAGMENTS
+ int SCTP_PEER_ADDR_PARAMS
+ int SCTP_DEFAULT_SEND_PARAM
+ int SCTP_EVENTS
+ int SCTP_I_WANT_MAPPED_V4_ADDR
+ int SCTP_MAXSEG
+ int SCTP_STATUS
+ int SCTP_GET_PEER_ADDR_INFO
+ int SCTP_DELAYED_ACK_TIME
+ int SCTP_CONTEXT
+ int SCTP_FRAGMENT_INTERLEAVE
+ int SCTP_PARTIAL_DELIVERY_POINT
+ int 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
+
+ # 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
+ 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
+
+
+ ## sctp_bindx
+ int SCTP_BINDX_ADD_ADDR
+ int SCTP_BINDX_REM_ADDR
+
+ int sctp_bindx (int sd, sockaddr *addrs, int addrcnt, int flags)
+ int sctp_connectx (int sd, sockaddr *addrs, int addrcnt)
+
+
+def bindx (int sd, object addrs, int flags) :
+ """
+ Bind the given SOCK_SEQPACKET to the given set of local addresses.
+
+ sd the system socket FD
+ addresses the list of address tuples
+ flags one of SCTP_BINDX_ADD/REM_ADDR
+ """
+
+ # automatically allocated array of sockaddr_storage's for passing given addresses to sctp_bindx
+ cdef sockaddr_storage *addrs_out
+
+ # used to iterate through addrs_out
+ cdef sockaddr_in *addr_in
+
+ # number of addresses given
+ cdef size_t addr_count = len(addrs)
+
+ # alloc stack storage for converting addresses
+ addrs_out = <sockaddr_storage *> alloca(addr_count * sizeof(sockaddr_storage))
+
+ for i, address in enumerate(addrs) :
+ # XXX: assume socket-style IPv4 for now...
+ addr, port = address
+
+ addr_in = <sockaddr_in *>(&addrs_out[i])
+
+ addr_in.sin_family = AF_INET
+ addr_in.sin_port = htons(port)
+ inet_aton(addr, &addr_in.sin_addr)
+
+ return sctp_bindx(sd, <sockaddr *>addrs_out, addr_count, flags)
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/sock/addr.pyx Sun Aug 16 02:58:32 2009 +0300
@@ -0,0 +1,220 @@
+"""
+ Socket addresses
+"""
+
+cimport libc
+
+cdef class sockaddr :
+ """
+ A network-level socket address
+
+ >>> sockaddr().family
+ 0
+ >>> sockaddr().port
+ Traceback (most recent call last):
+ ...
+ NotImplementedError
+ >>> sockaddr().getnameinfo()
+ Traceback (most recent call last):
+ ...
+ NotImplementedError
+ """
+
+ # address family
+ cdef readonly libc.sa_family_t family
+
+ cdef void _init_family (self, libc.sa_family_t family=libc.AF_UNSPEC) :
+ self.family = family
+
+ cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 :
+ """
+ Get the sockaddr pointer and sockaddr length for this address
+ """
+
+ raise NotImplementedError()
+
+ def getnameinfo (self) :
+ """
+ Returns a (host, serv) tuple for this address à la getnameinfo
+ """
+
+ cdef libc.sockaddr *sa
+ cdef libc.socklen_t sa_len
+
+ # XXX: take as args?
+ cdef int flags = libc.NI_NUMERICHOST | libc.NI_NUMERICSERV
+
+ # get our abstract sockaddr
+ self._get_sockaddr(&sa, &sa_len)
+
+ # get nice text format
+ return libc.getnameinfo(sa, sa_len, flags)
+
+ property addr :
+ """
+ The ASCII literal network address
+ """
+
+ def __get__ (self) :
+ """
+ Default implmentation using getnameinfo()
+ """
+
+ addr, port = self.getnameinfo()
+
+ return addr
+
+ property port :
+ """
+ The integer port number
+ """
+
+ def __get__ (self) :
+ """
+ Default implementation using getnameinfo() and int()
+ """
+
+ addr, port = self.getnameinfo()
+
+ return int(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'
+ >>> str(sockaddr_in())
+ '0.0.0.0:0'
+ """
+
+ # the struct sockaddr_in
+ cdef libc.sockaddr_in sockaddr
+
+ def __init__ (self, object addr=None, libc.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)
+ """
+
+ # store our family
+ # XXX: this should be a class attribute...
+ self._init_family(libc.AF_INET)
+
+ # constant af
+ self.sockaddr.sin_family = self.family
+
+ # set the sin_port
+ self.sockaddr.sin_port = libc.htons(port)
+
+ if addr :
+ # set the sin_addr
+ # this automatically converts the addr from str -> char *
+ libc.inet_pton(self.family, addr, &self.sockaddr.sin_addr)
+
+ else :
+ # set as INADDR_ANY
+ self.sockaddr.sin_addr.s_addr = libc.INADDR_ANY
+
+ cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 :
+ if sa_ptr :
+ sa_ptr[0] = <libc.sockaddr *> &self.sockaddr
+
+ if sa_len :
+ sa_len[0] = sizeof(self.sockaddr)
+
+ return 0
+
+ property port :
+ """
+ The integer port number
+ """
+
+ def __get__ (self) :
+ return libc.ntohs(self.sockaddr.sin_port)
+
+ def __str__ (self) :
+ """
+ Return the literal ASCII representation for this sockaddr as an '<addr>:<port> string
+ """
+
+ # 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'
+ >>> str(sockaddr_in6())
+ '[::]:0'
+ """
+
+ cdef libc.sockaddr_in6 sockaddr
+
+ def __init__ (self, object addr=None, libc.in_port_t port=0) :
+ """
+ Construct using given literal IPv6 address and TCP/UDP port
+
+ addr - IPv6 address, defaults to in6addr_any (::)
+ port - TCP/UDP port, defaults to 0 (ephemeral)
+ """
+
+ # store our family
+ # XXX: this should be a class attribute...
+ self._init_family(libc.AF_INET6)
+
+ # constant af
+ self.sockaddr.sin6_family = self.family
+
+ # set the sin_port
+ self.sockaddr.sin6_port = libc.htons(port)
+
+ if addr :
+ # set the sin_addr
+ # this automatically converts the addr from str -> char *
+ libc.inet_pton(self.family, addr, &self.sockaddr.sin6_addr)
+
+ else :
+ # set as INADDR_ANY
+ self.sockaddr.sin6_addr = libc.in6addr_any
+
+ cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 :
+ if sa_ptr :
+ sa_ptr[0] = <libc.sockaddr *> &self.sockaddr
+
+ if sa_len :
+ sa_len[0] = sizeof(self.sockaddr)
+
+ return 0
+
+ property port :
+ """
+ The integer port number
+ """
+
+ def __get__ (self) :
+ return libc.ntohs(self.sockaddr.sin6_port)
+
+
+ def __str__ (self) :
+ """
+ Return the literal ASCII representation for this sockaddr as a '[<addr>]:<port> string
+ """
+
+ # format
+ return "[%s]:%s" % self.getnameinfo()
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/test.py Sun Aug 16 02:58:32 2009 +0300
@@ -0,0 +1,6 @@
+import doctest
+
+import sock.addr
+
+doctest.testmod(sock.addr)
+