# HG changeset patch # User Tero Marttila # Date 1250461771 -10800 # Node ID 0e4933d5862e86159e0605119201d561d01fa208 # Parent e6b670dbfe3b140a047e5b81be27a2fae623924e rename qmsk.net.socket.addr -> qmsk.net.socket.address diff -r e6b670dbfe3b -r 0e4933d5862e .hgignore --- a/.hgignore Mon Aug 17 01:24:28 2009 +0300 +++ b/.hgignore Mon Aug 17 01:29:31 2009 +0300 @@ -5,3 +5,5 @@ \.so$ ^build/ + +^qmsk/net/.+\.c$ diff -r e6b670dbfe3b -r 0e4933d5862e qmsk/net/py.pxd --- a/qmsk/net/py.pxd Mon Aug 17 01:24:28 2009 +0300 +++ b/qmsk/net/py.pxd Mon Aug 17 01:29:31 2009 +0300 @@ -23,10 +23,6 @@ PyObject *PyExc_OSError -## custom haxes -#cdef extern from "_py.c" : -# object py_string_resize (object string, ssize_t new_size) - # raise OSError with errno # XXX: doesn't do anything with func cdef int raise_errno (char *func) except -1 diff -r e6b670dbfe3b -r 0e4933d5862e qmsk/net/sctp/sock.pyx --- a/qmsk/net/sctp/sock.pyx Mon Aug 17 01:24:28 2009 +0300 +++ b/qmsk/net/sctp/sock.pyx Mon Aug 17 01:29:31 2009 +0300 @@ -10,10 +10,11 @@ """ from qmsk.net.sctp.sock cimport * -from qmsk.net.socket.addr cimport sockaddr -from qmsk.net.socket cimport platform +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 : diff -r e6b670dbfe3b -r 0e4933d5862e qmsk/net/socket/addr.pxd --- a/qmsk/net/socket/addr.pxd Mon Aug 17 01:24:28 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +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 qmsk.net.libc as libc - -cimport qmsk.net.socket.platform as platform - -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 platform.sa_family_t family - - cdef void _init_family (self, platform.sa_family_t family = ?) - - # get the sockaddr/socklen - # each of these can be NULL to ignore it - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 - - cdef platform.sockaddr* _get_sockaddr_ptr (self) except NULL - cdef platform.socklen_t _get_sockaddr_len (self) except -1 - - # set the sockaddr, socklen must match - cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 - -# build a sockaddr from the given sockaddr struct, based on sa_family -cdef sockaddr build_sockaddr (platform.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, platform.addrinfo *c_ai) - -# build and return a new addrinfo instance -cdef addrinfo build_addrinfo (platform.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. - - >>> from __future__ import absolute_import; import socket as _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 e6b670dbfe3b -r 0e4933d5862e qmsk/net/socket/addr.pyx --- a/qmsk/net/socket/addr.pyx Mon Aug 17 01:24:28 2009 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,354 +0,0 @@ -cimport qmsk.net.libc as libc - -from qmsk.net.socket.addr cimport * - -cimport qmsk.net.socket.platform as platform - -cdef class sockaddr : - cdef void _init_family (self, platform.sa_family_t family=platform.AF_UNSPEC) : - self.family = family - - # XXX:use size_t - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : - """ - Get the sockaddr pointer and sockaddr length for this address - """ - - raise NotImplementedError() - - cdef platform.sockaddr* _get_sockaddr_ptr (self) except NULL : - """ - Get the sockaddr pointer - """ - - cdef platform.sockaddr *sa - cdef platform.socklen_t sa_len - - self._get_sockaddr(&sa, &sa_len) - - return sa - - cdef platform.socklen_t _get_sockaddr_len (self) except -1 : - """ - Get the sockaddr len - """ - - cdef platform.sockaddr *sa - cdef platform.socklen_t sa_len - - self._get_sockaddr(&sa, &sa_len) - - return sa_len - - cdef int _set_sockaddr (self, platform.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 platform.sockaddr *sa - cdef platform.socklen_t sa_len - - # XXX: take as args? - cdef int flags = platform.NI_NUMERICHOST | platform.NI_NUMERICSERV - - # get our abstract sockaddr - self._get_sockaddr(&sa, &sa_len) - - # get nice text format - return platform.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) - - 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' - >>> str(sockaddr_in()) - '0.0.0.0:0' - """ - - # 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) - """ - - # store our family - # XXX: this should be a class attribute... - self._init_family(platform.AF_INET) - - # constant af - self.sockaddr.sin_family = self.family - - # set the sin_port - self.sockaddr.sin_port = platform.htons(port) - - if addr : - # set the sin_addr - # this automatically converts the addr from str -> char * - platform.inet_pton(self.family, addr, &self.sockaddr.sin_addr) - - else : - # set as INADDR_ANY - self.sockaddr.sin_addr.s_addr = platform.INADDR_ANY - - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : - if sa_ptr : - sa_ptr[0] = &self.sockaddr - - if sa_len : - sa_len[0] = sizeof(self.sockaddr) - - return 0 - - cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 : - assert sa_len == sizeof(self.sockaddr) - - libc.memcpy(&self.sockaddr, sa, sa_len) - - property port : - """ - The integer port number - """ - - def __get__ (self) : - return platform.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 platform.sockaddr_in6 sockaddr - - def __init__ (self, object addr=None, platform.in_port_t port=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) - """ - - # 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 - - cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : - if sa_ptr : - sa_ptr[0] = &self.sockaddr - - if sa_len : - sa_len[0] = sizeof(self.sockaddr) - - return 0 - - cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 : - assert sa_len == sizeof(self.sockaddr) - - libc.memcpy(&self.sockaddr, sa, sa_len) - - property port : - """ - The integer port number - """ - - def __get__ (self) : - return platform.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 = { - platform.AF_INET: sockaddr_in, - platform.AF_INET6: sockaddr_in6, -} - -# build a sockaddr from the given sockaddr struct, based on sa_family -cdef sockaddr build_sockaddr (platform.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, platform.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 (platform.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 = platform.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 platform.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 platform.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 = platform.c_getaddrinfo(hostname, service, &hints, &res) - - try : - if err : - # XXX: raise a GAIError - raise Exception(platform.gai_strerror(err)) - - # gather results - r = res - - while r : - ret.append(build_addrinfo(r)) - - r = r.ai_next - - # ok - return ret - - finally : - platform.c_freeaddrinfo(res) - - def __str__ (self) : - return "hostname=%s, service=%s" % (self.hostname, self.service) - diff -r e6b670dbfe3b -r 0e4933d5862e qmsk/net/socket/address.pxd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/address.pxd Mon Aug 17 01:29:31 2009 +0300 @@ -0,0 +1,97 @@ +""" + 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 qmsk.net.libc as libc + +cimport qmsk.net.socket.platform as platform + +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 platform.sa_family_t family + + cdef void _init_family (self, platform.sa_family_t family = ?) + + # get the sockaddr/socklen + # each of these can be NULL to ignore it + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 + + cdef platform.sockaddr* _get_sockaddr_ptr (self) except NULL + cdef platform.socklen_t _get_sockaddr_len (self) except -1 + + # set the sockaddr, socklen must match + cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 + +# build a sockaddr from the given sockaddr struct, based on sa_family +cdef sockaddr build_sockaddr (platform.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, platform.addrinfo *c_ai) + +# build and return a new addrinfo instance +cdef addrinfo build_addrinfo (platform.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. + + >>> from __future__ import absolute_import; import socket as _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 e6b670dbfe3b -r 0e4933d5862e qmsk/net/socket/address.pyx --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/qmsk/net/socket/address.pyx Mon Aug 17 01:29:31 2009 +0300 @@ -0,0 +1,354 @@ +cimport qmsk.net.libc as libc + +from qmsk.net.socket.address cimport * + +cimport qmsk.net.socket.platform as platform + +cdef class sockaddr : + cdef void _init_family (self, platform.sa_family_t family=platform.AF_UNSPEC) : + self.family = family + + # XXX:use size_t + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : + """ + Get the sockaddr pointer and sockaddr length for this address + """ + + raise NotImplementedError() + + cdef platform.sockaddr* _get_sockaddr_ptr (self) except NULL : + """ + Get the sockaddr pointer + """ + + cdef platform.sockaddr *sa + cdef platform.socklen_t sa_len + + self._get_sockaddr(&sa, &sa_len) + + return sa + + cdef platform.socklen_t _get_sockaddr_len (self) except -1 : + """ + Get the sockaddr len + """ + + cdef platform.sockaddr *sa + cdef platform.socklen_t sa_len + + self._get_sockaddr(&sa, &sa_len) + + return sa_len + + cdef int _set_sockaddr (self, platform.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 platform.sockaddr *sa + cdef platform.socklen_t sa_len + + # XXX: take as args? + cdef int flags = platform.NI_NUMERICHOST | platform.NI_NUMERICSERV + + # get our abstract sockaddr + self._get_sockaddr(&sa, &sa_len) + + # get nice text format + return platform.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) + + 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' + >>> str(sockaddr_in()) + '0.0.0.0:0' + """ + + # 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) + """ + + # store our family + # XXX: this should be a class attribute... + self._init_family(platform.AF_INET) + + # constant af + self.sockaddr.sin_family = self.family + + # set the sin_port + self.sockaddr.sin_port = platform.htons(port) + + if addr : + # set the sin_addr + # this automatically converts the addr from str -> char * + platform.inet_pton(self.family, addr, &self.sockaddr.sin_addr) + + else : + # set as INADDR_ANY + self.sockaddr.sin_addr.s_addr = platform.INADDR_ANY + + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : + if sa_ptr : + sa_ptr[0] = &self.sockaddr + + if sa_len : + sa_len[0] = sizeof(self.sockaddr) + + return 0 + + cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 : + assert sa_len == sizeof(self.sockaddr) + + libc.memcpy(&self.sockaddr, sa, sa_len) + + property port : + """ + The integer port number + """ + + def __get__ (self) : + return platform.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 platform.sockaddr_in6 sockaddr + + def __init__ (self, object addr=None, platform.in_port_t port=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) + """ + + # 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 + + cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 : + if sa_ptr : + sa_ptr[0] = &self.sockaddr + + if sa_len : + sa_len[0] = sizeof(self.sockaddr) + + return 0 + + cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 : + assert sa_len == sizeof(self.sockaddr) + + libc.memcpy(&self.sockaddr, sa, sa_len) + + property port : + """ + The integer port number + """ + + def __get__ (self) : + return platform.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 = { + platform.AF_INET: sockaddr_in, + platform.AF_INET6: sockaddr_in6, +} + +# build a sockaddr from the given sockaddr struct, based on sa_family +cdef sockaddr build_sockaddr (platform.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, platform.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 (platform.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 = platform.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 platform.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 platform.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 = platform.c_getaddrinfo(hostname, service, &hints, &res) + + try : + if err : + # XXX: raise a GAIError + raise Exception(platform.gai_strerror(err)) + + # gather results + r = res + + while r : + ret.append(build_addrinfo(r)) + + r = r.ai_next + + # ok + return ret + + finally : + platform.c_freeaddrinfo(res) + + def __str__ (self) : + return "hostname=%s, service=%s" % (self.hostname, self.service) + diff -r e6b670dbfe3b -r 0e4933d5862e qmsk/net/socket/socket.pyx --- a/qmsk/net/socket/socket.pyx Mon Aug 17 01:24:28 2009 +0300 +++ b/qmsk/net/socket/socket.pyx Mon Aug 17 01:29:31 2009 +0300 @@ -1,5 +1,5 @@ from qmsk.net.socket.socket cimport * -from qmsk.net.socket.addr cimport sockaddr, build_sockaddr +from qmsk.net.socket.address cimport sockaddr, build_sockaddr cimport qmsk.net.socket.platform as platform cimport qmsk.net.libc as libc, qmsk.net.py as py diff -r e6b670dbfe3b -r 0e4933d5862e setup.py --- a/setup.py Mon Aug 17 01:24:28 2009 +0300 +++ b/setup.py Mon Aug 17 01:29:31 2009 +0300 @@ -29,7 +29,7 @@ cython_ext("qmsk.net.py", ["qmsk/net/py.pyx"]), cython_ext("qmsk.net.socket.platform", ["qmsk/net/socket/platform.pyx"]), cython_ext("qmsk.net.socket.constants", ["qmsk/net/socket/constants.pyx"]), - cython_ext("qmsk.net.socket.addr", ["qmsk/net/socket/addr.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"]), diff -r e6b670dbfe3b -r 0e4933d5862e test.py --- a/test.py Mon Aug 17 01:24:28 2009 +0300 +++ b/test.py Mon Aug 17 01:29:31 2009 +0300 @@ -1,11 +1,11 @@ import doctest -import qmsk.net.socket.addr +import qmsk.net.socket.address import qmsk.net.socket.socket import qmsk.net.sctp.sock for mod in ( - qmsk.net.socket.addr, + qmsk.net.socket.address, qmsk.net.socket.socket, qmsk.net.sctp.sock, ) :