modusocket.c 21 KB

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