|
1 """ |
|
2 This C(ython) extension module provides an interface to the libsctp library and associated socket API. |
|
3 |
|
4 >>> from __future__ import absolute_import; |
|
5 >>> from qmsk.net.socket.af_inet import sockaddr_in |
|
6 >>> from qmsk.net.socket.constants import * |
|
7 >>> s = sctp_socket(AF_INET, SOCK_SEQPACKET, IPPROTO_SCTP) |
|
8 >>> s.sctp_bindx([sockaddr_in('127.0.0.1', 1337), sockaddr_in('127.0.0.2')], 0x01) |
|
9 >>> |
|
10 |
|
11 """ |
|
12 |
|
13 from qmsk.net.socket.sctp cimport * |
|
14 from qmsk.net.socket.address cimport sockaddr |
|
15 |
|
16 cimport qmsk.net.socket.platform as platform |
|
17 cimport qmsk.net.libc as libc |
|
18 |
|
19 from qmsk.net.py cimport raise_errno |
|
20 |
|
21 cdef size_t addrsoup_len (object addrs) except -1 : |
|
22 """ |
|
23 Calculate the length of the addr_buf required to store the given addrsoup |
|
24 """ |
|
25 |
|
26 cdef sockaddr addr |
|
27 cdef size_t addr_size = 0 |
|
28 |
|
29 # whoever decided that sctp_bindx takes an array of mixed sockaddr_in/sockaddr_in6's should be shot |
|
30 for addr in addrs : |
|
31 addr_size += addr._get_sockaddr_len() |
|
32 |
|
33 return addr_size |
|
34 |
|
35 cdef addrsoup_store (object addrs, char *addr_buf) : |
|
36 """ |
|
37 Store the sockaddr_*'s for the given addresses into the given buffer, which should be addrsoup_len() bytes long |
|
38 """ |
|
39 |
|
40 cdef sockaddr addr |
|
41 cdef char *addr_ptr = addr_buf |
|
42 |
|
43 # fill it |
|
44 cdef platform.sockaddr *sa |
|
45 cdef platform.socklen_t sa_len |
|
46 |
|
47 for addr in addrs : |
|
48 # get address's sockaddr info |
|
49 addr._get_sockaddr(&sa, &sa_len) |
|
50 |
|
51 # copy to buffer |
|
52 libc.memcpy(addr_ptr, sa, sa_len) |
|
53 |
|
54 # move to next |
|
55 addr_ptr += sa_len |
|
56 |
|
57 cdef class sctp_socket (socket.socket) : |
|
58 |
|
59 def __init__ (self, int family = platform.AF_INET, int socktype = platform.SOCK_SEQPACKET, int protocol = IPPROTO_SCTP, int fd = -1) : |
|
60 """ |
|
61 Same behaviour as socket.__init__, but different defaults. |
|
62 """ |
|
63 |
|
64 socket.socket.__init__(self, family, socktype, protocol, fd) |
|
65 |
|
66 def sctp_bindx (self, object addrs, int flags) : |
|
67 """ |
|
68 Bind this IPPROTO_SCTP socket to the given set of local addresses. |
|
69 |
|
70 This may be called multiple times on a socket, even after bind(), to change the set of local addresses. |
|
71 This may affect ongoing associations, or only new associations. |
|
72 |
|
73 addresses the list of sockaddr's |
|
74 flags one of SCTP_BINDX_ADD/REM_ADDR |
|
75 |
|
76 """ |
|
77 |
|
78 # ensure that addrs stays the same... ? |
|
79 addrs = tuple(addrs) |
|
80 |
|
81 # alloc buffer to hold all the sockaddr_*'s |
|
82 cdef char *addr_buf = <char *> libc.alloca(addrsoup_len(addrs)) |
|
83 |
|
84 # store |
|
85 addrsoup_store(addrs, addr_buf) |
|
86 |
|
87 # then call |
|
88 if sctp_bindx(self.fd, <platform.sockaddr *> addr_buf, len(addrs), flags) : |
|
89 raise_errno('sctp_bindx') |
|
90 |
|
91 def sctp_connectx (self, int sd, object addrs) : |
|
92 """ |
|
93 Establish an association with the given set of remote sockaddr's. |
|
94 |
|
95 addresses the list of sockaddr's |
|
96 |
|
97 """ |
|
98 |
|
99 # ensure that addrs stays the same... ? |
|
100 addrs = tuple(addrs) |
|
101 |
|
102 # alloc buffer to hold all the sockaddr_*'s |
|
103 cdef char *addr_buf = <char *> libc.alloca(addrsoup_len(addrs)) |
|
104 |
|
105 # store |
|
106 addrsoup_store(addrs, addr_buf) |
|
107 |
|
108 # then call |
|
109 if sctp_connectx(self.fd, <platform.sockaddr *> addr_buf, len(addrs)) : |
|
110 raise_errno('sctp_connectx') |
|
111 |
|
112 |