modusocket.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600
  1. /*
  2. * This file is part of the MicroPython project, http://micropython.org/
  3. *
  4. * The MIT License (MIT)
  5. *
  6. * Copyright (c) 2018 Armink (armink.ztl@gmail.com)
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy
  9. * of this software and associated documentation files (the "Software"), to deal
  10. * in the Software without restriction, including without limitation the rights
  11. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  12. * copies of the Software, and to permit persons to whom the Software is
  13. * furnished to do so, subject to the following conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in
  16. * all copies or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  23. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  24. * THE SOFTWARE.
  25. */
  26. #include "py/mpconfig.h"
  27. #if MICROPY_PY_USOCKET
  28. #include <stdio.h>
  29. #include <string.h>
  30. #include <stdio.h>
  31. #include <netdb.h>
  32. #include <sys/socket.h>
  33. #include <fcntl.h>
  34. #include <sys/time.h>
  35. #include <sys/select.h>
  36. #include <errno.h>
  37. #include "py/objtuple.h"
  38. #include "py/objlist.h"
  39. #include "py/runtime.h"
  40. #include "py/mperrno.h"
  41. #include "py/stream.h"
  42. #include "py/objstr.h"
  43. #include "py/builtin.h"
  44. #include "lib/netutils/netutils.h"
  45. #include "modnetwork.h"
  46. #define SOCKET_POLL_US (100000)
  47. // socket class
  48. typedef struct _socket_obj_t {
  49. mp_obj_base_t base;
  50. int fd;
  51. uint8_t domain;
  52. uint8_t type;
  53. uint8_t proto;
  54. bool peer_closed;
  55. unsigned int retries;
  56. } socket_obj_t;
  57. STATIC const mp_obj_type_t socket_type;
  58. STATIC void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms);
  59. NORETURN static void exception_from_errno(int _errno) {
  60. // Here we need to convert from lwip errno values to MicroPython's standard ones
  61. if (_errno == EINPROGRESS) {
  62. _errno = MP_EINPROGRESS;
  63. }
  64. mp_raise_OSError(_errno);
  65. }
  66. static inline void check_for_exceptions(void) {
  67. mp_handle_pending(true);
  68. }
  69. static int _socket_getaddrinfo2(const mp_obj_t host, const mp_obj_t portx, struct addrinfo **resp) {
  70. const struct addrinfo hints = {
  71. .ai_family = AF_INET,
  72. .ai_socktype = SOCK_STREAM,
  73. };
  74. mp_obj_t port = portx;
  75. if (MP_OBJ_IS_SMALL_INT(port)) {
  76. // This is perverse, because lwip_getaddrinfo promptly converts it back to an int, but
  77. // that's the API we have to work with ...
  78. port = mp_obj_str_binary_op(MP_BINARY_OP_MODULO, mp_obj_new_str_via_qstr("%s", 2), port);
  79. }
  80. const char *host_str = mp_obj_str_get_str(host);
  81. const char *port_str = mp_obj_str_get_str(port);
  82. if (host_str[0] == '\0') {
  83. // a host of "" is equivalent to the default/all-local IP address
  84. host_str = "0.0.0.0";
  85. }
  86. MP_THREAD_GIL_EXIT();
  87. int res = getaddrinfo(host_str, port_str, &hints, resp);
  88. MP_THREAD_GIL_ENTER();
  89. return res;
  90. }
  91. int _socket_getaddrinfo(const mp_obj_t addrtuple, struct addrinfo **resp) {
  92. mp_uint_t len = 0;
  93. mp_obj_t *elem;
  94. mp_obj_get_array(addrtuple, &len, &elem);
  95. if (len != 2) return -1;
  96. return _socket_getaddrinfo2(elem[0], elem[1], resp);
  97. }
  98. STATIC mp_obj_t socket_bind(const mp_obj_t arg0, const mp_obj_t arg1) {
  99. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  100. struct addrinfo *res;
  101. _socket_getaddrinfo(arg1, &res);
  102. int r = bind(self->fd, res->ai_addr, res->ai_addrlen);
  103. freeaddrinfo(res);
  104. if (r < 0) exception_from_errno(errno);
  105. return mp_const_none;
  106. }
  107. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
  108. STATIC mp_obj_t socket_listen(const mp_obj_t arg0, const mp_obj_t arg1) {
  109. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  110. int backlog = mp_obj_get_int(arg1);
  111. int r = listen(self->fd, backlog);
  112. if (r < 0) exception_from_errno(errno);
  113. return mp_const_none;
  114. }
  115. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen);
  116. STATIC mp_obj_t socket_accept(const mp_obj_t arg0) {
  117. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  118. struct sockaddr addr;
  119. socklen_t addr_len = sizeof(addr);
  120. int new_fd = -1;
  121. for (int i = 0; i <= self->retries; i++) {
  122. MP_THREAD_GIL_EXIT();
  123. new_fd = accept(self->fd, &addr, &addr_len);
  124. MP_THREAD_GIL_ENTER();
  125. if (new_fd >= 0) break;
  126. // if (errno != EAGAIN) exception_from_errno(errno);
  127. check_for_exceptions();
  128. }
  129. if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT);
  130. // create new socket object
  131. socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);
  132. sock->base.type = self->base.type;
  133. sock->fd = new_fd;
  134. sock->domain = self->domain;
  135. sock->type = self->type;
  136. sock->proto = self->proto;
  137. sock->peer_closed = false;
  138. _socket_settimeout(sock, UINT64_MAX);
  139. // make the return value
  140. uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr;
  141. mp_uint_t port = ntohs(((struct sockaddr_in*)&addr)->sin_port);
  142. mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL);
  143. client->items[0] = sock;
  144. client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
  145. return client;
  146. }
  147. STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept);
  148. STATIC mp_obj_t socket_connect(const mp_obj_t arg0, const mp_obj_t arg1) {
  149. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  150. struct addrinfo *res;
  151. _socket_getaddrinfo(arg1, &res);
  152. MP_THREAD_GIL_EXIT();
  153. int r = connect(self->fd, res->ai_addr, res->ai_addrlen);
  154. MP_THREAD_GIL_ENTER();
  155. freeaddrinfo(res);
  156. if (r != 0) {
  157. exception_from_errno(errno);
  158. }
  159. return mp_const_none;
  160. }
  161. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
  162. STATIC mp_obj_t socket_setsockopt(size_t n_args, const mp_obj_t *args) {
  163. (void)n_args; // always 4
  164. socket_obj_t *self = MP_OBJ_TO_PTR(args[0]);
  165. int opt = mp_obj_get_int(args[2]);
  166. switch (opt) {
  167. // level: SOL_SOCKET
  168. case SO_REUSEADDR: {
  169. int val = mp_obj_get_int(args[3]);
  170. int ret = setsockopt(self->fd, SOL_SOCKET, opt, &val, sizeof(int));
  171. if (ret != 0) {
  172. exception_from_errno(errno);
  173. }
  174. break;
  175. }
  176. // level: IPPROTO_IP
  177. case IP_ADD_MEMBERSHIP: {
  178. mp_buffer_info_t bufinfo;
  179. mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ);
  180. if (bufinfo.len != sizeof(ip4_addr_t) * 2) {
  181. mp_raise_ValueError(NULL);
  182. }
  183. // // POSIX setsockopt has order: group addr, if addr, lwIP has it vice-versa
  184. // err_t err = igmp_joingroup((const ip4_addr_t*)bufinfo.buf + 1, bufinfo.buf);
  185. // if (err != ERR_OK) {
  186. // mp_raise_OSError(-err);
  187. // }
  188. break;
  189. }
  190. default:
  191. mp_printf(&mp_plat_print, "Warning: setsockopt() option not implemented\n");
  192. }
  193. return mp_const_none;
  194. }
  195. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt);
  196. STATIC void _socket_settimeout(socket_obj_t *sock, uint64_t timeout_ms) {
  197. // Rather than waiting for the entire timeout specified, we wait sock->retries times
  198. // for SOCKET_POLL_US each, checking for a MicroPython interrupt between timeouts.
  199. // with SOCKET_POLL_MS == 100ms, sock->retries allows for timeouts up to 13 years.
  200. // if timeout_ms == UINT64_MAX, wait forever.
  201. sock->retries = (timeout_ms == UINT64_MAX) ? UINT_MAX : timeout_ms * 1000 / SOCKET_POLL_US;
  202. struct timeval timeout = {
  203. .tv_sec = 0,
  204. .tv_usec = timeout_ms ? SOCKET_POLL_US : 0
  205. };
  206. setsockopt(sock->fd, SOL_SOCKET, SO_SNDTIMEO, (const void *)&timeout, sizeof(timeout));
  207. setsockopt(sock->fd, SOL_SOCKET, SO_RCVTIMEO, (const void *)&timeout, sizeof(timeout));
  208. fcntl(sock->fd, F_SETFL, timeout_ms ? 0 : O_NONBLOCK);
  209. }
  210. STATIC mp_obj_t socket_settimeout(const mp_obj_t arg0, const mp_obj_t arg1) {
  211. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  212. if (arg1 == mp_const_none) _socket_settimeout(self, UINT64_MAX);
  213. else _socket_settimeout(self, mp_obj_get_float(arg1) * 1000L);
  214. return mp_const_none;
  215. }
  216. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout);
  217. STATIC mp_obj_t socket_setblocking(const mp_obj_t arg0, const mp_obj_t arg1) {
  218. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  219. if (mp_obj_is_true(arg1)) _socket_settimeout(self, UINT64_MAX);
  220. else _socket_settimeout(self, 0);
  221. return mp_const_none;
  222. }
  223. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking);
  224. // XXX this can end up waiting a very long time if the content is dribbled in one character
  225. // at a time, as the timeout resets each time a recvfrom succeeds ... this is probably not
  226. // good behaviour.
  227. STATIC mp_uint_t _socket_read_data(mp_obj_t self_in, void *buf, size_t size,
  228. struct sockaddr *from, socklen_t *from_len, int *errcode) {
  229. socket_obj_t *sock = MP_OBJ_TO_PTR(self_in);
  230. // If the peer closed the connection then the lwIP socket API will only return "0" once
  231. // from lwip_recvfrom_r and then block on subsequent calls. To emulate POSIX behaviour,
  232. // which continues to return "0" for each call on a closed socket, we set a flag when
  233. // the peer closed the socket.
  234. if (sock->peer_closed) {
  235. return 0;
  236. }
  237. // XXX Would be nicer to use RTC to handle timeouts
  238. for (int i = 0; i <= sock->retries; ++i) {
  239. MP_THREAD_GIL_EXIT();
  240. int r = recvfrom(sock->fd, buf, size, 0, from, from_len);
  241. MP_THREAD_GIL_ENTER();
  242. if (r == 0) {
  243. sock->peer_closed = true;
  244. }
  245. if (r >= 0) {
  246. return r;
  247. }
  248. // if (errno != EWOULDBLOCK) {
  249. // *errcode = errno;
  250. // return MP_STREAM_ERROR;
  251. // }
  252. check_for_exceptions();
  253. }
  254. *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
  255. return MP_STREAM_ERROR;
  256. }
  257. mp_obj_t _socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in,
  258. struct sockaddr *from, socklen_t *from_len) {
  259. size_t len = mp_obj_get_int(len_in);
  260. vstr_t vstr;
  261. vstr_init_len(&vstr, len);
  262. int errcode;
  263. mp_uint_t ret = _socket_read_data(self_in, vstr.buf, len, from, from_len, &errcode);
  264. if (ret == MP_STREAM_ERROR) {
  265. exception_from_errno(errcode);
  266. }
  267. vstr.len = ret;
  268. return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
  269. }
  270. STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
  271. return _socket_recvfrom(self_in, len_in, NULL, NULL);
  272. }
  273. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
  274. STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
  275. struct sockaddr from;
  276. socklen_t fromlen = sizeof(from);
  277. mp_obj_t tuple[2];
  278. tuple[0] = _socket_recvfrom(self_in, len_in, &from, &fromlen);
  279. uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&from)->sin_addr;
  280. mp_uint_t port = ntohs(((struct sockaddr_in*)&from)->sin_port);
  281. tuple[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG);
  282. return mp_obj_new_tuple(2, tuple);
  283. }
  284. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom);
  285. STATIC int _socket_send(socket_obj_t *sock, const char *data, size_t datalen) {
  286. int sentlen = 0;
  287. for (int i = 0; i <= sock->retries && sentlen < datalen; i++) {
  288. MP_THREAD_GIL_EXIT();
  289. int r = send(sock->fd, data + sentlen, datalen - sentlen, 0);
  290. MP_THREAD_GIL_ENTER();
  291. if (r < 0 && errno != EWOULDBLOCK) exception_from_errno(errno);
  292. if (r > 0) sentlen += r;
  293. check_for_exceptions();
  294. }
  295. if (sentlen == 0) mp_raise_OSError(MP_ETIMEDOUT);
  296. return sentlen;
  297. }
  298. STATIC mp_obj_t socket_send(const mp_obj_t arg0, const mp_obj_t arg1) {
  299. socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);
  300. mp_uint_t datalen;
  301. const char *data = mp_obj_str_get_data(arg1, &datalen);
  302. int r = _socket_send(sock, data, datalen);
  303. return mp_obj_new_int(r);
  304. }
  305. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
  306. STATIC mp_obj_t socket_sendall(const mp_obj_t arg0, const mp_obj_t arg1) {
  307. // XXX behaviour when nonblocking (see extmod/modlwip.c)
  308. // XXX also timeout behaviour.
  309. socket_obj_t *sock = MP_OBJ_TO_PTR(arg0);
  310. mp_buffer_info_t bufinfo;
  311. mp_get_buffer_raise(arg1, &bufinfo, MP_BUFFER_READ);
  312. int r = _socket_send(sock, bufinfo.buf, bufinfo.len);
  313. if (r < bufinfo.len) mp_raise_OSError(MP_ETIMEDOUT);
  314. return mp_const_none;
  315. }
  316. STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_sendall_obj, socket_sendall);
  317. STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) {
  318. socket_obj_t *self = MP_OBJ_TO_PTR(self_in);
  319. // get the buffer to send
  320. mp_buffer_info_t bufinfo;
  321. mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ);
  322. // create the destination address
  323. struct sockaddr_in to;
  324. to.sin_len = sizeof(to);
  325. to.sin_family = AF_INET;
  326. to.sin_port = htons(netutils_parse_inet_addr(addr_in, (uint8_t*)&to.sin_addr, NETUTILS_BIG));
  327. // send the data
  328. for (int i=0; i<=self->retries; i++) {
  329. MP_THREAD_GIL_EXIT();
  330. int ret = sendto(self->fd, bufinfo.buf, bufinfo.len, 0, (struct sockaddr*)&to, sizeof(to));
  331. MP_THREAD_GIL_ENTER();
  332. if (ret > 0) return mp_obj_new_int_from_uint(ret);
  333. if (ret == -1 && errno != EWOULDBLOCK) {
  334. exception_from_errno(errno);
  335. }
  336. check_for_exceptions();
  337. }
  338. mp_raise_OSError(MP_ETIMEDOUT);
  339. }
  340. STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto);
  341. STATIC mp_obj_t socket_fileno(const mp_obj_t arg0) {
  342. socket_obj_t *self = MP_OBJ_TO_PTR(arg0);
  343. return mp_obj_new_int(self->fd);
  344. }
  345. STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_fileno_obj, socket_fileno);
  346. STATIC mp_obj_t socket_makefile(size_t n_args, const mp_obj_t *args) {
  347. (void)n_args;
  348. return args[0];
  349. }
  350. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_makefile_obj, 1, 3, socket_makefile);
  351. STATIC mp_uint_t socket_stream_read(mp_obj_t self_in, void *buf, mp_uint_t size, int *errcode) {
  352. return _socket_read_data(self_in, buf, size, NULL, NULL, errcode);
  353. }
  354. STATIC mp_uint_t socket_stream_write(mp_obj_t self_in, const void *buf, mp_uint_t size, int *errcode) {
  355. socket_obj_t *sock = self_in;
  356. for (int i = 0; i <= sock->retries; i++) {
  357. MP_THREAD_GIL_EXIT();
  358. int r = send(sock->fd, buf, size, 0);
  359. MP_THREAD_GIL_ENTER();
  360. if (r > 0) return r;
  361. if (r < 0 && errno != EWOULDBLOCK) { *errcode = errno; return MP_STREAM_ERROR; }
  362. check_for_exceptions();
  363. }
  364. *errcode = sock->retries == 0 ? MP_EWOULDBLOCK : MP_ETIMEDOUT;
  365. return MP_STREAM_ERROR;
  366. }
  367. STATIC mp_uint_t socket_stream_ioctl(mp_obj_t self_in, mp_uint_t request, uintptr_t arg, int *errcode) {
  368. socket_obj_t * socket = self_in;
  369. if (request == MP_STREAM_POLL) {
  370. fd_set rfds; FD_ZERO(&rfds);
  371. fd_set wfds; FD_ZERO(&wfds);
  372. fd_set efds; FD_ZERO(&efds);
  373. struct timeval timeout = { .tv_sec = 0, .tv_usec = 0 };
  374. if (arg & MP_STREAM_POLL_RD) FD_SET(socket->fd, &rfds);
  375. if (arg & MP_STREAM_POLL_WR) FD_SET(socket->fd, &wfds);
  376. if (arg & MP_STREAM_POLL_HUP) FD_SET(socket->fd, &efds);
  377. MP_THREAD_GIL_EXIT();
  378. int r = select((socket->fd)+1, &rfds, &wfds, &efds, &timeout);
  379. MP_THREAD_GIL_ENTER();
  380. if (r < 0) {
  381. *errcode = MP_EIO;
  382. return MP_STREAM_ERROR;
  383. }
  384. mp_uint_t ret = 0;
  385. if (FD_ISSET(socket->fd, &rfds)) ret |= MP_STREAM_POLL_RD;
  386. if (FD_ISSET(socket->fd, &wfds)) ret |= MP_STREAM_POLL_WR;
  387. if (FD_ISSET(socket->fd, &efds)) ret |= MP_STREAM_POLL_HUP;
  388. return ret;
  389. } else if (request == MP_STREAM_CLOSE) {
  390. if (socket->fd >= 0) {
  391. int ret = closesocket(socket->fd);
  392. if (ret != 0) {
  393. *errcode = errno;
  394. return MP_STREAM_ERROR;
  395. }
  396. socket->fd = -1;
  397. }
  398. return 0;
  399. }
  400. *errcode = MP_EINVAL;
  401. return MP_STREAM_ERROR;
  402. }
  403. STATIC const mp_rom_map_elem_t socket_locals_dict_table[] = {
  404. { MP_ROM_QSTR(MP_QSTR___del__), MP_ROM_PTR(&mp_stream_close_obj) },
  405. { MP_ROM_QSTR(MP_QSTR_close), MP_ROM_PTR(&mp_stream_close_obj) },
  406. { MP_ROM_QSTR(MP_QSTR_bind), MP_ROM_PTR(&socket_bind_obj) },
  407. { MP_ROM_QSTR(MP_QSTR_listen), MP_ROM_PTR(&socket_listen_obj) },
  408. { MP_ROM_QSTR(MP_QSTR_accept), MP_ROM_PTR(&socket_accept_obj) },
  409. { MP_ROM_QSTR(MP_QSTR_connect), MP_ROM_PTR(&socket_connect_obj) },
  410. { MP_ROM_QSTR(MP_QSTR_send), MP_ROM_PTR(&socket_send_obj) },
  411. { MP_ROM_QSTR(MP_QSTR_sendall), MP_ROM_PTR(&socket_sendall_obj) },
  412. { MP_ROM_QSTR(MP_QSTR_sendto), MP_ROM_PTR(&socket_sendto_obj) },
  413. { MP_ROM_QSTR(MP_QSTR_recv), MP_ROM_PTR(&socket_recv_obj) },
  414. { MP_ROM_QSTR(MP_QSTR_recvfrom), MP_ROM_PTR(&socket_recvfrom_obj) },
  415. { MP_ROM_QSTR(MP_QSTR_setsockopt), MP_ROM_PTR(&socket_setsockopt_obj) },
  416. { MP_ROM_QSTR(MP_QSTR_settimeout), MP_ROM_PTR(&socket_settimeout_obj) },
  417. { MP_ROM_QSTR(MP_QSTR_setblocking), MP_ROM_PTR(&socket_setblocking_obj) },
  418. { MP_ROM_QSTR(MP_QSTR_makefile), MP_ROM_PTR(&socket_makefile_obj) },
  419. { MP_ROM_QSTR(MP_QSTR_fileno), MP_ROM_PTR(&socket_fileno_obj) },
  420. { MP_ROM_QSTR(MP_QSTR_read), MP_ROM_PTR(&mp_stream_read_obj) },
  421. { MP_ROM_QSTR(MP_QSTR_readinto), MP_ROM_PTR(&mp_stream_readinto_obj) },
  422. { MP_ROM_QSTR(MP_QSTR_readline), MP_ROM_PTR(&mp_stream_unbuffered_readline_obj) },
  423. { MP_ROM_QSTR(MP_QSTR_write), MP_ROM_PTR(&mp_stream_write_obj) },
  424. };
  425. STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
  426. STATIC const mp_stream_p_t socket_stream_p = {
  427. .read = socket_stream_read,
  428. .write = socket_stream_write,
  429. .ioctl = socket_stream_ioctl
  430. };
  431. STATIC const mp_obj_type_t socket_type = {
  432. { &mp_type_type },
  433. .name = MP_QSTR_socket,
  434. .protocol = &socket_stream_p,
  435. .locals_dict = (mp_obj_t)&socket_locals_dict,
  436. };
  437. STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) {
  438. socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t);
  439. sock->base.type = &socket_type;
  440. sock->domain = AF_INET;
  441. sock->type = SOCK_STREAM;
  442. sock->proto = 0;
  443. sock->peer_closed = false;
  444. if (n_args > 0) {
  445. sock->domain = mp_obj_get_int(args[0]);
  446. if (n_args > 1) {
  447. sock->type = mp_obj_get_int(args[1]);
  448. if (n_args > 2) {
  449. sock->proto = mp_obj_get_int(args[2]);
  450. }
  451. }
  452. }
  453. sock->fd = socket(sock->domain, sock->type, sock->proto);
  454. if (sock->fd < 0) {
  455. exception_from_errno(errno);
  456. }
  457. _socket_settimeout(sock, UINT64_MAX);
  458. return MP_OBJ_FROM_PTR(sock);
  459. }
  460. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(get_socket_obj, 0, 3, get_socket);
  461. /******************************************************************************/
  462. // usocket module
  463. // function usocket.getaddrinfo(host, port)
  464. STATIC mp_obj_t mod_usocket_getaddrinfo(uint n_args, const mp_obj_t *arg) {
  465. // TODO support additional args beyond the first two
  466. size_t hlen;
  467. int ret;
  468. const char *host = mp_obj_str_get_data(arg[0], &hlen);
  469. mp_int_t port = mp_obj_get_int(arg[1]);
  470. struct addrinfo hint, *res = NULL;
  471. memset(&hint, 0, sizeof(hint));
  472. MP_THREAD_GIL_EXIT();
  473. ret = getaddrinfo(host, NULL, &hint, &res);
  474. MP_THREAD_GIL_ENTER();
  475. if (ret != 0) {
  476. mp_printf(&mp_plat_print, "getaddrinfo err: %d '%s'\n", ret, host);
  477. nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, "no available netif"));
  478. }
  479. mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL);
  480. tuple->items[0] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_AF_INET);
  481. tuple->items[1] = MP_OBJ_NEW_SMALL_INT(MOD_NETWORK_SOCK_STREAM);
  482. tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0);
  483. tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_);
  484. mp_obj_t tuple_addr[2] = {
  485. tuple_addr[0] = netutils_format_ipv4_addr((uint8_t *)((res->ai_addr->sa_data) + 2), NETUTILS_BIG),
  486. tuple_addr[1] = mp_obj_new_int(port),
  487. };
  488. tuple->items[4] = mp_obj_new_tuple(2, tuple_addr);
  489. freeaddrinfo(res);
  490. return mp_obj_new_list(1, (mp_obj_t*) &tuple);
  491. }
  492. STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(mod_usocket_getaddrinfo_obj, 2, 6, mod_usocket_getaddrinfo);
  493. STATIC const mp_rom_map_elem_t mp_module_socket_globals_table[] = {
  494. { MP_ROM_QSTR(MP_QSTR___name__), MP_ROM_QSTR(MP_QSTR_usocket) },
  495. { MP_ROM_QSTR(MP_QSTR_socket), MP_ROM_PTR(&get_socket_obj) },
  496. { MP_ROM_QSTR(MP_QSTR_getaddrinfo), MP_ROM_PTR(&mod_usocket_getaddrinfo_obj) },
  497. { MP_ROM_QSTR(MP_QSTR_AF_INET), MP_ROM_INT(AF_INET) },
  498. { MP_ROM_QSTR(MP_QSTR_AF_INET6), MP_ROM_INT(AF_INET6) },
  499. { MP_ROM_QSTR(MP_QSTR_SOCK_STREAM), MP_ROM_INT(SOCK_STREAM) },
  500. { MP_ROM_QSTR(MP_QSTR_SOCK_DGRAM), MP_ROM_INT(SOCK_DGRAM) },
  501. { MP_ROM_QSTR(MP_QSTR_SOCK_RAW), MP_ROM_INT(SOCK_RAW) },
  502. { MP_ROM_QSTR(MP_QSTR_IPPROTO_TCP), MP_ROM_INT(IPPROTO_TCP) },
  503. { MP_ROM_QSTR(MP_QSTR_IPPROTO_UDP), MP_ROM_INT(IPPROTO_UDP) },
  504. { MP_ROM_QSTR(MP_QSTR_IPPROTO_IP), MP_ROM_INT(IPPROTO_IP) },
  505. { MP_ROM_QSTR(MP_QSTR_SOL_SOCKET), MP_ROM_INT(SOL_SOCKET) },
  506. { MP_ROM_QSTR(MP_QSTR_SO_REUSEADDR), MP_ROM_INT(SO_REUSEADDR) },
  507. { MP_ROM_QSTR(MP_QSTR_IP_ADD_MEMBERSHIP), MP_ROM_INT(IP_ADD_MEMBERSHIP) },
  508. };
  509. STATIC MP_DEFINE_CONST_DICT(mp_module_socket_globals, mp_module_socket_globals_table);
  510. const mp_obj_module_t mp_module_usocket = {
  511. .base = { &mp_type_module },
  512. .globals = (mp_obj_dict_t*)&mp_module_socket_globals,
  513. };
  514. #endif // MICROPY_PY_USOCKET