diff options
Diffstat (limited to 'cc3200/mods/modusocket.c')
| -rw-r--r-- | cc3200/mods/modusocket.c | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/cc3200/mods/modusocket.c b/cc3200/mods/modusocket.c new file mode 100644 index 000000000..7356942f2 --- /dev/null +++ b/cc3200/mods/modusocket.c @@ -0,0 +1,451 @@ +/* + * This file is part of the Micro Python project, http://micropython.org/ + * + * The MIT License (MIT) + * + * Copyright (c) 2013, 2014 Damien P. George + * Copyright (c) 2015 Daniel Campora + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include <std.h> +#include <stdint.h> +#include <string.h> + +#include "simplelink.h" +#include "mpconfig.h" +#include MICROPY_HAL_H +#include "nlr.h" +#include "misc.h" +#include "qstr.h" +#include "obj.h" +#include "objtuple.h" +#include "objlist.h" +#include "runtime.h" +#include "modnetwork.h" +#include "mpexception.h" +#include "mpstate.h" + +/******************************************************************************/ +// socket class + +STATIC const mp_obj_type_t socket_type; + +// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None) +STATIC mp_obj_t socket_make_new(mp_obj_t type_in, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { + mp_arg_check_num(n_args, n_kw, 0, 4, false); + + // create socket object (not bound to any NIC yet) + mod_network_socket_obj_t *s = m_new_obj_with_finaliser(mod_network_socket_obj_t); + s->base.type = (mp_obj_t)&socket_type; + s->nic = MP_OBJ_NULL; + s->nic_type = NULL; + s->u_param.domain = AF_INET; + s->u_param.type = SOCK_STREAM; + s->u_param.proto = IPPROTO_TCP; + s->u_param.fileno = -1; + if (n_args >= 1) { + s->u_param.domain = mp_obj_get_int(args[0]); + if (n_args >= 2) { + s->u_param.type = mp_obj_get_int(args[1]); + if (n_args >= 3) { + s->u_param.proto = mp_obj_get_int(args[2]); + if (n_args == 4) { + s->u_param.fileno = mp_obj_get_int(args[3]); + } + } + } + } + return s; +} + +STATIC void socket_select_nic(mod_network_socket_obj_t *self, const byte *ip) { + if (self->nic == MP_OBJ_NULL) { + // select NIC based on IP + self->nic = mod_network_find_nic(ip); + self->nic_type = (mod_network_nic_type_t*)mp_obj_get_type(self->nic); + + // call the NIC to open the socket + int _errno; + if (self->nic_type->socket(self, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + } +} +// method socket.close() +STATIC mp_obj_t socket_close(mp_obj_t self_in) { + mod_network_socket_obj_t *self = self_in; + if (self->nic != MP_OBJ_NULL) { + self->nic_type->close(self); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_close_obj, socket_close); + +// method socket.bind(address) +STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to bind the socket + int _errno; + if (self->nic_type->bind(self, ip, port, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind); + +// method socket.listen(backlog) +STATIC mp_obj_t socket_listen(mp_obj_t self_in, mp_obj_t backlog) { + mod_network_socket_obj_t *self = self_in; + + if (self->nic == MP_OBJ_NULL) { + // not connected + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + } + + int _errno; + if (self->nic_type->listen(self, mp_obj_get_int(backlog), &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_listen_obj, socket_listen); + +// method socket.accept() +STATIC mp_obj_t socket_accept(mp_obj_t self_in) { + mod_network_socket_obj_t *self = self_in; + + // create new socket object + // starts with empty NIC so that finaliser doesn't run close() method if accept() fails + mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); + socket2->base.type = (mp_obj_t)&socket_type; + socket2->nic = MP_OBJ_NULL; + socket2->nic_type = NULL; + + // accept incoming connection + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port; + int _errno; + if (self->nic_type->accept(self, socket2, ip, &port, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + // new socket has valid state, so set the NIC to the same as parent + socket2->nic = self->nic; + socket2->nic_type = self->nic_type; + + // make the return value + mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); + client->items[0] = socket2; + client->items[1] = mod_network_format_inet_addr(ip, port); + + return client; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_1(socket_accept_obj, socket_accept); + +// method socket.connect(address) +STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to connect the socket + int _errno; + if (self->nic_type->connect(self, ip, port, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect); + +// method socket.send(bytes) +STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) { + mod_network_socket_obj_t *self = self_in; + if (self->nic == MP_OBJ_NULL) { + // not connected + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); + } + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(buf_in, &bufinfo, MP_BUFFER_READ); + int _errno; + mp_uint_t ret = self->nic_type->send(self, bufinfo.buf, bufinfo.len, &_errno); + if (ret == -1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + return mp_obj_new_int_from_uint(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send); + +// method socket.recv(bufsize) +STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = self_in; + if (self->nic == MP_OBJ_NULL) { + // not connected + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + } + mp_int_t len = mp_obj_get_int(len_in); + vstr_t vstr; + vstr_init_len(&vstr, len); + int _errno; + mp_uint_t ret = self->nic_type->recv(self, (byte*)vstr.buf, len, &_errno); + if (ret == -1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + if (ret == 0) { + return mp_const_empty_bytes; + } + vstr.len = ret; + vstr.buf[vstr.len] = '\0'; + return mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv); + +// method socket.sendto(bytes, address) +STATIC mp_obj_t socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t addr_in) { + mod_network_socket_obj_t *self = self_in; + + // get the data + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(data_in, &bufinfo, MP_BUFFER_READ); + + // get address + uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + mp_uint_t port = mod_network_parse_inet_addr(addr_in, ip); + + // check if we need to select a NIC + socket_select_nic(self, ip); + + // call the NIC to sendto + int _errno; + mp_int_t ret = self->nic_type->sendto(self, bufinfo.buf, bufinfo.len, ip, port, &_errno); + if (ret == -1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + return mp_obj_new_int(ret); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_3(socket_sendto_obj, socket_sendto); + +// method socket.recvfrom(bufsize) +STATIC mp_obj_t socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) { + mod_network_socket_obj_t *self = self_in; + if (self->nic == MP_OBJ_NULL) { + // not connected + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + } + vstr_t vstr; + vstr_init_len(&vstr, mp_obj_get_int(len_in)); + byte ip[4]; + mp_uint_t port; + int _errno; + mp_int_t ret = self->nic_type->recvfrom(self, (byte*)vstr.buf, vstr.len, ip, &port, &_errno); + if (ret == -1) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + mp_obj_t tuple[2]; + if (ret == 0) { + tuple[0] = mp_const_empty_bytes; + } else { + vstr.len = ret; + vstr.buf[vstr.len] = '\0'; + tuple[0] = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr); + } + tuple[1] = mod_network_format_inet_addr(ip, port); + return mp_obj_new_tuple(2, tuple); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recvfrom_obj, socket_recvfrom); + +// method socket.setsockopt(level, optname, value) +STATIC mp_obj_t socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) { + mod_network_socket_obj_t *self = args[0]; + + mp_int_t level = mp_obj_get_int(args[1]); + mp_int_t opt = mp_obj_get_int(args[2]); + + const void *optval; + mp_uint_t optlen; + mp_int_t val; + if (mp_obj_is_integer(args[3])) { + val = mp_obj_int_get_truncated(args[3]); + optval = &val; + optlen = sizeof(val); + } else { + mp_buffer_info_t bufinfo; + mp_get_buffer_raise(args[3], &bufinfo, MP_BUFFER_READ); + optval = bufinfo.buf; + optlen = bufinfo.len; + } + + int _errno; + if (self->nic_type->setsockopt(self, level, opt, optval, optlen, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_VAR_BETWEEN(socket_setsockopt_obj, 4, 4, socket_setsockopt); + +// method socket.settimeout(value) +// timeout=0 means non-blocking +// timeout=None means blocking +// otherwise, timeout is in seconds +STATIC mp_obj_t socket_settimeout(mp_obj_t self_in, mp_obj_t timeout_in) { + mod_network_socket_obj_t *self = self_in; + if (self->nic == MP_OBJ_NULL) { + // not connected + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOTCONN))); + } + mp_uint_t timeout; + if (timeout_in == mp_const_none) { + timeout = -1; + } else { + timeout = 1000 * mp_obj_get_int(timeout_in); + } + int _errno; + if (self->nic_type->settimeout(self, timeout, &_errno) != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); + } + return mp_const_none; +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_settimeout_obj, socket_settimeout); + +// method socket.setblocking(flag) +STATIC mp_obj_t socket_setblocking(mp_obj_t self_in, mp_obj_t blocking) { + if (mp_obj_is_true(blocking)) { + return socket_settimeout(self_in, mp_const_none); + } else { + return socket_settimeout(self_in, MP_OBJ_NEW_SMALL_INT(0)); + } +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_setblocking_obj, socket_setblocking); + +STATIC const mp_map_elem_t socket_locals_dict_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___del__), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_close), (mp_obj_t)&socket_close_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_listen), (mp_obj_t)&socket_listen_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_accept), (mp_obj_t)&socket_accept_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_sendto), (mp_obj_t)&socket_sendto_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_recvfrom), (mp_obj_t)&socket_recvfrom_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_setsockopt), (mp_obj_t)&socket_setsockopt_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_settimeout), (mp_obj_t)&socket_settimeout_obj }, + { MP_OBJ_NEW_QSTR(MP_QSTR_setblocking), (mp_obj_t)&socket_setblocking_obj }, +}; + +STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table); + +mp_uint_t socket_ioctl(mp_obj_t self_in, mp_uint_t request, mp_uint_t arg, int *errcode) { + mod_network_socket_obj_t *self = self_in; + return self->nic_type->ioctl(self, request, arg, errcode); +} + +STATIC const mp_stream_p_t socket_stream_p = { + .ioctl = socket_ioctl, + .is_text = false, +}; + +STATIC const mp_obj_type_t socket_type = { + { &mp_type_type }, + .name = MP_QSTR_socket, + .make_new = socket_make_new, + .stream_p = &socket_stream_p, + .locals_dict = (mp_obj_t)&socket_locals_dict, +}; + +/******************************************************************************/ +// usocket module + +// function usocket.getaddrinfo(host, port) +/// \function getaddrinfo(host, port) +STATIC mp_obj_t mod_usocket_getaddrinfo(mp_obj_t host_in, mp_obj_t port_in) { + mp_uint_t hlen; + const char *host = mp_obj_str_get_data(host_in, &hlen); + mp_int_t port = mp_obj_get_int(port_in); + + // find a NIC that can do a name lookup + for (mp_uint_t i = 0; i < MP_STATE_PORT(mod_network_nic_list).len; i++) { + mp_obj_t nic = MP_STATE_PORT(mod_network_nic_list).items[i]; + mod_network_nic_type_t *nic_type = (mod_network_nic_type_t*)mp_obj_get_type(nic); + if (nic_type->gethostbyname != NULL) { + // Only IPv4 is supported + uint8_t out_ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; + int32_t result = nic_type->gethostbyname(nic, host, hlen, out_ip, AF_INET); + if (result != 0) { + nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(result))); + } + mp_obj_tuple_t *tuple = mp_obj_new_tuple(5, NULL); + tuple->items[0] = MP_OBJ_NEW_SMALL_INT(AF_INET); + tuple->items[1] = MP_OBJ_NEW_SMALL_INT(SOCK_STREAM); + tuple->items[2] = MP_OBJ_NEW_SMALL_INT(0); + tuple->items[3] = MP_OBJ_NEW_QSTR(MP_QSTR_); + tuple->items[4] = mod_network_format_inet_addr(out_ip, port); + return mp_obj_new_list(1, (mp_obj_t*)&tuple); + } + } + + nlr_raise(mp_obj_new_exception_msg(&mp_type_OSError, mpexception_os_resource_not_avaliable)); +} +STATIC MP_DEFINE_CONST_FUN_OBJ_2(mod_usocket_getaddrinfo_obj, mod_usocket_getaddrinfo); + +STATIC const mp_map_elem_t mp_module_usocket_globals_table[] = { + { MP_OBJ_NEW_QSTR(MP_QSTR___name__), MP_OBJ_NEW_QSTR(MP_QSTR_usocket) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_socket), (mp_obj_t)&socket_type }, + { MP_OBJ_NEW_QSTR(MP_QSTR_getaddrinfo), (mp_obj_t)&mod_usocket_getaddrinfo_obj }, + + // class constants + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET), MP_OBJ_NEW_SMALL_INT(AF_INET) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_AF_INET6), MP_OBJ_NEW_SMALL_INT(AF_INET6) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_STREAM), MP_OBJ_NEW_SMALL_INT(SOCK_STREAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_DGRAM), MP_OBJ_NEW_SMALL_INT(SOCK_DGRAM) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_SOCK_RAW), MP_OBJ_NEW_SMALL_INT(SOCK_RAW) }, + + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_TCP), MP_OBJ_NEW_SMALL_INT(IPPROTO_TCP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_UDP), MP_OBJ_NEW_SMALL_INT(IPPROTO_UDP) }, + { MP_OBJ_NEW_QSTR(MP_QSTR_IPPROTO_RAW), MP_OBJ_NEW_SMALL_INT(IPPROTO_RAW) }, +}; + +STATIC MP_DEFINE_CONST_DICT(mp_module_usocket_globals, mp_module_usocket_globals_table); + +const mp_obj_module_t mp_module_usocket = { + .base = { &mp_type_module }, + .name = MP_QSTR_usocket, + .globals = (mp_obj_dict_t*)&mp_module_usocket_globals, +}; |
