Branch data Line data Source code
1 : : /*
2 : : * This file is part of the MicroPython project, http://micropython.org/
3 : : *
4 : : * The MIT License (MIT)
5 : : *
6 : : * Copyright (c) 2014-2018 Paul Sokolovsky
7 : : * Copyright (c) 2014-2019 Damien P. George
8 : : *
9 : : * Permission is hereby granted, free of charge, to any person obtaining a copy
10 : : * of this software and associated documentation files (the "Software"), to deal
11 : : * in the Software without restriction, including without limitation the rights
12 : : * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 : : * copies of the Software, and to permit persons to whom the Software is
14 : : * furnished to do so, subject to the following conditions:
15 : : *
16 : : * The above copyright notice and this permission notice shall be included in
17 : : * all copies or substantial portions of the Software.
18 : : *
19 : : * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 : : * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 : : * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 : : * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 : : * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 : : * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 : : * THE SOFTWARE.
26 : : */
27 : :
28 : : #include "py/mpconfig.h"
29 : :
30 : : #if MICROPY_PY_SOCKET
31 : :
32 : : #include <stdio.h>
33 : : #include <assert.h>
34 : : #include <string.h>
35 : : #include <unistd.h>
36 : : #include <fcntl.h>
37 : : #include <sys/stat.h>
38 : : #include <sys/types.h>
39 : : #include <sys/socket.h>
40 : : #include <netinet/in.h>
41 : : #include <arpa/inet.h>
42 : : #include <netdb.h>
43 : : #include <errno.h>
44 : : #include <math.h>
45 : :
46 : : #include "py/objtuple.h"
47 : : #include "py/objstr.h"
48 : : #include "py/runtime.h"
49 : : #include "py/stream.h"
50 : : #include "py/builtin.h"
51 : : #include "py/mphal.h"
52 : : #include "py/mpthread.h"
53 : : #include "extmod/vfs.h"
54 : : #include <poll.h>
55 : :
56 : : /*
57 : : The idea of this module is to implement reasonable minimum of
58 : : socket-related functions to write typical clients and servers.
59 : : It's then possible to make a Python-level module more (or fully)
60 : : compatible with CPython "socket", e.g.:
61 : : ---- socket.py ----
62 : : from socket import *
63 : : from socket_more_funcs import *
64 : : from socket_more_funcs2 import *
65 : : -------------------
66 : : I.e. this module should stay lean, and more functions (if needed)
67 : : should be add to separate modules (C or Python level).
68 : : */
69 : :
70 : : // This type must "inherit" from mp_obj_fdfile_t, i.e. matching subset of
71 : : // fields should have the same layout.
72 : : typedef struct _mp_obj_socket_t {
73 : : mp_obj_base_t base;
74 : : int fd;
75 : : bool blocking;
76 : : } mp_obj_socket_t;
77 : :
78 : : const mp_obj_type_t mp_type_socket;
79 : :
80 : : // Helper functions
81 : 0 : static inline mp_obj_t mp_obj_from_sockaddr(const struct sockaddr *addr, socklen_t len) {
82 : 0 : return mp_obj_new_bytes((const byte *)addr, len);
83 : : }
84 : :
85 : 22 : static mp_obj_socket_t *socket_new(int fd) {
86 : 22 : mp_obj_socket_t *o = mp_obj_malloc(mp_obj_socket_t, &mp_type_socket);
87 : 22 : o->fd = fd;
88 : 22 : o->blocking = true;
89 : 22 : return o;
90 : : }
91 : :
92 : :
93 : 0 : static void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
94 : 0 : (void)kind;
95 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
96 : 0 : mp_printf(print, "<_socket %d>", self->fd);
97 : 0 : }
98 : :
99 : 0 : static mp_uint_t socket_read(mp_obj_t o_in, void *buf, mp_uint_t size, int *errcode) {
100 : 0 : mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in);
101 : 0 : ssize_t r;
102 [ # # # # : 0 : MP_HAL_RETRY_SYSCALL(r, read(o->fd, buf, size), {
# # # # ]
103 : : // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO
104 : : // timed out, and need to convert that to ETIMEDOUT.
105 : : if (err == EAGAIN && o->blocking) {
106 : : err = MP_ETIMEDOUT;
107 : : }
108 : :
109 : : *errcode = err;
110 : : return MP_STREAM_ERROR;
111 : 0 : });
112 : 0 : return (mp_uint_t)r;
113 : : }
114 : :
115 : 0 : static mp_uint_t socket_write(mp_obj_t o_in, const void *buf, mp_uint_t size, int *errcode) {
116 : 0 : mp_obj_socket_t *o = MP_OBJ_TO_PTR(o_in);
117 : 0 : ssize_t r;
118 [ # # # # : 0 : MP_HAL_RETRY_SYSCALL(r, write(o->fd, buf, size), {
# # # # ]
119 : : // On blocking socket, we get EAGAIN in case SO_RCVTIMEO/SO_SNDTIMEO
120 : : // timed out, and need to convert that to ETIMEDOUT.
121 : : if (err == EAGAIN && o->blocking) {
122 : : err = MP_ETIMEDOUT;
123 : : }
124 : :
125 : : *errcode = err;
126 : : return MP_STREAM_ERROR;
127 : 0 : });
128 : 0 : return (mp_uint_t)r;
129 : : }
130 : :
131 : 40 : static mp_uint_t socket_ioctl(mp_obj_t o_in, mp_uint_t request, uintptr_t arg, int *errcode) {
132 : 40 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(o_in);
133 : 40 : (void)arg;
134 [ + + - - ]: 40 : switch (request) {
135 : 16 : case MP_STREAM_CLOSE:
136 : : // There's a POSIX drama regarding return value of close in general,
137 : : // and EINTR error in particular. See e.g.
138 : : // http://lwn.net/Articles/576478/
139 : : // http://austingroupbugs.net/view.php?id=529
140 : : // The rationale MicroPython follows is that close() just releases
141 : : // file descriptor. If you're interested to catch I/O errors before
142 : : // closing fd, fsync() it.
143 : 16 : MP_THREAD_GIL_EXIT();
144 : 16 : close(self->fd);
145 : 16 : MP_THREAD_GIL_ENTER();
146 : 16 : return 0;
147 : :
148 : 24 : case MP_STREAM_GET_FILENO:
149 : 24 : return self->fd;
150 : :
151 : : #if MICROPY_PY_SELECT
152 : 0 : case MP_STREAM_POLL: {
153 : 0 : mp_uint_t ret = 0;
154 : 0 : uint8_t pollevents = 0;
155 [ # # ]: 0 : if (arg & MP_STREAM_POLL_RD) {
156 : 0 : pollevents |= POLLIN;
157 : : }
158 [ # # ]: 0 : if (arg & MP_STREAM_POLL_WR) {
159 : 0 : pollevents |= POLLOUT;
160 : : }
161 : 0 : struct pollfd pfd = { .fd = self->fd, .events = pollevents };
162 [ # # ]: 0 : if (poll(&pfd, 1, 0) > 0) {
163 [ # # ]: 0 : if (pfd.revents & POLLIN) {
164 : 0 : ret |= MP_STREAM_POLL_RD;
165 : : }
166 [ # # ]: 0 : if (pfd.revents & POLLOUT) {
167 : 0 : ret |= MP_STREAM_POLL_WR;
168 : : }
169 [ # # ]: 0 : if (pfd.revents & POLLERR) {
170 : 0 : ret |= MP_STREAM_POLL_ERR;
171 : : }
172 [ # # ]: 0 : if (pfd.revents & POLLHUP) {
173 : 0 : ret |= MP_STREAM_POLL_HUP;
174 : : }
175 [ # # ]: 0 : if (pfd.revents & POLLNVAL) {
176 : 0 : ret |= MP_STREAM_POLL_NVAL;
177 : : }
178 : : }
179 : 0 : return ret;
180 : : }
181 : : #endif
182 : :
183 : 0 : default:
184 : 0 : *errcode = MP_EINVAL;
185 : 0 : return MP_STREAM_ERROR;
186 : : }
187 : : }
188 : :
189 : 0 : static mp_obj_t socket_fileno(mp_obj_t self_in) {
190 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
191 : 0 : return MP_OBJ_NEW_SMALL_INT(self->fd);
192 : : }
193 : : static MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno);
194 : :
195 : 0 : static mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
196 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
197 : 0 : mp_buffer_info_t bufinfo;
198 : 0 : mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ);
199 : :
200 : : // special case of PEP 475 to retry only if blocking so we can't use
201 : : // MP_HAL_RETRY_SYSCALL() here
202 : 0 : for (;;) {
203 : 0 : MP_THREAD_GIL_EXIT();
204 : 0 : int r = connect(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len);
205 : 0 : MP_THREAD_GIL_ENTER();
206 [ # # ]: 0 : if (r == -1) {
207 : 0 : int err = errno;
208 [ # # ]: 0 : if (self->blocking) {
209 [ # # ]: 0 : if (err == EINTR) {
210 : 0 : mp_handle_pending(true);
211 : 0 : continue;
212 : : }
213 : : // EINPROGRESS on a blocking socket means the operation timed out
214 [ # # ]: 0 : if (err == EINPROGRESS) {
215 : 0 : err = MP_ETIMEDOUT;
216 : : }
217 : : }
218 : 0 : mp_raise_OSError(err);
219 : : }
220 : 0 : return mp_const_none;
221 : : }
222 : : }
223 : : static MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
224 : :
225 : 12 : static mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
226 : 12 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
227 : 12 : mp_buffer_info_t bufinfo;
228 : 12 : mp_get_buffer_raise(addr_in, &bufinfo, MP_BUFFER_READ);
229 : 12 : MP_THREAD_GIL_EXIT();
230 : 12 : int r = bind(self->fd, (const struct sockaddr *)bufinfo.buf, bufinfo.len);
231 : 12 : MP_THREAD_GIL_ENTER();
232 [ - + ]: 12 : RAISE_ERRNO(r, errno);
233 : 12 : return mp_const_none;
234 : : }
235 : : static MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
236 : :
237 : : // method socket.listen([backlog])
238 : 0 : static mp_obj_t socket_listen(size_t n_args, const mp_obj_t *args) {
239 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
240 : :
241 : 0 : int backlog = MICROPY_PY_SOCKET_LISTEN_BACKLOG_DEFAULT;
242 [ # # ]: 0 : if (n_args > 1) {
243 : 0 : backlog = (int)mp_obj_get_int(args[1]);
244 : 0 : backlog = (backlog < 0) ? 0 : backlog;
245 : : }
246 : :
247 : 0 : MP_THREAD_GIL_EXIT();
248 : 0 : int r = listen(self->fd, backlog);
249 : 0 : MP_THREAD_GIL_ENTER();
250 [ # # ]: 0 : RAISE_ERRNO(r, errno);
251 : 0 : return mp_const_none;
252 : : }
253 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_listen_obj, 1, 2, socket_listen);
254 : :
255 : 0 : static mp_obj_t socket_accept(mp_obj_t self_in) {
256 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
257 : : // sockaddr_storage isn't stack-friendly (129 bytes or so)
258 : : // struct sockaddr_storage addr;
259 : 0 : byte addr[32];
260 : 0 : socklen_t addr_len = sizeof(addr);
261 : 0 : int fd;
262 [ # # # # : 0 : MP_HAL_RETRY_SYSCALL(fd, accept(self->fd, (struct sockaddr *)&addr, &addr_len), {
# # # # ]
263 : : // EAGAIN on a blocking socket means the operation timed out
264 : : if (self->blocking && err == EAGAIN) {
265 : : err = MP_ETIMEDOUT;
266 : : }
267 : : mp_raise_OSError(err);
268 : 0 : });
269 : :
270 : 0 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
271 : 0 : t->items[0] = MP_OBJ_FROM_PTR(socket_new(fd));
272 : 0 : t->items[1] = mp_obj_new_bytearray(addr_len, &addr);
273 : :
274 : 0 : return MP_OBJ_FROM_PTR(t);
275 : : }
276 : : static MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
277 : :
278 : : // Note: besides flag param, this differs from read() in that
279 : : // this does not swallow blocking errors (EAGAIN, EWOULDBLOCK) -
280 : : // these would be thrown as exceptions.
281 : 4 : static mp_obj_t socket_recv(size_t n_args, const mp_obj_t *args) {
282 : 4 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
283 : 4 : int sz = MP_OBJ_SMALL_INT_VALUE(args[1]);
284 : 4 : int flags = 0;
285 : :
286 [ - + ]: 4 : if (n_args > 2) {
287 : 0 : flags = MP_OBJ_SMALL_INT_VALUE(args[2]);
288 : : }
289 : :
290 : 4 : byte *buf = m_new(byte, sz);
291 : 4 : ssize_t out_sz;
292 [ + - - + ]: 4 : MP_HAL_RETRY_SYSCALL(out_sz, recv(self->fd, buf, sz, flags), mp_raise_OSError(err));
293 : 0 : mp_obj_t ret = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz);
294 : 0 : m_del(char, buf, sz);
295 : 0 : return ret;
296 : : }
297 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recv_obj, 2, 3, socket_recv);
298 : :
299 : 0 : static mp_obj_t socket_recvfrom(size_t n_args, const mp_obj_t *args) {
300 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
301 : 0 : int sz = MP_OBJ_SMALL_INT_VALUE(args[1]);
302 : 0 : int flags = 0;
303 : :
304 [ # # ]: 0 : if (n_args > 2) {
305 : 0 : flags = MP_OBJ_SMALL_INT_VALUE(args[2]);
306 : : }
307 : :
308 : 0 : struct sockaddr_storage addr;
309 : 0 : socklen_t addr_len = sizeof(addr);
310 : :
311 : 0 : byte *buf = m_new(byte, sz);
312 : 0 : ssize_t out_sz;
313 [ # # # # ]: 0 : MP_HAL_RETRY_SYSCALL(out_sz, recvfrom(self->fd, buf, sz, flags, (struct sockaddr *)&addr, &addr_len),
314 : 0 : mp_raise_OSError(err));
315 : 0 : mp_obj_t buf_o = mp_obj_new_str_of_type(&mp_type_bytes, buf, out_sz);
316 : 0 : m_del(char, buf, sz);
317 : :
318 : 0 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
319 : 0 : t->items[0] = buf_o;
320 : 0 : t->items[1] = mp_obj_from_sockaddr((struct sockaddr *)&addr, addr_len);
321 : :
322 : 0 : return MP_OBJ_FROM_PTR(t);
323 : : }
324 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_recvfrom_obj, 2, 3, socket_recvfrom);
325 : :
326 : : // Note: besides flag param, this differs from write() in that
327 : : // this does not swallow blocking errors (EAGAIN, EWOULDBLOCK) -
328 : : // these would be thrown as exceptions.
329 : 0 : static mp_obj_t socket_send(size_t n_args, const mp_obj_t *args) {
330 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
331 : 0 : int flags = 0;
332 : :
333 [ # # ]: 0 : if (n_args > 2) {
334 : 0 : flags = MP_OBJ_SMALL_INT_VALUE(args[2]);
335 : : }
336 : :
337 : 0 : mp_buffer_info_t bufinfo;
338 : 0 : mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
339 : 0 : ssize_t out_sz;
340 [ # # # # ]: 0 : MP_HAL_RETRY_SYSCALL(out_sz, send(self->fd, bufinfo.buf, bufinfo.len, flags),
341 : 0 : mp_raise_OSError(err));
342 : 0 : return MP_OBJ_NEW_SMALL_INT(out_sz);
343 : : }
344 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_send_obj, 2, 3, socket_send);
345 : :
346 : 0 : static mp_obj_t socket_sendto(size_t n_args, const mp_obj_t *args) {
347 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
348 : 0 : int flags = 0;
349 : :
350 : 0 : mp_obj_t dst_addr = args[2];
351 [ # # ]: 0 : if (n_args > 3) {
352 : 0 : flags = MP_OBJ_SMALL_INT_VALUE(args[2]);
353 : 0 : dst_addr = args[3];
354 : : }
355 : :
356 : 0 : mp_buffer_info_t bufinfo, addr_bi;
357 : 0 : mp_get_buffer_raise(args[1], &bufinfo, MP_BUFFER_READ);
358 : 0 : mp_get_buffer_raise(dst_addr, &addr_bi, MP_BUFFER_READ);
359 : 0 : ssize_t out_sz;
360 [ # # # # ]: 0 : MP_HAL_RETRY_SYSCALL(out_sz, sendto(self->fd, bufinfo.buf, bufinfo.len, flags,
361 : 0 : (struct sockaddr *)addr_bi.buf, addr_bi.len), mp_raise_OSError(err));
362 : 0 : return MP_OBJ_NEW_SMALL_INT(out_sz);
363 : : }
364 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_sendto_obj, 3, 4, socket_sendto);
365 : :
366 : 0 : static mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
367 : 0 : (void)n_args; // always 4
368 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
369 : 0 : int level = MP_OBJ_SMALL_INT_VALUE(args[1]);
370 : 0 : int option = mp_obj_get_int(args[2]);
371 : :
372 : 0 : const void *optval;
373 : 0 : socklen_t optlen;
374 : 0 : int val;
375 [ # # # # : 0 : if (mp_obj_is_int(args[3])) {
# # ]
376 : 0 : val = mp_obj_int_get_truncated(args[3]);
377 : 0 : optval = &val;
378 : 0 : optlen = sizeof(val);
379 : : } else {
380 : 0 : mp_buffer_info_t bufinfo;
381 : 0 : mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
382 : 0 : optval = bufinfo.buf;
383 : 0 : optlen = bufinfo.len;
384 : : }
385 : 0 : MP_THREAD_GIL_EXIT();
386 : 0 : int r = setsockopt(self->fd, level, option, optval, optlen);
387 : 0 : MP_THREAD_GIL_ENTER();
388 [ # # ]: 0 : RAISE_ERRNO(r, errno);
389 : 0 : return mp_const_none;
390 : : }
391 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
392 : :
393 : 2 : static mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t flag_in) {
394 : 2 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
395 : 2 : int val = mp_obj_is_true(flag_in);
396 : 2 : MP_THREAD_GIL_EXIT();
397 : 2 : int flags = fcntl(self->fd, F_GETFL, 0);
398 [ - + ]: 2 : if (flags == -1) {
399 : 0 : MP_THREAD_GIL_ENTER();
400 : 0 : RAISE_ERRNO(flags, errno);
401 : : }
402 [ - + ]: 2 : if (val) {
403 : 0 : flags &= ~O_NONBLOCK;
404 : : } else {
405 : 2 : flags |= O_NONBLOCK;
406 : : }
407 : 2 : flags = fcntl(self->fd, F_SETFL, flags);
408 : 2 : MP_THREAD_GIL_ENTER();
409 [ - + ]: 2 : RAISE_ERRNO(flags, errno);
410 : 2 : self->blocking = val;
411 : 2 : return mp_const_none;
412 : : }
413 : : static MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
414 : :
415 : 2 : static mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) {
416 : 2 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(self_in);
417 : 2 : struct timeval tv = {0, };
418 : 2 : bool new_blocking = true;
419 : :
420 : : // Timeout of None means no timeout, which in POSIX is signified with 0 timeout,
421 : : // and that's how 'tv' is initialized above
422 [ + - ]: 2 : if (timeout_in != mp_const_none) {
423 : : #if MICROPY_PY_BUILTINS_FLOAT
424 : 2 : mp_float_t val = mp_obj_get_float(timeout_in);
425 : 2 : mp_float_t ipart;
426 : 2 : tv.tv_usec = (time_t)MICROPY_FLOAT_C_FUN(round)(MICROPY_FLOAT_C_FUN(modf)(val, &ipart) * MICROPY_FLOAT_CONST(1000000.));
427 : 2 : tv.tv_sec = (suseconds_t)ipart;
428 : : #else
429 : : tv.tv_sec = mp_obj_get_int(timeout_in);
430 : : #endif
431 : :
432 : : // For SO_RCVTIMEO/SO_SNDTIMEO, zero timeout means infinity, but
433 : : // for Python API it means non-blocking.
434 [ + - + - ]: 2 : if (tv.tv_sec == 0 && tv.tv_usec == 0) {
435 : 2 : new_blocking = false;
436 : : }
437 : : }
438 : :
439 : 2 : if (new_blocking) {
440 : 0 : int r;
441 : 0 : MP_THREAD_GIL_EXIT();
442 : 0 : r = setsockopt(self->fd, SOL_SOCKET, SO_RCVTIMEO, &tv, sizeof(struct timeval));
443 [ # # ]: 0 : if (r == -1) {
444 : 0 : MP_THREAD_GIL_ENTER();
445 : 0 : RAISE_ERRNO(r, errno);
446 : : }
447 : 0 : r = setsockopt(self->fd, SOL_SOCKET, SO_SNDTIMEO, &tv, sizeof(struct timeval));
448 : 0 : MP_THREAD_GIL_ENTER();
449 [ # # ]: 0 : RAISE_ERRNO(r, errno);
450 : : }
451 : :
452 [ + - ]: 2 : if (self->blocking != new_blocking) {
453 [ + - ]: 4 : socket_setblocking(self_in, mp_obj_new_bool(new_blocking));
454 : : }
455 : :
456 : 2 : return mp_const_none;
457 : : }
458 : : static MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
459 : :
460 : 0 : static mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
461 : : // TODO: CPython explicitly says that closing returned object doesn't close
462 : : // the original socket (Python2 at all says that fd is dup()ed). But we
463 : : // save on the bloat.
464 : 0 : mp_obj_socket_t *self = MP_OBJ_TO_PTR(args[0]);
465 : 0 : mp_obj_t *new_args = alloca(n_args * sizeof(mp_obj_t));
466 : 0 : memcpy(new_args + 1, args + 1, (n_args - 1) * sizeof(mp_obj_t));
467 : 0 : new_args[0] = MP_OBJ_NEW_SMALL_INT(self->fd);
468 : 0 : return mp_vfs_open(n_args, new_args, (mp_map_t *)&mp_const_empty_map);
469 : : }
470 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
471 : :
472 : 22 : static mp_obj_t socket_make_new(const mp_obj_type_t *type_in, size_t n_args, size_t n_kw, const mp_obj_t *args) {
473 : 22 : (void)type_in;
474 : 22 : (void)n_kw;
475 : :
476 : 22 : int family = AF_INET;
477 : 22 : int type = SOCK_STREAM;
478 : 22 : int proto = 0;
479 : :
480 [ + + ]: 22 : if (n_args > 0) {
481 [ - + ]: 14 : assert(mp_obj_is_small_int(args[0]));
482 : 14 : family = MP_OBJ_SMALL_INT_VALUE(args[0]);
483 [ + - ]: 14 : if (n_args > 1) {
484 [ - + ]: 14 : assert(mp_obj_is_small_int(args[1]));
485 : 14 : type = MP_OBJ_SMALL_INT_VALUE(args[1]);
486 [ - + ]: 14 : if (n_args > 2) {
487 [ # # ]: 0 : assert(mp_obj_is_small_int(args[2]));
488 : 0 : proto = MP_OBJ_SMALL_INT_VALUE(args[2]);
489 : : }
490 : : }
491 : : }
492 : :
493 : 22 : MP_THREAD_GIL_EXIT();
494 : 22 : int fd = socket(family, type, proto);
495 : 22 : MP_THREAD_GIL_ENTER();
496 [ - + ]: 22 : RAISE_ERRNO(fd, errno);
497 : 22 : return MP_OBJ_FROM_PTR(socket_new(fd));
498 : : }
499 : :
500 : : static const mp_rom_map_elem_t socket_locals_dict_table[] = {
501 : : { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) },
502 : : { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
503 : : { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
504 : : { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
505 : : { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
506 : : { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
507 : : { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
508 : : { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
509 : : { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
510 : : { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
511 : : { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
512 : : { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
513 : : { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
514 : : { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
515 : : { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
516 : : { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
517 : : { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
518 : : { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
519 : : };
520 : :
521 : : static MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
522 : :
523 : : static const mp_stream_p_t socket_stream_p = {
524 : : .read = socket_read,
525 : : .write = socket_write,
526 : : .ioctl = socket_ioctl,
527 : : };
528 : :
529 : : MP_DEFINE_CONST_OBJ_TYPE(
530 : : mp_type_socket,
531 : : MP_QSTR_socket,
532 : : MP_TYPE_FLAG_NONE,
533 : : make_new, socket_make_new,
534 : : print, socket_print,
535 : : protocol, &socket_stream_p,
536 : : locals_dict, &socket_locals_dict
537 : : );
538 : :
539 : : #define BINADDR_MAX_LEN sizeof(struct in6_addr)
540 : 0 : static mp_obj_t mod_socket_inet_pton(mp_obj_t family_in, mp_obj_t addr_in) {
541 : 0 : int family = mp_obj_get_int(family_in);
542 : 0 : byte binaddr[BINADDR_MAX_LEN];
543 : 0 : int r = inet_pton(family, mp_obj_str_get_str(addr_in), binaddr);
544 [ # # ]: 0 : RAISE_ERRNO(r, errno);
545 [ # # ]: 0 : if (r == 0) {
546 : 0 : mp_raise_OSError(MP_EINVAL);
547 : : }
548 : 0 : int binaddr_len = 0;
549 [ # # # ]: 0 : switch (family) {
550 : 0 : case AF_INET:
551 : 0 : binaddr_len = sizeof(struct in_addr);
552 : 0 : break;
553 : 0 : case AF_INET6:
554 : 0 : binaddr_len = sizeof(struct in6_addr);
555 : 0 : break;
556 : : }
557 : 0 : return mp_obj_new_bytes(binaddr, binaddr_len);
558 : : }
559 : : static MP_DEFINE_CONST_FUN_OBJ_2(mod_socket_inet_pton_obj, mod_socket_inet_pton);
560 : :
561 : 0 : static mp_obj_t mod_socket_inet_ntop(mp_obj_t family_in, mp_obj_t binaddr_in) {
562 : 0 : int family = mp_obj_get_int(family_in);
563 : 0 : mp_buffer_info_t bufinfo;
564 : 0 : mp_get_buffer_raise(binaddr_in, &bufinfo, MP_BUFFER_READ);
565 : 0 : vstr_t vstr;
566 [ # # ]: 0 : vstr_init_len(&vstr, family == AF_INET ? INET_ADDRSTRLEN : INET6_ADDRSTRLEN);
567 [ # # ]: 0 : if (inet_ntop(family, bufinfo.buf, vstr.buf, vstr.len) == NULL) {
568 : 0 : mp_raise_OSError(errno);
569 : : }
570 : 0 : vstr.len = strlen(vstr.buf);
571 : 0 : return mp_obj_new_str_from_utf8_vstr(&vstr);
572 : : }
573 : : static MP_DEFINE_CONST_FUN_OBJ_2(mod_socket_inet_ntop_obj, mod_socket_inet_ntop);
574 : :
575 : 12 : static mp_obj_t mod_socket_getaddrinfo(size_t n_args, const mp_obj_t *args) {
576 : :
577 : 12 : const char *host = mp_obj_str_get_str(args[0]);
578 : 12 : const char *serv = NULL;
579 : 12 : struct addrinfo hints;
580 : 12 : char buf[6];
581 : 12 : memset(&hints, 0, sizeof(hints));
582 : : // getaddrinfo accepts port in string notation, so however
583 : : // it may seem stupid, we need to convert int to str
584 [ + - ]: 12 : if (mp_obj_is_small_int(args[1])) {
585 : 12 : unsigned port = (unsigned short)MP_OBJ_SMALL_INT_VALUE(args[1]);
586 : 12 : snprintf(buf, sizeof(buf), "%u", port);
587 : 12 : serv = buf;
588 : 12 : hints.ai_flags = AI_NUMERICSERV;
589 : : #ifdef __UCLIBC_MAJOR__
590 : : #if __UCLIBC_MAJOR__ == 0 && (__UCLIBC_MINOR__ < 9 || (__UCLIBC_MINOR__ == 9 && __UCLIBC_SUBLEVEL__ <= 32))
591 : : // "warning" requires -Wno-cpp which is a relatively new gcc option, so we choose not to use it.
592 : : // #warning Working around uClibc bug with numeric service name
593 : : // Older versions og uClibc have bugs when numeric ports in service
594 : : // arg require also hints.ai_socktype (or hints.ai_protocol) != 0
595 : : // This actually was fixed in 0.9.32.1, but uClibc doesn't allow to
596 : : // test for that.
597 : : // http://git.uclibc.org/uClibc/commit/libc/inet/getaddrinfo.c?id=bc3be18145e4d5
598 : : // Note that this is crude workaround, precluding UDP socket addresses
599 : : // to be returned. TODO: set only if not set by Python args.
600 : : hints.ai_socktype = SOCK_STREAM;
601 : : #endif
602 : : #endif
603 : : } else {
604 : 0 : serv = mp_obj_str_get_str(args[1]);
605 : : }
606 : :
607 [ - + ]: 12 : if (n_args > 2) {
608 : 0 : hints.ai_family = MP_OBJ_SMALL_INT_VALUE(args[2]);
609 [ # # ]: 0 : if (n_args > 3) {
610 : 0 : hints.ai_socktype = MP_OBJ_SMALL_INT_VALUE(args[3]);
611 [ # # ]: 0 : if (n_args > 4) {
612 : 0 : hints.ai_protocol = MP_OBJ_SMALL_INT_VALUE(args[4]);
613 [ # # ]: 0 : if (n_args > 5) {
614 : 0 : hints.ai_flags = MP_OBJ_SMALL_INT_VALUE(args[5]);
615 : : }
616 : : }
617 : : }
618 : : }
619 : :
620 : 12 : struct addrinfo *addr_list;
621 : 12 : MP_THREAD_GIL_EXIT();
622 : 12 : int res = getaddrinfo(host, serv, &hints, &addr_list);
623 : 12 : MP_THREAD_GIL_ENTER();
624 : :
625 [ - + ]: 12 : if (res != 0) {
626 : : // CPython: socket.gaierror
627 : 0 : mp_raise_msg_varg(&mp_type_OSError, MP_ERROR_TEXT("[addrinfo error %d]"), res);
628 : : }
629 [ - + ]: 12 : assert(addr_list);
630 : :
631 : 12 : mp_obj_t list = mp_obj_new_list(0, NULL);
632 [ + + ]: 48 : for (struct addrinfo *addr = addr_list; addr; addr = addr->ai_next) {
633 : 36 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
634 : 36 : t->items[0] = MP_OBJ_NEW_SMALL_INT(addr->ai_family);
635 : 36 : t->items[1] = MP_OBJ_NEW_SMALL_INT(addr->ai_socktype);
636 : 36 : t->items[2] = MP_OBJ_NEW_SMALL_INT(addr->ai_protocol);
637 : : // "canonname will be a string representing the canonical name of the host
638 : : // if AI_CANONNAME is part of the flags argument; else canonname will be empty." ??
639 [ - + ]: 36 : if (addr->ai_canonname) {
640 : 0 : t->items[3] = MP_OBJ_NEW_QSTR(qstr_from_str(addr->ai_canonname));
641 : : } else {
642 : 36 : t->items[3] = mp_const_none;
643 : : }
644 : 36 : t->items[4] = mp_obj_new_bytearray(addr->ai_addrlen, addr->ai_addr);
645 : 36 : mp_obj_list_append(list, MP_OBJ_FROM_PTR(t));
646 : : }
647 : 12 : freeaddrinfo(addr_list);
648 : 12 : return list;
649 : : }
650 : : static MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_socket_getaddrinfo_obj, 2, 6, mod_socket_getaddrinfo);
651 : :
652 : 0 : static mp_obj_t mod_socket_sockaddr(mp_obj_t sockaddr_in) {
653 : 0 : mp_buffer_info_t bufinfo;
654 : 0 : mp_get_buffer_raise(sockaddr_in, &bufinfo, MP_BUFFER_READ);
655 [ # # # ]: 0 : switch (((struct sockaddr *)bufinfo.buf)->sa_family) {
656 : 0 : case AF_INET: {
657 : 0 : struct sockaddr_in *sa = (struct sockaddr_in *)bufinfo.buf;
658 : 0 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(3, NULL));
659 : 0 : t->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET);
660 : 0 : t->items[1] = mp_obj_new_bytes((byte *)&sa->sin_addr, sizeof(sa->sin_addr));
661 : 0 : t->items[2] = MP_OBJ_NEW_SMALL_INT(ntohs(sa->sin_port));
662 : 0 : return MP_OBJ_FROM_PTR(t);
663 : : }
664 : 0 : case AF_INET6: {
665 : 0 : struct sockaddr_in6 *sa = (struct sockaddr_in6 *)bufinfo.buf;
666 : 0 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(5, NULL));
667 : 0 : t->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET6);
668 : 0 : t->items[1] = mp_obj_new_bytes((byte *)&sa->sin6_addr, sizeof(sa->sin6_addr));
669 : 0 : t->items[2] = MP_OBJ_NEW_SMALL_INT(ntohs(sa->sin6_port));
670 : 0 : t->items[3] = MP_OBJ_NEW_SMALL_INT(ntohl(sa->sin6_flowinfo));
671 : 0 : t->items[4] = MP_OBJ_NEW_SMALL_INT(ntohl(sa->sin6_scope_id));
672 : 0 : return MP_OBJ_FROM_PTR(t);
673 : : }
674 : 0 : default: {
675 : 0 : struct sockaddr *sa = (struct sockaddr *)bufinfo.buf;
676 : 0 : mp_obj_tuple_t *t = MP_OBJ_TO_PTR(mp_obj_new_tuple(2, NULL));
677 : 0 : t->items[0] = MP_OBJ_NEW_SMALL_INT(sa->sa_family);
678 : 0 : t->items[1] = mp_obj_new_bytes((byte *)sa->sa_data, bufinfo.len - offsetof(struct sockaddr, sa_data));
679 : 0 : return MP_OBJ_FROM_PTR(t);
680 : : }
681 : : }
682 : : return mp_const_none;
683 : : }
684 : : static MP_DEFINE_CONST_FUN_OBJ_1(mod_socket_sockaddr_obj, mod_socket_sockaddr);
685 : :
686 : : static const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
687 : : { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_socket) },
688 : : { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&mp_type_socket) },
689 : : { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_socket_getaddrinfo_obj) },
690 : : { MP_ROM_QSTR(MP_QSTR_inet_pton), MP_ROM_PTR(&mod_socket_inet_pton_obj) },
691 : : { MP_ROM_QSTR(MP_QSTR_inet_ntop), MP_ROM_PTR(&mod_socket_inet_ntop_obj) },
692 : : { MP_ROM_QSTR(MP_QSTR_sockaddr), MP_ROM_PTR(&mod_socket_sockaddr_obj) },
693 : :
694 : : #define C(name) { MP_ROM_QSTR(MP_QSTR_##name), MP_ROM_INT(name) }
695 : : C(AF_UNIX),
696 : : C(AF_INET),
697 : : C(AF_INET6),
698 : : C(SOCK_STREAM),
699 : : C(SOCK_DGRAM),
700 : : C(SOCK_RAW),
701 : :
702 : : C(MSG_DONTROUTE),
703 : : C(MSG_DONTWAIT),
704 : :
705 : : C(SOL_SOCKET),
706 : : C(SO_BROADCAST),
707 : : C(SO_ERROR),
708 : : C(SO_KEEPALIVE),
709 : : C(SO_LINGER),
710 : : C(SO_REUSEADDR),
711 : : #undef C
712 : : };
713 : :
714 : : static MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
715 : :
716 : : const mp_obj_module_t mp_module_socket = {
717 : : .base = { &mp_type_module },
718 : : .globals = (mp_obj_dict_t *)&mp_module_socket_globals,
719 : : };
720 : :
721 : : MP_REGISTER_EXTENSIBLE_MODULE(MP_QSTR_socket, mp_module_socket);
722 : :
723 : : #endif // MICROPY_PY_SOCKET
|