1 from qmsk.net.socket.socket cimport * |
1 from qmsk.net.socket.socket cimport * |
2 from qmsk.net.socket.addr cimport sockaddr, build_sockaddr |
2 from qmsk.net.socket.addr cimport sockaddr, build_sockaddr |
|
3 |
3 cimport qmsk.net.socket.platform as platform |
4 cimport qmsk.net.socket.platform as platform |
4 |
|
5 cimport qmsk.net.libc as libc, qmsk.net.py as py |
5 cimport qmsk.net.libc as libc, qmsk.net.py as py |
6 |
6 |
7 from qmsk.net.py cimport raise_errno |
7 from qmsk.net.py cimport raise_errno |
|
8 |
|
9 cdef parse_sockaddr (platform.sockaddr **sa_ptr, platform.socklen_t *sa_len, sockaddr addr, int optional = 0) : |
|
10 if addr is not None : |
|
11 addr._get_sockaddr(sa_ptr, sa_len) |
|
12 |
|
13 elif optional : |
|
14 sa_ptr[0] = NULL |
|
15 sa_len[0] = 0 |
|
16 |
|
17 else : |
|
18 raise ValueError(addr) |
|
19 |
|
20 cdef parse_buf (void **buf_ptr, size_t *buf_len, object buf, int optional = 0) : |
|
21 cdef libc.ssize_t tmp_len |
|
22 |
|
23 if buf is not None : |
|
24 # XXX: test that except works right |
|
25 py.PyObject_AsCharBuffer(buf, <char **> buf_ptr, &tmp_len) |
|
26 |
|
27 # XXX: ensure that this is >= 0 |
|
28 buf_len[0] = tmp_len |
|
29 |
|
30 elif optional : |
|
31 buf_ptr[0] = NULL |
|
32 buf_len[0] = 0 |
|
33 |
|
34 else : |
|
35 raise ValueError(buf) |
8 |
36 |
9 # XXX: do some GIL-releasin' |
37 # XXX: do some GIL-releasin' |
10 cdef class socket : |
38 cdef class socket : |
11 |
39 |
12 def __init__ (self, int fd = -1) : |
40 def __init__ (self, int fd = -1) : |
42 |
70 |
43 addr - the local address to bind to. The port may be zero to let the system choose an unused |
71 addr - the local address to bind to. The port may be zero to let the system choose an unused |
44 ephemeral port. |
72 ephemeral port. |
45 """ |
73 """ |
46 |
74 |
47 cdef platform.sockaddr *sa_ptr |
75 cdef platform.sockaddr *sa |
48 cdef platform.socklen_t sa_len |
76 cdef platform.socklen_t sa_len |
49 |
77 |
50 # get the address |
78 # XXX: require non-NULL addr? |
51 addr._get_sockaddr(&sa_ptr, &sa_len) |
79 parse_sockaddr(&sa, &sa_len, addr, 1) |
52 |
80 |
53 # bind() |
81 # bind() |
54 if platform.bind(self.fd, sa_ptr, sa_len) : |
82 if platform.bind(self.fd, sa, sa_len) : |
55 raise_errno('bind') |
83 raise_errno('bind') |
56 |
84 |
57 def listen (self, int backlog) : |
85 def listen (self, int backlog) : |
58 """ |
86 """ |
59 Listen for connections, marking this socket as a passive socket, which can accept incoming connection |
87 Listen for connections, marking this socket as a passive socket, which can accept incoming connection |
124 |
152 |
125 def send (self, object buf, int flags = 0) : |
153 def send (self, object buf, int flags = 0) : |
126 """ |
154 """ |
127 Transmit a message to the connected remote endpoint. |
155 Transmit a message to the connected remote endpoint. |
128 |
156 |
129 buf - the data to send |
157 buf - the data to send |
130 flags - MSG_* flags to send with |
158 flags - (optional) MSG_* flags to send with |
131 |
159 |
132 Returns the number of bytes sent, which may be less than the length of buf. |
160 Returns the number of bytes sent, which may be less than the length of buf. |
133 """ |
161 """ |
134 |
162 |
135 cdef char *buf_ptr |
163 cdef void *buf_ptr |
136 cdef libc.ssize_t buf_len, ret |
164 cdef size_t buf_len |
137 |
165 cdef libc.ssize_t ret |
138 # get buffer |
166 |
139 # XXX: test that except works right |
167 parse_buf(&buf_ptr, &buf_len, buf, 0) |
140 py.PyObject_AsCharBuffer(buf, &buf_ptr, &buf_len) |
168 |
141 |
|
142 # send() |
169 # send() |
143 ret = platform.send(self.fd, <void *> buf_ptr, buf_len, flags) |
170 ret = platform.send(self.fd, buf_ptr, buf_len, flags) |
144 |
171 |
145 if ret < 0 : |
172 if ret < 0 : |
146 raise_errno('send') |
173 raise_errno('send') |
147 |
174 |
148 else : |
175 else : |
149 return ret |
176 return ret |
150 |
177 |
|
178 def sendto (self, object buf, int flags = 0, sockaddr addr = None) : |
|
179 """ |
|
180 Transmit a message to the given remote endpoint. If this socket is connected, the addr must not be |
|
181 specified, and this acts like send() |
|
182 |
|
183 buf - the data to send |
|
184 flags - (optional) MSG_* flags to send with |
|
185 addr - (optional) target address |
|
186 |
|
187 Returns the number of bytes sent, which may be less than the length of buf. |
|
188 """ |
|
189 |
|
190 cdef void *buf_ptr |
|
191 cdef size_t buf_len |
|
192 cdef libc.ssize_t ret |
|
193 |
|
194 cdef platform.sockaddr *sa |
|
195 cdef platform.socklen_t sa_len |
|
196 |
|
197 parse_sockaddr(&sa, &sa_len, addr, 1) |
|
198 parse_buf(&buf_ptr, &buf_len, buf, 0) |
|
199 |
|
200 # send() |
|
201 ret = platform.sendto(self.fd, buf_ptr, buf_len, flags, sa, sa_len) |
|
202 |
|
203 if ret < 0 : |
|
204 raise_errno('sendto') |
|
205 |
|
206 else : |
|
207 return ret |
|
208 |
|
209 def sendmsg (self, sockaddr addr = None, iov = None, control = None, int flags = 0) : |
|
210 """ |
|
211 Transmit an extended message to the given remote endpoint (or default for connected sockets) with the given |
|
212 extra parameters. |
|
213 |
|
214 addr - (optional) destination address (struct msghdr::msg_name) |
|
215 iov - (optional) sequence of read-buffers to transmit |
|
216 control - (optional) control message to transmit |
|
217 flags - (optional) MSG_* flags to send with |
|
218 |
|
219 Returns the number of bytes sent, which may be less than the total length of iov. |
|
220 """ |
|
221 |
|
222 cdef libc.ssize_t ret |
|
223 cdef libc.iovec *iovec |
|
224 cdef platform.msghdr msg |
|
225 |
|
226 libc.memset(&msg, 0, sizeof(msg)) |
|
227 |
|
228 parse_sockaddr(<platform.sockaddr **> &msg.msg_name, &msg.msg_namelen, addr, 1) |
|
229 parse_buf(&msg.msg_control, &msg.msg_controllen, control, 1) |
|
230 |
|
231 # iov |
|
232 if iov : |
|
233 iov = tuple(iov) |
|
234 |
|
235 # numerb of bufs = number of iovecs |
|
236 msg.msg_iovlen = len(iov) |
|
237 |
|
238 # alloca the required number of iovec's |
|
239 msg.msg_iov = <libc.iovec *> libc.alloca(msg.msg_iovlen * sizeof(libc.iovec)) |
|
240 |
|
241 # fill in the iovecs |
|
242 for i, buf in enumerate(iov) : |
|
243 iovec = &msg.msg_iov[i] |
|
244 |
|
245 parse_buf(&iovec.iov_base, &iovec.iov_len, buf, 1) |
|
246 |
|
247 # sendmsg() |
|
248 ret = platform.sendmsg(self.fd, &msg, flags) |
|
249 |
|
250 if ret < 0 : |
|
251 raise_errno('sendmsg') |
|
252 |
|
253 else : |
|
254 return ret |
|
255 |
|
256 def write (self, object buf) : |
|
257 """ |
|
258 Write data to socket, mostly equivalent to send() with flags=0. |
|
259 |
|
260 buf - the data to send |
|
261 |
|
262 Returns the number of bytes sent, which may be less than the length of buf. |
|
263 """ |
|
264 |
|
265 cdef void *buf_ptr |
|
266 cdef size_t buf_len |
|
267 cdef libc.ssize_t ret |
|
268 |
|
269 parse_buf(&buf_ptr, &buf_len, buf, 0) |
|
270 |
|
271 # send() |
|
272 ret = libc.write(self.fd, buf_ptr, buf_len) |
|
273 |
|
274 if ret < 0 : |
|
275 raise_errno('write') |
|
276 |
|
277 else : |
|
278 return ret |
|
279 |
|
280 def writev (self, iov) : |
|
281 """ |
|
282 Write data to a socket from multiple read-buffers. |
|
283 |
|
284 iov - sequence of read-buffers to transmit |
|
285 |
|
286 Returns the number of bytes sent, which may be less than the total length of iov. |
|
287 """ |
|
288 |
|
289 # iov |
|
290 cdef libc.iovec *iov_list = NULL |
|
291 cdef size_t iov_count = 0 |
|
292 cdef libc.iovec *iovec |
|
293 |
|
294 iov = tuple(iov) |
|
295 |
|
296 # numerb of bufs = number of iovecs |
|
297 iov_count = len(iov) |
|
298 |
|
299 # alloca the required number of iovec's |
|
300 iov_list = <libc.iovec *> libc.alloca(iov_count * sizeof(libc.iovec)) |
|
301 |
|
302 # fill in the iovecs |
|
303 for i, buf in enumerate(iov) : |
|
304 iovec = &iov_list[i] |
|
305 |
|
306 |
|
307 parse_buf(&iovec.iov_base, &iovec.iov_len, buf, 1) |
|
308 |
|
309 # sendmsg() |
|
310 ret = libc.writev(self.fd, iov_list, iov_count) |
|
311 |
|
312 if ret < 0 : |
|
313 raise_errno('writev') |
|
314 |
|
315 else : |
|
316 return ret |
|
317 |