|
1 """ |
|
2 Socket addresses at various levels: |
|
3 |
|
4 sockaddr - specific network-level address for socket operations |
|
5 addrinfo - information on a specific sockaddr including its socket parameters |
|
6 endpoint - human-readable network address, corresponding to multiple sockaddr's |
|
7 """ |
|
8 |
|
9 cimport qmsk.net.libc as libc |
|
10 |
|
11 cimport qmsk.net.socket.platform as platform |
|
12 |
|
13 cdef class sockaddr : |
|
14 """ |
|
15 A network-level socket address |
|
16 |
|
17 XXX: rename to 'address' |
|
18 |
|
19 >>> sockaddr().family |
|
20 0 |
|
21 >>> sockaddr().port |
|
22 Traceback (most recent call last): |
|
23 ... |
|
24 NotImplementedError |
|
25 >>> sockaddr().getnameinfo() |
|
26 Traceback (most recent call last): |
|
27 ... |
|
28 NotImplementedError |
|
29 """ |
|
30 |
|
31 # address family |
|
32 # XXX: this should be a class constant! It's part of our type safety! |
|
33 cdef readonly platform.sa_family_t family |
|
34 |
|
35 cdef void _init_family (self, platform.sa_family_t family = ?) |
|
36 |
|
37 # get the sockaddr/socklen |
|
38 # each of these can be NULL to ignore it |
|
39 cdef int _get_sockaddr (self, platform.sockaddr **sa_ptr, platform.socklen_t *sa_len) except -1 |
|
40 |
|
41 cdef platform.sockaddr* _get_sockaddr_ptr (self) except NULL |
|
42 cdef platform.socklen_t _get_sockaddr_len (self) except -1 |
|
43 |
|
44 # set the sockaddr, socklen must match |
|
45 cdef int _set_sockaddr (self, platform.sockaddr *sa, size_t sa_len) except -1 |
|
46 |
|
47 # build a sockaddr from the given sockaddr struct, based on sa_family |
|
48 cdef sockaddr build_sockaddr (platform.sockaddr *sa, size_t sa_len) |
|
49 |
|
50 cdef class addrinfo : |
|
51 """ |
|
52 A socket-level endpoint address, which contains the full socket parameters and an bind/connect address |
|
53 """ |
|
54 |
|
55 # cdef readonly int flags |
|
56 cdef readonly int family, socktype, protocol |
|
57 cdef readonly sockaddr addr |
|
58 cdef readonly object canonname |
|
59 |
|
60 cdef _init_addrinfo (self, platform.addrinfo *c_ai) |
|
61 |
|
62 # build and return a new addrinfo instance |
|
63 cdef addrinfo build_addrinfo (platform.addrinfo *c_ai) |
|
64 |
|
65 cdef class endpoint : |
|
66 """ |
|
67 A network-level socket endpoint. This is the level that humans mostly work with, but the tricky bit is that |
|
68 an endpoint can map to more than one sockaddr... |
|
69 |
|
70 Hence, endpoints are stored as human-readable hostname/service strings, which are then translated to sockaddrs |
|
71 using getaddrinfo. |
|
72 |
|
73 >>> from __future__ import absolute_import; import socket as _socket |
|
74 >>> e = endpoint('127.0.0.1', 80) |
|
75 >>> str(e) |
|
76 'hostname=127.0.0.1, service=80' |
|
77 >>> res = e.getaddrinfo(_socket.AF_UNSPEC, _socket.SOCK_STREAM) |
|
78 >>> len(res) |
|
79 1 |
|
80 >>> str(res[0]) |
|
81 'family=2, socktype=1, protocol=6, addr=127.0.0.1:80, canonname=None' |
|
82 >>> e = endpoint('2001::5', 80) |
|
83 >>> str(e) |
|
84 'hostname=2001::5, service=80' |
|
85 >>> res = e.getaddrinfo(_socket.AF_UNSPEC, _socket.SOCK_STREAM) |
|
86 >>> len(res) |
|
87 1 |
|
88 >>> str(res[0]) |
|
89 'family=10, socktype=1, protocol=6, addr=[2001::5]:80, canonname=None' |
|
90 |
|
91 """ |
|
92 |
|
93 # our defining attributes, set via __init__ |
|
94 cdef object hostname, service |
|
95 |
|
96 cpdef getaddrinfo (self, int family, int socktype, int protocol = ?, int flags = ?) |
|
97 |