# HG changeset patch # User Tero Marttila # Date 1250438481 -10800 # Node ID 74fde84264b137eebe60891cddaea5dacc2eeb8c # Parent 10bd48c9b6ce494c6bb5dba338c25ed1d089cd4b broke Cython with this package magic diff -r 10bd48c9b6ce -r 74fde84264b1 inc/libc.pxd --- a/inc/libc.pxd Sun Aug 16 18:29:55 2009 +0300 +++ b/inc/libc.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -1,1 +1,1 @@ -../libc.pxd \ No newline at end of file +../qmsk/net/libc.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 inc/py.pxd --- a/inc/py.pxd Sun Aug 16 18:29:55 2009 +0300 +++ b/inc/py.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -1,1 +1,1 @@ -../py.pxd \ No newline at end of file +../qmsk/net/py.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 inc/qmsk.net.socket.addr.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/qmsk.net.socket.addr.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,1 @@ +../qmsk/net/socket/addr.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 inc/qmsk.net.socket.socket.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/inc/qmsk.net.socket.socket.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,1 @@ +../qmsk/net/socket/socket.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 inc/sctp.sock.pxd --- a/inc/sctp.sock.pxd Sun Aug 16 18:29:55 2009 +0300 +++ b/inc/sctp.sock.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -1,1 +1,1 @@ -../sctp/sock.pxd \ No newline at end of file +../qmsk/net/sctp/sock.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 inc/sock.addr.pxd --- a/inc/sock.addr.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1 +0,0 @@ -../sock/addr.pxd \ No newline at end of file diff -r 10bd48c9b6ce -r 74fde84264b1 libc.pxd --- a/libc.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,315 +0,0 @@ -""" - 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 - -cdef extern from "sys/types.h" : - # potentially wrong... - ctypedef signed long ssize_t - -# -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 "errno.h" : - int errno - -cdef extern from "string.h" : - void* memcpy (void *dest, void *src, size_t n) - void* memset (void *s, int c, size_t n) - - char* strerror (int errno) - -cdef extern from "alloca.h" : - void* alloca (size_t size) - -cdef extern from "sys/uio.h" : - struct iovec : - void *iov_base - size_t iov_len - -cdef extern from "arpa/inet.h" : - # XXX: correct?! - ctypedef uint32_t socklen_t - - 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 "sys/socket.h" : - # socket types - enum : - SOCK_STREAM - SOCK_DGRAM - SOCK_RAW - SOCK_RDM - SOCK_SEQPACKET - SOCK_PACKET - - # packet/address families - enum : - PF_UNSPEC - PF_LOCAL - PF_UNIX # same as PF_LOCAL - PF_FILE # same as PF_LOCAL - PF_INET - PF_INET6 - PF_NETLINK - PF_ROUTE # same as PF_NETLINK - - - # aliases for PF_* - enum : - AF_UNSPEC - AF_LOCAL - AF_UNIX - AF_FILE - AF_INET - AF_INET6 - AF_NETLINK - AF_ROUTE - - # base sockaddr stuff - ctypedef uint16_t sa_family_t - - struct sockaddr : - sa_family_t sa_family - - struct sockaddr_storage : - sa_family_t ss_family - - # flag values - enum : - MSG_OOB - MSG_PEEK - MSG_DONTROUTE - MSG_CTRUNC - MSG_PROXY - MSG_TRUNC - MSG_DONTWAIT - MSG_EOR - MSG_WAITALL - MSG_FIN - MSG_SYN - MSG_CONFIRM - MSG_RST - MSG_ERRQUEUE - MSG_NOSIGNAL - MSG_MORE - MSG_CMSG_CLOEXEC - - ## send/recv-msg - struct msghdr : - void *msg_name # sockaddr - socklen_t msg_namelen - - iovec *msg_iov # message data - size_t msg_iovlen - - void *msg_control # aux data - size_t msg_controllen - - int msg_flags # flags - - struct cmsghdr : - size_t cmsg_len # length including this cmsghdr struct - - int cmsg_level # originating protocol (IPPROTO_* ???) - int cmsg_type # protocol-specific type - - ## socket-level cmsghdr types - enum : - SCM_RIGHTS - SCM_CREDENTIALS - - #- ucred - - # SO_LINGER parameters - struct linger : - int l_onoff - int l_linger - - - ## API - int socket (int domain, int socktype, int protocol) - int bind (int fd, sockaddr *addr, socklen_t len) - int connect (int fd, sockaddr *addr, socklen_t len) - int listen (int fd, int n) - int accept (int fd, sockaddr *addr, socklen_t *len) - int shutdown (int fd, int how) - - int getsockname (int fd, sockaddr *addr, socklen_t *len) - int getpeername (int fd, sockaddr *addr, socklen_t *len) - - ssize_t send (int fd, void *buf, size_t n, int flags) - ssize_t recv (int fd, void *buf, size_t n, int flags) - ssize_t sendto (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) - ssize_t recvfrom (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) - ssize_t sendmsg (int fd, msghdr *msg, int flags) - ssize_t recvmsg (int fd, msghdr *msg, int flags) - - int getsockopt (int fd, int level, int optname, void *optval, socklen_t optlen) - int setsockopt (int fd, int level, int optname, void *optval, socklen_t optlen) - - enum : - SHUT_RD - SHUT_WR - SHUT_RDWR - -cdef extern from "netinet/in.h" : - ## socket protocol types - enum : - IPPROTO_IP - IPPROTO_ICMP - IPPROTO_IGMP - IPPROTO_TCP - IPPROTO_UDP - IPPROTO_IPV6 - IPPROTO_ICMPV6 - IPPROTO_SCTP - IPPROTO_RAW - - - ## ports - ctypedef uint16_t in_port_t - - ## AF_INET - ctypedef uint32_t in_addr_t - struct in_addr : - in_addr_t s_addr - - # XXX: should these be in another cdef? - in_addr_t INADDR_ANY - - ## AF_INET6 - struct in6_addr : - # XXX: check POSIX... - uint8_t s6_addr[16] - uint16_t s6_addr16[8] - uint32_t s6_addr32[4] - - # common in6_addr's - in6_addr in6addr_any - in6_addr in6addr_loopback - - ## constants - enum : - INET_ADDRSTRLEN - INET6_ADDRSTRLEN - - ## sockaddrs - struct sockaddr_in : - sa_family_t sin_family - in_port_t sin_port - in_addr sin_addr - - 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 - - uint16_t htons(uint16_t) - uint32_t htonl(uint32_t) - uint16_t ntohs(uint16_t) - uint32_t ntohl(uint32_t) - -cdef extern from "netdb.h" : - ## getaddrinfo - struct addrinfo : - int ai_flags - int ai_family - int ai_socktype - int ai_protocol - int ai_addrlen - sockaddr *ai_addr - char *ai_canonname - addrinfo *ai_next - - enum : - AI_PASSIVE - AI_CANONNAME - AI_NUMERICHOST - AI_V4MAPPED - AI_ALL - AI_ADDRCONFIG - # AI_*IDN* - AI_NUMERICSERV - - int c_getaddrinfo "getaddrinfo" ( - char *node, char *service, - addrinfo *hints, addrinfo **res - ) - - void c_freeaddrinfo "freeaddrinfo" (addrinfo *res) - - ## getnameinfo - 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) - -## general errno-based errors -#cdef class Errno (py.OSError) : -# """ -# Some libc function returned an error code: -# -# func - the name of the function called -# err - the system error code -# strerror - human-readable error code -> message -# """ -# -# cdef readonly char *func -# cdef readonly int err -# cdef readonly object strerror -# -#cdef class GAIError (py.OSError) : -# """ -# Some libc GAI function returnd an error code: -# -# func - the name of the function called -# err - the GAI_* error code -# strerror - human-readable error code -> message -# """ -# -# cdef readonly char *func -# cdef readonly int err -# cdef readonly object strerror -# diff -r 10bd48c9b6ce -r 74fde84264b1 libc.pyx --- a/libc.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -from libc cimport * - -from py cimport raise_errno - -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 : - raise_errno('inet_ntop') - - # autoconvert -> str - return buf - -cdef object inet_pton (int af, char *addr, void *sockaddr_out) : - cdef int ret - - ret = c_inet_pton(af, addr, sockaddr_out) - - if ret < 0 : - raise_errno('inet_pton') - - elif ret == 0 : - raise NameError("Invalid network address for specified address family: %r" % (addr, )) - -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)) -# raise GAIError('getnameinfo', err) - - else : - return hostbuf, servbuf - -#cdef class Errno (py.OSError) : -# def __init__ (self, func) : -# self.func = func -# self.err = errno -# self.strerror = strerror(errno) -# -# def __str__ (self) : -# return "%s: %s" % (self.func, self.strerror) -# -#cdef class GAIError (py.OSError) : -# def __init__ (self, func, err) : -# self.func = func -# self.err = err -# self.strerror = gai_strerror(err) -# -# def __str__ (self) : -# return "%s: %s" % (self.func, self.strerror) -# diff -r 10bd48c9b6ce -r 74fde84264b1 py.pxd --- a/py.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,18 +0,0 @@ -cimport libc - -cdef extern from "Python.h" : - struct PyObject : - pass - - ## string stuff - int PyObject_AsCharBuffer (object obj, char **buf, libc.ssize_t *len) except -1 - - ## except setting - PyObject* PyErr_SetFromErrno (PyObject *type) - - PyObject *PyExc_OSError - -# raise OSError with errno -# XXX: doesn't do anything with func -cdef int raise_errno (char *func) except -1 - diff -r 10bd48c9b6ce -r 74fde84264b1 py.pyx --- a/py.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,6 +0,0 @@ - -cdef int raise_errno (char *func) except -1 : - PyErr_SetFromErrno(PyExc_OSError) - - return -1 - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/sctp/constants.pyx --- a/qmsk.net/sctp/constants.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,62 +0,0 @@ -cimport sctp.sock as sctp - -SOL_SCTP = sctp.SOL_SCTP -IPPROTO_SCTP = sctp.IPPROTO_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 10bd48c9b6ce -r 74fde84264b1 qmsk.net/sctp/sock.pxd --- a/qmsk.net/sctp/sock.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -cimport libc - -from libc cimport __u8, __u16, __u32, __s8, __s16, __s32 - -# -# 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 - - # 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 - libc.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 - enum : - SCTP_BINDX_ADD_ADDR - SCTP_BINDX_REM_ADDR - - int c_sctp_bindx "sctp_bindx" (int sd, libc.sockaddr *addrs, int addrcnt, int flags) - - # XXX: missing return-sctp_assoc_t-id argument! - int c_sctp_connectx "sctp_connectx" (int sd, libc.sockaddr *addrs, int addrcnt) - - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/sctp/sock.pyx --- a/qmsk.net/sctp/sock.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,98 +0,0 @@ -""" - This C(ython) extension module provides an interface to the libsctp library and associated socket API. - - >>> import socket - >>> from sock.addr import sockaddr_in - >>> s = socket.socket(socket.AF_INET, socket.SOCK_SEQPACKET, 132) - >>> sctp_bindx(s.fileno(), [sockaddr_in('127.0.0.1', 1337), sockaddr_in('127.0.0.2')], 0x01) - >>> - -""" - -from sctp.sock cimport * -from py cimport raise_errno - -cimport libc -cimport sock.addr - -cdef size_t addrsoup_len (object addrs) except -1 : - """ - Calculate the length of the addr_buf required to store the given addrsoup - """ - - cdef sock.addr.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 sock.addr.sockaddr addr - cdef char *addr_ptr = addr_buf - - # fill it - cdef libc.sockaddr *sa - cdef libc.socklen_t sa_len - - for addr in addrs : - # get address's sockaddr info - addr._get_sockaddr(&sa, &sa_len) - - # copy to buffer - libc.memcpy(addr_ptr, sa, sa_len) - - # move to next - addr_ptr += sa_len - -def sctp_bindx (int sd, object addrs, int flags) : - """ - Bind the given SOCK_SEQPACKET to the given set of sock.addr.sockaddr's. - - sd the system socket FD - addresses the list of qmsk.net.sock.addr.sockaddr's - flags one of SCTP_BINDX_ADD/REM_ADDR - - """ - - # ensure that addrs stays the same... ? - addrs = tuple(addrs) - - # alloc buffer to hold all the sockaddr_*'s - cdef char *addr_buf = libc.alloca(addrsoup_len(addrs)) - - # store - addrsoup_store(addrs, addr_buf) - - # then call - if c_sctp_bindx(sd, addr_buf, len(addrs), flags) < 0 : - raise_errno('sctp_bindx') - -def sctp_connectx (int sd, object addrs) : - """ - Connect the given SOCK_SEQPACKET to the given set of remote sock.addr.sockaddr's. - - sd the system socket FD - addresses the list of qmsk.net.sock.addr.sockaddr's - - """ - - # ensure that addrs stays the same... ? - addrs = tuple(addrs) - - # alloc buffer to hold all the sockaddr_*'s - cdef char *addr_buf = libc.alloca(addrsoup_len(addrs)) - - # store - addrsoup_store(addrs, addr_buf) - - # then call - if c_sctp_connectx(sd, addr_buf, len(addrs)) < 0 : - raise_errno('sctp_connectx') - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/socket/addr.pxd --- a/qmsk.net/socket/addr.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,95 +0,0 @@ -""" - Socket addresses at various levels: - - sockaddr - specific network-level address for socket operations - addrinfo - information on a specific sockaddr including its socket parameters - endpoint - human-readable network address, corresponding to multiple sockaddr's -""" - -cimport libc - -cdef class sockaddr : - """ - A network-level socket address - - XXX: rename to 'address' - - >>> sockaddr().family - 0 - >>> sockaddr().port - Traceback (most recent call last): - ... - NotImplementedError - >>> sockaddr().getnameinfo() - Traceback (most recent call last): - ... - NotImplementedError - """ - - # address family - # XXX: this should be a class constant! It's part of our type safety! - cdef readonly libc.sa_family_t family - - cdef void _init_family (self, libc.sa_family_t family = ?) - - # get the sockaddr/socklen - # each of these can be NULL to ignore it - cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 - - cdef libc.sockaddr* _get_sockaddr_ptr (self) except NULL - cdef libc.socklen_t _get_sockaddr_len (self) except -1 - - # set the sockaddr, socklen must match - cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 - -# build a sockaddr from the given sockaddr struct, based on sa_family -cdef sockaddr build_sockaddr (libc.sockaddr *sa, size_t sa_len) - -cdef class addrinfo : - """ - A socket-level endpoint address, which contains the full socket parameters and an bind/connect address - """ - -# cdef readonly int flags - cdef readonly int family, socktype, protocol - cdef readonly sockaddr addr - cdef readonly object canonname - - cdef _init_addrinfo (self, libc.addrinfo *c_ai) - -# build and return a new addrinfo instance -cdef addrinfo build_addrinfo (libc.addrinfo *c_ai) - -cdef class endpoint : - """ - A network-level socket endpoint. This is the level that humans mostly work with, but the tricky bit is that - an endpoint can map to more than one sockaddr... - - Hence, endpoints are stored as human-readable hostname/service strings, which are then translated to sockaddrs - using getaddrinfo. - - >>> import socket - >>> e = endpoint('127.0.0.1', 80) - >>> str(e) - 'hostname=127.0.0.1, service=80' - >>> res = e.getaddrinfo(socket.AF_UNSPEC, socket.SOCK_STREAM) - >>> len(res) - 1 - >>> str(res[0]) - 'family=2, socktype=1, protocol=6, addr=127.0.0.1:80, canonname=None' - >>> e = endpoint('2001::5', 80) - >>> str(e) - 'hostname=2001::5, service=80' - >>> res = e.getaddrinfo(socket.AF_UNSPEC, socket.SOCK_STREAM) - >>> len(res) - 1 - >>> str(res[0]) - 'family=10, socktype=1, protocol=6, addr=[2001::5]:80, canonname=None' - - """ - - # our defining attributes, set via __init__ - cdef object hostname, service - - cpdef getaddrinfo (self, int family, int socktype, int protocol = ?, int flags = ?) - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/socket/addr.pyx --- a/qmsk.net/socket/addr.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,349 +0,0 @@ -cimport libc - -from addr cimport * - -cdef class sockaddr : - cdef void _init_family (self, libc.sa_family_t family=libc.AF_UNSPEC) : - self.family = family - - # XXX:use size_t - 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() - - cdef libc.sockaddr* _get_sockaddr_ptr (self) except NULL : - """ - Get the sockaddr pointer - """ - - cdef libc.sockaddr *sa - cdef libc.socklen_t sa_len - - self._get_sockaddr(&sa, &sa_len) - - return sa - - cdef libc.socklen_t _get_sockaddr_len (self) except -1 : - """ - Get the sockaddr len - """ - - cdef libc.sockaddr *sa - cdef libc.socklen_t sa_len - - self._get_sockaddr(&sa, &sa_len) - - return sa_len - - cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 : - """ - Set the sockaddr value for this address; sa_len must match! - """ - - 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] = &self.sockaddr - - if sa_len : - sa_len[0] = sizeof(self.sockaddr) - - return 0 - - cdef int _set_sockaddr (self, libc.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 - """ - - def __get__ (self) : - return libc.ntohs(self.sockaddr.sin_port) - - def __str__ (self) : - """ - Return the literal ASCII representation for this sockaddr as an ': 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] = &self.sockaddr - - if sa_len : - sa_len[0] = sizeof(self.sockaddr) - - return 0 - - cdef int _set_sockaddr (self, libc.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 - """ - - def __get__ (self) : - return libc.ntohs(self.sockaddr.sin6_port) - - - def __str__ (self) : - """ - Return the literal ASCII representation for this sockaddr as a '[]: string - """ - - # format - return "[%s]:%s" % self.getnameinfo() - -# mapping of AF -> sockaddr, user-modifyable -SOCKADDR_BY_FAMILY = { - libc.AF_INET: sockaddr_in, - libc.AF_INET6: sockaddr_in6, -} - -# build a sockaddr from the given sockaddr struct, based on sa_family -cdef sockaddr build_sockaddr (libc.sockaddr *sa, size_t sa_len) : - # lookup correct class to use - addr_type = SOCKADDR_BY_FAMILY[sa.sa_family] - - # construct with defaults - cdef sockaddr addr = addr_type() - - # store - addr._set_sockaddr(sa, sa_len) - - return addr - -cdef class addrinfo : - - cdef _init_addrinfo (self, libc.addrinfo *ai) : - #ai.flags = c_ai.ai_flags - self.family = ai.ai_family - self.socktype = ai.ai_socktype - self.protocol = ai.ai_protocol - self.addr = build_sockaddr(ai.ai_addr, ai.ai_addrlen) - self.canonname = ai.ai_canonname if ai.ai_canonname else None - - def __str__ (self) : - return "family=%d, socktype=%d, protocol=%d, addr=%s, canonname=%s" % (self.family, self.socktype, self.protocol, self.addr, self.canonname) - -cdef addrinfo build_addrinfo (libc.addrinfo *c_ai) : - cdef addrinfo ai = addrinfo() - - ai._init_addrinfo(c_ai) - - return ai - -cdef class endpoint : - - def __init__ (self, hostname=None, service=None) : - """ - Construct with the given hostname/service, either of which may be None. - - A hostname of None implies all valid local addresses (with AI_PASSIVE), and a service of None implies an - ephemeral port. - - hostname - the literal address or DNS hostname or anything else that GAI supports - service - the numeric port or service name - """ - - self.hostname = str(hostname) - self.service = str(service) - - cpdef getaddrinfo (self, int family, int socktype, int protocol = 0, int flags = libc.AI_PASSIVE) : - """ - Look up our hostname/service using the given socket parameters, and return a sequence of addrinfo objects. - """ - - # XXX: Cython doesn't support proper compound value literals... - cdef libc.addrinfo hints - - libc.memset(&hints, 0, sizeof(hints)) - hints.ai_flags = flags - hints.ai_family = family - hints.ai_socktype = socktype - hints.ai_protocol = protocol - - cdef libc.addrinfo *res, *r - cdef int err - cdef object ret = [] - - cdef char *hostname = NULL - cdef char *service = NULL - - if self.hostname is not None : - hostname = self.hostname - - if self.service is not None : - service = self.service - - # operate! - err = libc.c_getaddrinfo(hostname, service, &hints, &res) - - try : - if err : - # XXX: raise a GAIError - raise Exception(libc.gai_strerror(err)) - - # gather results - r = res - - while r : - ret.append(build_addrinfo(r)) - - r = r.ai_next - - # ok - return ret - - finally : - libc.c_freeaddrinfo(res) - - def __str__ (self) : - return "hostname=%s, service=%s" % (self.hostname, self.service) - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/socket/sock.pxd --- a/qmsk.net/socket/sock.pxd Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -""" - Sockect Object/API -""" - -ctypedef int socket_t - -cdef class sock : - """ - Represents a single OS-level socket - - >>> from socket import addr - >>> s = sock() - >>> s.send('foo') - Traceback (most recent call last): - ... - OSError: [Errno 9] Bad file descriptor - >>> s.socket() - >>> s.bind(addr.sockaddr_in('127.0.0.1', 1337)) - >>> s.listen(1) - >>> s.listen(0) - >>> s.connect(addr.sockaddr_in('127.0.01.', 1338)) - x - """ - - cdef readonly socket_t fd - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk.net/socket/sock.pyx --- a/qmsk.net/socket/sock.pyx Sun Aug 16 18:29:55 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,149 +0,0 @@ -from sock.sock cimport * -from sock.addr cimport sockaddr, build_sockaddr - -cimport libc, py - -from py cimport raise_errno - -# XXX: do some GIL-releasin' -cdef class sock : - - def __init__ (self, int fd = -1) : - """ - Construct this socket with the given fd, or -1 to mark it as fd-less - """ - - self.fd = fd - - def socket (self, int family = libc.AF_INET, int socktype = libc.SOCK_STREAM, int protocol = 0) : - """ - Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol. - - family - one of AF_* - socktype - one of SOCK_* - protocol - one of IPPROTO_* or zero to select default - """ - - if self.fd >= 0 : - raise Exception("Socket fd already exists") - - # socket() - self.fd = libc.socket(family, socktype, protocol) - - # trap - if self.fd < 0 : - raise_errno('socket') - - def bind (self, sockaddr addr) : - """ - Bind this socket to the given local socket address. The given sockaddr should be of the same or a - compatible address family. - - addr - the local address to bind to. The port may be zero to let the system choose an unused - ephemeral port. - """ - - cdef libc.sockaddr *sa_ptr - cdef libc.socklen_t sa_len - - # get the address - addr._get_sockaddr(&sa_ptr, &sa_len) - - # bind() - if libc.bind(self.fd, sa_ptr, sa_len) : - raise_errno('bind') - - def listen (self, int backlog) : - """ - Listen for connections, marking this socket as a passive socket, which can accept incoming connection - requests using sock.accept(). - - It is customary to call .bind() before .listen(). - - backlog - maximum number of pending connections (those not yet .accept()'d). - """ - - # listen() - if libc.listen(self.fd, backlog) : - raise_errno('listen') - - def connect (self, sockaddr addr) : - """ - Initiate a connection, connecting this socket to the remote endpoint specified by `addr`. The given sockaddr - should be of the same or a compatible address family. - - If the socket is in non-blocking mode, this will presumeably return errno.EINPROGRESS. - - If the socket has not yet been bound (using .bind()), the system will pick an appropriate local address and - ephemeral port. - - addr - the remote address to connect to. - """ - - cdef libc.sockaddr *sa_ptr - cdef libc.socklen_t sa_len - - # get the address - addr._get_sockaddr(&sa_ptr, &sa_len) - - # connect() - if libc.connect(self.fd, sa_ptr, sa_len) : - raise_errno('connect') - - def accept (self) : - """ - Accept a connection, dequeueing the first pending connection and returning a new sock object for it. This - socket must be a connection-based socket (SOCK_STREAM/SOCK_SEQPACKET) and in the passive listening mode - (.listen()). - - This returns a (sock, sockaddr) tuple: - sock - the newly created sock, corresponding to the incoming connection - sockaddr - the remote address of the incoming connection - """ - - # prep the sockaddr that we will return - cdef libc.sockaddr_storage ss - cdef libc.socklen_t ss_len = sizeof(ss) - - cdef socket_t sock_fd - - # accept() - sock_fd = libc.accept(self.fd, &ss, &ss_len) - - if sock_fd < 0 : - raise_errno('accept') - - # prep the new socket - sock_obj = sock(sock_fd) - - # prep the new addr - sock_addr = build_sockaddr( &ss, ss_len) - - return sock_obj, sock_addr - - def send (self, object buf, int flags = 0) : - """ - Transmit a message to the connected remote endpoint. - - buf - the data to send - flags - MSG_* flags to send with - - Returns the number of bytes sent, which may be less than the length of buf. - """ - - cdef char *buf_ptr - cdef libc.ssize_t buf_len, ret - - # get buffer - # XXX: test that except works right - py.PyObject_AsCharBuffer(buf, &buf_ptr, &buf_len) - - # send() - ret = libc.send(self.fd, buf_ptr, buf_len, flags) - - if ret < 0 : - raise_errno('send') - - else : - return ret - diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/libc.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/libc.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,315 @@ +""" + 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 + +cdef extern from "sys/types.h" : + # potentially wrong... + ctypedef signed long ssize_t + +# +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 "errno.h" : + int errno + +cdef extern from "string.h" : + void* memcpy (void *dest, void *src, size_t n) + void* memset (void *s, int c, size_t n) + + char* strerror (int errno) + +cdef extern from "alloca.h" : + void* alloca (size_t size) + +cdef extern from "sys/uio.h" : + struct iovec : + void *iov_base + size_t iov_len + +cdef extern from "arpa/inet.h" : + # XXX: correct?! + ctypedef uint32_t socklen_t + + 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 "sys/socket.h" : + # socket types + enum : + SOCK_STREAM + SOCK_DGRAM + SOCK_RAW + SOCK_RDM + SOCK_SEQPACKET + SOCK_PACKET + + # packet/address families + enum : + PF_UNSPEC + PF_LOCAL + PF_UNIX # same as PF_LOCAL + PF_FILE # same as PF_LOCAL + PF_INET + PF_INET6 + PF_NETLINK + PF_ROUTE # same as PF_NETLINK + + + # aliases for PF_* + enum : + AF_UNSPEC + AF_LOCAL + AF_UNIX + AF_FILE + AF_INET + AF_INET6 + AF_NETLINK + AF_ROUTE + + # base sockaddr stuff + ctypedef uint16_t sa_family_t + + struct sockaddr : + sa_family_t sa_family + + struct sockaddr_storage : + sa_family_t ss_family + + # flag values + enum : + MSG_OOB + MSG_PEEK + MSG_DONTROUTE + MSG_CTRUNC + MSG_PROXY + MSG_TRUNC + MSG_DONTWAIT + MSG_EOR + MSG_WAITALL + MSG_FIN + MSG_SYN + MSG_CONFIRM + MSG_RST + MSG_ERRQUEUE + MSG_NOSIGNAL + MSG_MORE + MSG_CMSG_CLOEXEC + + ## send/recv-msg + struct msghdr : + void *msg_name # sockaddr + socklen_t msg_namelen + + iovec *msg_iov # message data + size_t msg_iovlen + + void *msg_control # aux data + size_t msg_controllen + + int msg_flags # flags + + struct cmsghdr : + size_t cmsg_len # length including this cmsghdr struct + + int cmsg_level # originating protocol (IPPROTO_* ???) + int cmsg_type # protocol-specific type + + ## socket-level cmsghdr types + enum : + SCM_RIGHTS + SCM_CREDENTIALS + + #- ucred + + # SO_LINGER parameters + struct linger : + int l_onoff + int l_linger + + + ## API + int socket (int domain, int socktype, int protocol) + int bind (int fd, sockaddr *addr, socklen_t len) + int connect (int fd, sockaddr *addr, socklen_t len) + int listen (int fd, int n) + int accept (int fd, sockaddr *addr, socklen_t *len) + int shutdown (int fd, int how) + + int getsockname (int fd, sockaddr *addr, socklen_t *len) + int getpeername (int fd, sockaddr *addr, socklen_t *len) + + ssize_t send (int fd, void *buf, size_t n, int flags) + ssize_t recv (int fd, void *buf, size_t n, int flags) + ssize_t sendto (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) + ssize_t recvfrom (int fd, void *buf, size_t n, int flags, sockaddr *addr, socklen_t addr_len) + ssize_t sendmsg (int fd, msghdr *msg, int flags) + ssize_t recvmsg (int fd, msghdr *msg, int flags) + + int getsockopt (int fd, int level, int optname, void *optval, socklen_t optlen) + int setsockopt (int fd, int level, int optname, void *optval, socklen_t optlen) + + enum : + SHUT_RD + SHUT_WR + SHUT_RDWR + +cdef extern from "netinet/in.h" : + ## socket protocol types + enum : + IPPROTO_IP + IPPROTO_ICMP + IPPROTO_IGMP + IPPROTO_TCP + IPPROTO_UDP + IPPROTO_IPV6 + IPPROTO_ICMPV6 + IPPROTO_SCTP + IPPROTO_RAW + + + ## ports + ctypedef uint16_t in_port_t + + ## AF_INET + ctypedef uint32_t in_addr_t + struct in_addr : + in_addr_t s_addr + + # XXX: should these be in another cdef? + in_addr_t INADDR_ANY + + ## AF_INET6 + struct in6_addr : + # XXX: check POSIX... + uint8_t s6_addr[16] + uint16_t s6_addr16[8] + uint32_t s6_addr32[4] + + # common in6_addr's + in6_addr in6addr_any + in6_addr in6addr_loopback + + ## constants + enum : + INET_ADDRSTRLEN + INET6_ADDRSTRLEN + + ## sockaddrs + struct sockaddr_in : + sa_family_t sin_family + in_port_t sin_port + in_addr sin_addr + + 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 + + uint16_t htons(uint16_t) + uint32_t htonl(uint32_t) + uint16_t ntohs(uint16_t) + uint32_t ntohl(uint32_t) + +cdef extern from "netdb.h" : + ## getaddrinfo + struct addrinfo : + int ai_flags + int ai_family + int ai_socktype + int ai_protocol + int ai_addrlen + sockaddr *ai_addr + char *ai_canonname + addrinfo *ai_next + + enum : + AI_PASSIVE + AI_CANONNAME + AI_NUMERICHOST + AI_V4MAPPED + AI_ALL + AI_ADDRCONFIG + # AI_*IDN* + AI_NUMERICSERV + + int c_getaddrinfo "getaddrinfo" ( + char *node, char *service, + addrinfo *hints, addrinfo **res + ) + + void c_freeaddrinfo "freeaddrinfo" (addrinfo *res) + + ## getnameinfo + 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) + +## general errno-based errors +#cdef class Errno (py.OSError) : +# """ +# Some libc function returned an error code: +# +# func - the name of the function called +# err - the system error code +# strerror - human-readable error code -> message +# """ +# +# cdef readonly char *func +# cdef readonly int err +# cdef readonly object strerror +# +#cdef class GAIError (py.OSError) : +# """ +# Some libc GAI function returnd an error code: +# +# func - the name of the function called +# err - the GAI_* error code +# strerror - human-readable error code -> message +# """ +# +# cdef readonly char *func +# cdef readonly int err +# cdef readonly object strerror +# diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/libc.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/libc.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,61 @@ +from libc cimport * +from py cimport raise_errno + +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 : + raise_errno('inet_ntop') + + # autoconvert -> str + return buf + +cdef object inet_pton (int af, char *addr, void *sockaddr_out) : + cdef int ret + + ret = c_inet_pton(af, addr, sockaddr_out) + + if ret < 0 : + raise_errno('inet_pton') + + elif ret == 0 : + raise NameError("Invalid network address for specified address family: %r" % (addr, )) + +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)) +# raise GAIError('getnameinfo', err) + + else : + return hostbuf, servbuf + +#cdef class Errno (py.OSError) : +# def __init__ (self, func) : +# self.func = func +# self.err = errno +# self.strerror = strerror(errno) +# +# def __str__ (self) : +# return "%s: %s" % (self.func, self.strerror) +# +#cdef class GAIError (py.OSError) : +# def __init__ (self, func, err) : +# self.func = func +# self.err = err +# self.strerror = gai_strerror(err) +# +# def __str__ (self) : +# return "%s: %s" % (self.func, self.strerror) +# diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/py.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/py.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,18 @@ +cimport libc + +cdef extern from "Python.h" : + struct PyObject : + pass + + ## string stuff + int PyObject_AsCharBuffer (object obj, char **buf, libc.ssize_t *len) except -1 + + ## except setting + PyObject* PyErr_SetFromErrno (PyObject *type) + + PyObject *PyExc_OSError + +# raise OSError with errno +# XXX: doesn't do anything with func +cdef int raise_errno (char *func) except -1 + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/py.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/py.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,7 @@ +from py cimport * + +cdef int raise_errno (char *func) except -1 : + PyErr_SetFromErrno(PyExc_OSError) + + return -1 + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/sctp/constants.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/sctp/constants.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,62 @@ +cimport sctp.sock as sctp + +SOL_SCTP = sctp.SOL_SCTP +IPPROTO_SCTP = sctp.IPPROTO_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 10bd48c9b6ce -r 74fde84264b1 qmsk/net/sctp/sock.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/sctp/sock.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,206 @@ +cimport libc + +from libc cimport __u8, __u16, __u32, __s8, __s16, __s32 + +# +# 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 + + # 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 + libc.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 + enum : + SCTP_BINDX_ADD_ADDR + SCTP_BINDX_REM_ADDR + + int c_sctp_bindx "sctp_bindx" (int sd, libc.sockaddr *addrs, int addrcnt, int flags) + + # XXX: missing return-sctp_assoc_t-id argument! + int c_sctp_connectx "sctp_connectx" (int sd, libc.sockaddr *addrs, int addrcnt) + + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/sctp/sock.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/sctp/sock.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,98 @@ +""" + This C(ython) extension module provides an interface to the libsctp library and associated socket API. + + >>> import socket + >>> from sock.addr import sockaddr_in + >>> s = socket.socket(socket.AF_INET, socket.SOCK_SEQPACKET, 132) + >>> sctp_bindx(s.fileno(), [sockaddr_in('127.0.0.1', 1337), sockaddr_in('127.0.0.2')], 0x01) + >>> + +""" + +from sctp.sock cimport * +from py cimport raise_errno + +cimport libc +cimport socket.addr + +cdef size_t addrsoup_len (object addrs) except -1 : + """ + Calculate the length of the addr_buf required to store the given addrsoup + """ + + cdef socket.addr.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 socket.addr.sockaddr addr + cdef char *addr_ptr = addr_buf + + # fill it + cdef libc.sockaddr *sa + cdef libc.socklen_t sa_len + + for addr in addrs : + # get address's sockaddr info + addr._get_sockaddr(&sa, &sa_len) + + # copy to buffer + libc.memcpy(addr_ptr, sa, sa_len) + + # move to next + addr_ptr += sa_len + +def sctp_bindx (int sd, object addrs, int flags) : + """ + Bind the given SOCK_SEQPACKET to the given set of sock.addr.sockaddr's. + + sd the system socket FD + addresses the list of qmsk.net.sock.addr.sockaddr's + flags one of SCTP_BINDX_ADD/REM_ADDR + + """ + + # ensure that addrs stays the same... ? + addrs = tuple(addrs) + + # alloc buffer to hold all the sockaddr_*'s + cdef char *addr_buf = libc.alloca(addrsoup_len(addrs)) + + # store + addrsoup_store(addrs, addr_buf) + + # then call + if c_sctp_bindx(sd, addr_buf, len(addrs), flags) < 0 : + raise_errno('sctp_bindx') + +def sctp_connectx (int sd, object addrs) : + """ + Connect the given SOCK_SEQPACKET to the given set of remote sock.addr.sockaddr's. + + sd the system socket FD + addresses the list of qmsk.net.sock.addr.sockaddr's + + """ + + # ensure that addrs stays the same... ? + addrs = tuple(addrs) + + # alloc buffer to hold all the sockaddr_*'s + cdef char *addr_buf = libc.alloca(addrsoup_len(addrs)) + + # store + addrsoup_store(addrs, addr_buf) + + # then call + if c_sctp_connectx(sd, addr_buf, len(addrs)) < 0 : + raise_errno('sctp_connectx') + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/socket/addr.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/addr.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,95 @@ +""" + Socket addresses at various levels: + + sockaddr - specific network-level address for socket operations + addrinfo - information on a specific sockaddr including its socket parameters + endpoint - human-readable network address, corresponding to multiple sockaddr's +""" + +cimport libc + +cdef class sockaddr : + """ + A network-level socket address + + XXX: rename to 'address' + + >>> sockaddr().family + 0 + >>> sockaddr().port + Traceback (most recent call last): + ... + NotImplementedError + >>> sockaddr().getnameinfo() + Traceback (most recent call last): + ... + NotImplementedError + """ + + # address family + # XXX: this should be a class constant! It's part of our type safety! + cdef readonly libc.sa_family_t family + + cdef void _init_family (self, libc.sa_family_t family = ?) + + # get the sockaddr/socklen + # each of these can be NULL to ignore it + cdef int _get_sockaddr (self, libc.sockaddr **sa_ptr, libc.socklen_t *sa_len) except -1 + + cdef libc.sockaddr* _get_sockaddr_ptr (self) except NULL + cdef libc.socklen_t _get_sockaddr_len (self) except -1 + + # set the sockaddr, socklen must match + cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 + +# build a sockaddr from the given sockaddr struct, based on sa_family +cdef sockaddr build_sockaddr (libc.sockaddr *sa, size_t sa_len) + +cdef class addrinfo : + """ + A socket-level endpoint address, which contains the full socket parameters and an bind/connect address + """ + +# cdef readonly int flags + cdef readonly int family, socktype, protocol + cdef readonly sockaddr addr + cdef readonly object canonname + + cdef _init_addrinfo (self, libc.addrinfo *c_ai) + +# build and return a new addrinfo instance +cdef addrinfo build_addrinfo (libc.addrinfo *c_ai) + +cdef class endpoint : + """ + A network-level socket endpoint. This is the level that humans mostly work with, but the tricky bit is that + an endpoint can map to more than one sockaddr... + + Hence, endpoints are stored as human-readable hostname/service strings, which are then translated to sockaddrs + using getaddrinfo. + + >>> import socket + >>> e = endpoint('127.0.0.1', 80) + >>> str(e) + 'hostname=127.0.0.1, service=80' + >>> res = e.getaddrinfo(socket.AF_UNSPEC, socket.SOCK_STREAM) + >>> len(res) + 1 + >>> str(res[0]) + 'family=2, socktype=1, protocol=6, addr=127.0.0.1:80, canonname=None' + >>> e = endpoint('2001::5', 80) + >>> str(e) + 'hostname=2001::5, service=80' + >>> res = e.getaddrinfo(socket.AF_UNSPEC, socket.SOCK_STREAM) + >>> len(res) + 1 + >>> str(res[0]) + 'family=10, socktype=1, protocol=6, addr=[2001::5]:80, canonname=None' + + """ + + # our defining attributes, set via __init__ + cdef object hostname, service + + cpdef getaddrinfo (self, int family, int socktype, int protocol = ?, int flags = ?) + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/socket/addr.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/addr.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,349 @@ +cimport libc + +from addr cimport * + +cdef class sockaddr : + cdef void _init_family (self, libc.sa_family_t family=libc.AF_UNSPEC) : + self.family = family + + # XXX:use size_t + 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() + + cdef libc.sockaddr* _get_sockaddr_ptr (self) except NULL : + """ + Get the sockaddr pointer + """ + + cdef libc.sockaddr *sa + cdef libc.socklen_t sa_len + + self._get_sockaddr(&sa, &sa_len) + + return sa + + cdef libc.socklen_t _get_sockaddr_len (self) except -1 : + """ + Get the sockaddr len + """ + + cdef libc.sockaddr *sa + cdef libc.socklen_t sa_len + + self._get_sockaddr(&sa, &sa_len) + + return sa_len + + cdef int _set_sockaddr (self, libc.sockaddr *sa, size_t sa_len) except -1 : + """ + Set the sockaddr value for this address; sa_len must match! + """ + + 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] = &self.sockaddr + + if sa_len : + sa_len[0] = sizeof(self.sockaddr) + + return 0 + + cdef int _set_sockaddr (self, libc.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 + """ + + def __get__ (self) : + return libc.ntohs(self.sockaddr.sin_port) + + def __str__ (self) : + """ + Return the literal ASCII representation for this sockaddr as an ': 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] = &self.sockaddr + + if sa_len : + sa_len[0] = sizeof(self.sockaddr) + + return 0 + + cdef int _set_sockaddr (self, libc.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 + """ + + def __get__ (self) : + return libc.ntohs(self.sockaddr.sin6_port) + + + def __str__ (self) : + """ + Return the literal ASCII representation for this sockaddr as a '[]: string + """ + + # format + return "[%s]:%s" % self.getnameinfo() + +# mapping of AF -> sockaddr, user-modifyable +SOCKADDR_BY_FAMILY = { + libc.AF_INET: sockaddr_in, + libc.AF_INET6: sockaddr_in6, +} + +# build a sockaddr from the given sockaddr struct, based on sa_family +cdef sockaddr build_sockaddr (libc.sockaddr *sa, size_t sa_len) : + # lookup correct class to use + addr_type = SOCKADDR_BY_FAMILY[sa.sa_family] + + # construct with defaults + cdef sockaddr addr = addr_type() + + # store + addr._set_sockaddr(sa, sa_len) + + return addr + +cdef class addrinfo : + + cdef _init_addrinfo (self, libc.addrinfo *ai) : + #ai.flags = c_ai.ai_flags + self.family = ai.ai_family + self.socktype = ai.ai_socktype + self.protocol = ai.ai_protocol + self.addr = build_sockaddr(ai.ai_addr, ai.ai_addrlen) + self.canonname = ai.ai_canonname if ai.ai_canonname else None + + def __str__ (self) : + return "family=%d, socktype=%d, protocol=%d, addr=%s, canonname=%s" % (self.family, self.socktype, self.protocol, self.addr, self.canonname) + +cdef addrinfo build_addrinfo (libc.addrinfo *c_ai) : + cdef addrinfo ai = addrinfo() + + ai._init_addrinfo(c_ai) + + return ai + +cdef class endpoint : + + def __init__ (self, hostname=None, service=None) : + """ + Construct with the given hostname/service, either of which may be None. + + A hostname of None implies all valid local addresses (with AI_PASSIVE), and a service of None implies an + ephemeral port. + + hostname - the literal address or DNS hostname or anything else that GAI supports + service - the numeric port or service name + """ + + self.hostname = str(hostname) + self.service = str(service) + + cpdef getaddrinfo (self, int family, int socktype, int protocol = 0, int flags = libc.AI_PASSIVE) : + """ + Look up our hostname/service using the given socket parameters, and return a sequence of addrinfo objects. + """ + + # XXX: Cython doesn't support proper compound value literals... + cdef libc.addrinfo hints + + libc.memset(&hints, 0, sizeof(hints)) + hints.ai_flags = flags + hints.ai_family = family + hints.ai_socktype = socktype + hints.ai_protocol = protocol + + cdef libc.addrinfo *res, *r + cdef int err + cdef object ret = [] + + cdef char *hostname = NULL + cdef char *service = NULL + + if self.hostname is not None : + hostname = self.hostname + + if self.service is not None : + service = self.service + + # operate! + err = libc.c_getaddrinfo(hostname, service, &hints, &res) + + try : + if err : + # XXX: raise a GAIError + raise Exception(libc.gai_strerror(err)) + + # gather results + r = res + + while r : + ret.append(build_addrinfo(r)) + + r = r.ai_next + + # ok + return ret + + finally : + libc.c_freeaddrinfo(res) + + def __str__ (self) : + return "hostname=%s, service=%s" % (self.hostname, self.service) + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/socket/socket.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/socket.pxd Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,26 @@ +""" + Sockect Object/API +""" + +ctypedef int socket_t + +cdef class sock : + """ + Represents a single OS-level socket + + >>> from socket import addr + >>> s = sock() + >>> s.send('foo') + Traceback (most recent call last): + ... + OSError: [Errno 9] Bad file descriptor + >>> s.socket() + >>> s.bind(addr.sockaddr_in('127.0.0.1', 1337)) + >>> s.listen(1) + >>> s.listen(0) + >>> s.connect(addr.sockaddr_in('127.0.01.', 1338)) + x + """ + + cdef readonly socket_t fd + diff -r 10bd48c9b6ce -r 74fde84264b1 qmsk/net/socket/socket.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/socket.pyx Sun Aug 16 19:01:21 2009 +0300 @@ -0,0 +1,150 @@ +from qmsk.net.socket.socket cimport * +from qmsk.net.socket.addr cimport sockaddr, build_sockaddr + +cimport libc, py + +from py cimport raise_errno + + +# XXX: do some GIL-releasin' +cdef class sock : + + def __init__ (self, int fd = -1) : + """ + Construct this socket with the given fd, or -1 to mark it as fd-less + """ + + self.fd = fd + + def socket (self, int family = libc.AF_INET, int socktype = libc.SOCK_STREAM, int protocol = 0) : + """ + Create a new socket endpoint with the given family/domain, socktype and optionally, specific protocol. + + family - one of AF_* + socktype - one of SOCK_* + protocol - one of IPPROTO_* or zero to select default + """ + + if self.fd >= 0 : + raise Exception("Socket fd already exists") + + # socket() + self.fd = libc.socket(family, socktype, protocol) + + # trap + if self.fd < 0 : + raise_errno('socket') + + def bind (self, sockaddr addr) : + """ + Bind this socket to the given local socket address. The given sockaddr should be of the same or a + compatible address family. + + addr - the local address to bind to. The port may be zero to let the system choose an unused + ephemeral port. + """ + + cdef libc.sockaddr *sa_ptr + cdef libc.socklen_t sa_len + + # get the address + addr._get_sockaddr(&sa_ptr, &sa_len) + + # bind() + if libc.bind(self.fd, sa_ptr, sa_len) : + raise_errno('bind') + + def listen (self, int backlog) : + """ + Listen for connections, marking this socket as a passive socket, which can accept incoming connection + requests using sock.accept(). + + It is customary to call .bind() before .listen(). + + backlog - maximum number of pending connections (those not yet .accept()'d). + """ + + # listen() + if libc.listen(self.fd, backlog) : + raise_errno('listen') + + def connect (self, sockaddr addr) : + """ + Initiate a connection, connecting this socket to the remote endpoint specified by `addr`. The given sockaddr + should be of the same or a compatible address family. + + If the socket is in non-blocking mode, this will presumeably return errno.EINPROGRESS. + + If the socket has not yet been bound (using .bind()), the system will pick an appropriate local address and + ephemeral port. + + addr - the remote address to connect to. + """ + + cdef libc.sockaddr *sa_ptr + cdef libc.socklen_t sa_len + + # get the address + addr._get_sockaddr(&sa_ptr, &sa_len) + + # connect() + if libc.connect(self.fd, sa_ptr, sa_len) : + raise_errno('connect') + + def accept (self) : + """ + Accept a connection, dequeueing the first pending connection and returning a new sock object for it. This + socket must be a connection-based socket (SOCK_STREAM/SOCK_SEQPACKET) and in the passive listening mode + (.listen()). + + This returns a (sock, sockaddr) tuple: + sock - the newly created sock, corresponding to the incoming connection + sockaddr - the remote address of the incoming connection + """ + + # prep the sockaddr that we will return + cdef libc.sockaddr_storage ss + cdef libc.socklen_t ss_len = sizeof(ss) + + cdef socket_t sock_fd + + # accept() + sock_fd = libc.accept(self.fd, &ss, &ss_len) + + if sock_fd < 0 : + raise_errno('accept') + + # prep the new socket + sock_obj = sock(sock_fd) + + # prep the new addr + sock_addr = build_sockaddr( &ss, ss_len) + + return sock_obj, sock_addr + + def send (self, object buf, int flags = 0) : + """ + Transmit a message to the connected remote endpoint. + + buf - the data to send + flags - MSG_* flags to send with + + Returns the number of bytes sent, which may be less than the length of buf. + """ + + cdef char *buf_ptr + cdef libc.ssize_t buf_len, ret + + # get buffer + # XXX: test that except works right + py.PyObject_AsCharBuffer(buf, &buf_ptr, &buf_len) + + # send() + ret = libc.send(self.fd, buf_ptr, buf_len, flags) + + if ret < 0 : + raise_errno('send') + + else : + return ret + diff -r 10bd48c9b6ce -r 74fde84264b1 setup.py --- a/setup.py Sun Aug 16 18:29:55 2009 +0300 +++ b/setup.py Sun Aug 16 19:01:21 2009 +0300 @@ -6,14 +6,31 @@ return Extension(name, files, include_dirs=['inc'], **opts) setup( - cmdclass = {'build_ext': build_ext}, + name = 'qmsk.net', + version = '0.0.1', + description = "Python network programming re-invented", + author = "Tero Marttila", + author_email = "terom@fixme.fi", + url = "http://projects.qmsk.net/qmsk.net", + + # for python code + packages = [ + 'qmsk.net.socket', + 'qmsk.net.sctp', + ], + + # override build_ext to use Cython + cmdclass = {'build_ext': build_ext}, + + # describe Cython modules + ext_package = 'qmsk.net', ext_modules = [ - cython_ext("libc", ["libc.pyx"]), - cython_ext("py", ["py.pyx"]), - cython_ext("socket.addr", ["socket/addr.pyx"]), - cython_ext("socket.sock", ["socket/sock.pyx"]), - cython_ext("sctp.sock", ["sctp/sock.pyx"], libraries=['sctp']), - cython_ext("sctp.constants", ["sctp/constants.pyx"]), + cython_ext("libc", ["qmsk/net/libc.pyx"]), + cython_ext("py", ["qmsk/net/py.pyx"]), + cython_ext("socket.addr", ["qmsk/net/socket/addr.pyx"]), + cython_ext("socket.socket", ["qmsk/net/socket/socket.pyx"]), + cython_ext("sctp.sock", ["qmsk/net/sctp/sock.pyx"], libraries=['sctp']), + cython_ext("sctp.constants", ["qmsk/net/sctp/constants.pyx"]), ] )