// 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; }
// 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 mod_network_socket_obj_t *socket2 = m_new_obj_with_finaliser(mod_network_socket_obj_t); // the new socket inherits all properties from its parent memcpy (socket2, self, sizeof(mod_network_socket_obj_t)); // accept the incoming connection uint8_t ip[MOD_NETWORK_IPV4ADDR_BUF_SIZE]; mp_uint_t port; int _errno; if (wlan_socket_accept(self, socket2, ip, &port, &_errno) != 0) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(-_errno))); } // add the socket to the list modusocket_socket_add(socket2->sock_base.sd, true); // make the return value mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_LITTLE); return client; }
// 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 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->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 > 0) { s->u_param.domain = mp_obj_get_int(args[0]); if (n_args > 1) { s->u_param.type = mp_obj_get_int(args[1]); if (n_args > 2) { s->u_param.proto = mp_obj_get_int(args[2]); if (n_args > 3) { s->u_param.fileno = mp_obj_get_int(args[3]); } } } } // create the socket int _errno; if (wlan_socket_socket(s, &_errno) != 0) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(_errno))); } modusocket_socket_add(s->sd, true); return s; }
// 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; }
// constructor socket(family=AF_INET, type=SOCK_STREAM, proto=IPPROTO_TCP, fileno=None) STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 0, 4, false); // create socket object 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->sock_base.u_param.domain = AF_INET; s->sock_base.u_param.type = SOCK_STREAM; s->sock_base.u_param.proto = IPPROTO_TCP; s->sock_base.u_param.fileno = -1; s->sock_base.has_timeout = false; s->sock_base.cert_req = false; if (n_args > 0) { s->sock_base.u_param.domain = mp_obj_get_int(args[0]); if (n_args > 1) { s->sock_base.u_param.type = mp_obj_get_int(args[1]); if (n_args > 2) { s->sock_base.u_param.proto = mp_obj_get_int(args[2]); if (n_args > 3) { s->sock_base.u_param.fileno = mp_obj_get_int(args[3]); } } } } // create the socket int _errno; if (wlan_socket_socket(s, &_errno) != 0) { mp_raise_OSError(-_errno); } // add the socket to the list modusocket_socket_add(s->sock_base.sd, true); return s; }
STATIC mp_obj_t socket_accept(const mp_obj_t arg0) { socket_obj_t *self = MP_OBJ_TO_PTR(arg0); struct sockaddr addr; socklen_t addr_len = sizeof(addr); int new_fd = -1; for (int i=0; i<=self->retries; i++) { MP_THREAD_GIL_EXIT(); new_fd = lwip_accept_r(self->fd, &addr, &addr_len); MP_THREAD_GIL_ENTER(); if (new_fd >= 0) break; if (errno != EAGAIN) exception_from_errno(errno); check_for_exceptions(); } if (new_fd < 0) mp_raise_OSError(MP_ETIMEDOUT); // create new socket object socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); sock->base.type = self->base.type; sock->fd = new_fd; sock->domain = self->domain; sock->type = self->type; sock->proto = self->proto; _socket_settimeout(sock, UINT64_MAX); // make the return value uint8_t *ip = (uint8_t*)&((struct sockaddr_in*)&addr)->sin_addr; mp_uint_t port = lwip_ntohs(((struct sockaddr_in*)&addr)->sin_port); mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = sock; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }
STATIC mp_obj_t file_obj_make_new(mp_obj_t type_in, uint n_args, uint n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); const char *filename = mp_obj_str_get_str(args[0]); const char *mode = "r"; if (n_args > 1) { mode = mp_obj_str_get_str(args[1]); } pyb_file_obj_t *self = m_new_obj_with_finaliser(pyb_file_obj_t); self->base.type = &file_obj_type; if (mode[0] == 'r') { // open for reading FRESULT res = f_open(&self->fp, filename, FA_READ); if (res != FR_OK) { printf("FileNotFoundError: [Errno 2] No such file or directory: '%s'\n", filename); return mp_const_none; } } else if (mode[0] == 'w') { // open for writing, truncate the file first FRESULT res = f_open(&self->fp, filename, FA_WRITE | FA_CREATE_ALWAYS); if (res != FR_OK) { printf("?FileError: could not create file: '%s'\n", filename); return mp_const_none; } } else { printf("ValueError: invalid mode: '%s'\n", mode); return mp_const_none; } return self; }
STATIC mp_obj_t file_obj_make_new(mp_obj_t type, mp_uint_t n_args, mp_uint_t n_kw, const mp_obj_t *args) { mp_arg_check_num(n_args, n_kw, 1, 2, false); const char *fname = mp_obj_str_get_str(args[0]); int mode = 0; if (n_args == 1) { mode = FA_READ; } else { const char *mode_s = mp_obj_str_get_str(args[1]); // TODO make sure only one of r, w, x, a, and b, t are specified while (*mode_s) { switch (*mode_s++) { case 'r': mode |= FA_READ; break; case 'w': mode |= FA_WRITE | FA_CREATE_ALWAYS; break; case 'x': mode |= FA_WRITE | FA_CREATE_NEW; break; case 'a': mode |= FA_WRITE | FA_OPEN_ALWAYS; break; case '+': mode |= FA_READ | FA_WRITE; break; #if MICROPY_PY_IO_FILEIO case 'b': type = (mp_obj_t)&mp_type_fileio; break; #endif case 't': type = (mp_obj_t)&mp_type_textio; break; } } } pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t); o->base.type = type; FRESULT res = f_open(&o->fp, fname, mode); if (res != FR_OK) { m_del_obj(pyb_file_obj_t, o); nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(fresult_to_errno_table[res]))); } // for 'a' mode, we must begin at the end of the file if ((mode & FA_OPEN_ALWAYS) != 0) { f_lseek(&o->fp, f_size(&o->fp)); } return o; }
// FIXME: Only supports two arguments at present STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, 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); lwip_socket_obj_t *socket = m_new_obj_with_finaliser(lwip_socket_obj_t); socket->base.type = (mp_obj_t)&lwip_socket_type; socket->domain = MOD_NETWORK_AF_INET; socket->type = MOD_NETWORK_SOCK_STREAM; socket->callback = MP_OBJ_NULL; if (n_args >= 1) { socket->domain = mp_obj_get_int(args[0]); if (n_args >= 2) { socket->type = mp_obj_get_int(args[1]); } } switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: socket->pcb.tcp = tcp_new(); break; case MOD_NETWORK_SOCK_DGRAM: socket->pcb.udp = udp_new(); break; //case MOD_NETWORK_SOCK_RAW: socket->pcb.raw = raw_new(); break; default: nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_EINVAL))); } if (socket->pcb.tcp == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(MP_ENOMEM))); } switch (socket->type) { case MOD_NETWORK_SOCK_STREAM: { // Register the socket object as our callback argument. tcp_arg(socket->pcb.tcp, (void*)socket); // Register our error callback. tcp_err(socket->pcb.tcp, _lwip_tcp_error); break; } case MOD_NETWORK_SOCK_DGRAM: { // Register our receive callback now. Since UDP sockets don't require binding or connection // before use, there's no other good time to do it. udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket); break; } } socket->incoming.pbuf = NULL; socket->timeout = -1; socket->state = STATE_NEW; socket->leftover_count = 0; return socket; }
STATIC mp_obj_t esp_socket_make_new_base() { esp_socket_obj_t *s = m_new_obj_with_finaliser(esp_socket_obj_t); s->recvbuf = NULL; s->base.type = (mp_obj_t)&esp_socket_type; s->cb_connect = mp_const_none; s->cb_recv = mp_const_none; s->cb_disconnect = mp_const_none; s->cb_sent = mp_const_none; s->fromserver = false; s->connlist = NULL; return s; }
static void get_fds(mp_obj_t *fdlist, uint fdlist_len, mp_obj_t *fdlist_out, fd_set *fdset) { for (int i=0; i<fdlist_len; i++) { socket_t *s = fdlist[i]; if (FD_ISSET(s->fd, fdset)) { socket_t *socket_obj = m_new_obj_with_finaliser(socket_t); socket_obj->base.type = (mp_obj_t)&socket_type; socket_obj->fd = s->fd; mp_obj_list_append(fdlist_out, socket_obj); } } }
STATIC mp_obj_t file_open(fs_user_mount_t *vfs, const mp_obj_type_t *type, mp_arg_val_t *args) { int mode = 0; const char *mode_s = mp_obj_str_get_str(args[1].u_obj); // TODO make sure only one of r, w, x, a, and b, t are specified while (*mode_s) { switch (*mode_s++) { case 'r': mode |= FA_READ; break; case 'w': mode |= FA_WRITE | FA_CREATE_ALWAYS; break; case 'x': mode |= FA_WRITE | FA_CREATE_NEW; break; case 'a': mode |= FA_WRITE | FA_OPEN_ALWAYS; break; case '+': mode |= FA_READ | FA_WRITE; break; #if MICROPY_PY_IO_FILEIO case 'b': type = &mp_type_fileio; break; #endif case 't': type = &mp_type_textio; break; } } pyb_file_obj_t *o = m_new_obj_with_finaliser(pyb_file_obj_t); o->base.type = type; const char *fname = mp_obj_str_get_str(args[0].u_obj); assert(vfs != NULL); FRESULT res = f_open(&vfs->fatfs, &o->fp, fname, mode); if (res != FR_OK) { m_del_obj(pyb_file_obj_t, o); mp_raise_OSError(fresult_to_errno_table[res]); } // for 'a' mode, we must begin at the end of the file if ((mode & FA_OPEN_ALWAYS) != 0) { f_lseek(&o->fp, f_size(&o->fp)); } return MP_OBJ_FROM_PTR(o); }
STATIC mp_obj_t ppp_make_new(mp_obj_t stream) { mp_get_stream_raise(stream, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE); ppp_if_obj_t *self = m_new_obj_with_finaliser(ppp_if_obj_t); self->base.type = &ppp_if_type; self->stream = stream; self->active = false; self->connected = false; self->clean_close = false; self->client_task_handle = NULL; return MP_OBJ_FROM_PTR(self); }
STATIC mp_obj_t get_socket(size_t n_args, const mp_obj_t *args) { socket_obj_t *sock = m_new_obj_with_finaliser(socket_obj_t); sock->base.type = &socket_type; sock->domain = AF_INET; sock->type = SOCK_STREAM; sock->proto = 0; if (n_args > 0) { sock->domain = mp_obj_get_int(args[0]); if (n_args > 1) { sock->type = mp_obj_get_int(args[1]); if (n_args > 2) { sock->proto = mp_obj_get_int(args[2]); } } } sock->fd = lwip_socket(sock->domain, sock->type, sock->proto); if (sock->fd < 0) { exception_from_errno(errno); } _socket_settimeout(sock, UINT64_MAX); return MP_OBJ_FROM_PTR(sock); }
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb.tcp == NULL) { mp_raise_OSError(MP_EBADF); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { mp_raise_OSError(MP_EOPNOTSUPP); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = socket->pcb.tcp; if (listener->state != LISTEN) { mp_raise_OSError(MP_EINVAL); } // accept incoming connection if (socket->incoming.connection == NULL) { if (socket->timeout == 0) { mp_raise_OSError(MP_EAGAIN); } else if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->incoming.connection != NULL) break; } if (socket->incoming.connection == NULL) { mp_raise_OSError(MP_ETIMEDOUT); } } else { while (socket->incoming.connection == NULL) { poll_sockets(); } } } // create new socket object lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); socket2->base.type = (mp_obj_t)&lwip_socket_type; // We get a new pcb handle... socket2->pcb.tcp = socket->incoming.connection; socket->incoming.connection = NULL; // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming.pbuf = NULL; socket2->timeout = socket->timeout; socket2->state = STATE_CONNECTED; socket2->recv_offset = 0; socket2->callback = MP_OBJ_NULL; tcp_arg(socket2->pcb.tcp, (void*)socket2); tcp_err(socket2->pcb.tcp, _lwip_tcp_error); tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); tcp_accepted(listener); // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(socket2->pcb.tcp->remote_ip), sizeof(ip)); mp_uint_t port = (mp_uint_t)socket2->pcb.tcp->remote_port; mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }
STATIC mp_obj_ssl_socket_t *socket_new(mp_obj_t sock, struct ssl_args *args) { // Verify the socket object has the full stream protocol mp_get_stream_raise(sock, MP_STREAM_OP_READ | MP_STREAM_OP_WRITE | MP_STREAM_OP_IOCTL); #if MICROPY_PY_USSL_FINALISER mp_obj_ssl_socket_t *o = m_new_obj_with_finaliser(mp_obj_ssl_socket_t); #else mp_obj_ssl_socket_t *o = m_new_obj(mp_obj_ssl_socket_t); #endif o->base.type = &ussl_socket_type; o->sock = sock; int ret; mbedtls_ssl_init(&o->ssl); mbedtls_ssl_config_init(&o->conf); mbedtls_x509_crt_init(&o->cacert); mbedtls_x509_crt_init(&o->cert); mbedtls_pk_init(&o->pkey); mbedtls_ctr_drbg_init(&o->ctr_drbg); #ifdef MBEDTLS_DEBUG_C // Debug level (0-4) mbedtls_debug_set_threshold(0); #endif mbedtls_entropy_init(&o->entropy); const byte seed[] = "upy"; ret = mbedtls_ctr_drbg_seed(&o->ctr_drbg, mbedtls_entropy_func, &o->entropy, seed, sizeof(seed)); if (ret != 0) { goto cleanup; } ret = mbedtls_ssl_config_defaults(&o->conf, args->server_side.u_bool ? MBEDTLS_SSL_IS_SERVER : MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT); if (ret != 0) { goto cleanup; } mbedtls_ssl_conf_authmode(&o->conf, MBEDTLS_SSL_VERIFY_NONE); mbedtls_ssl_conf_rng(&o->conf, mbedtls_ctr_drbg_random, &o->ctr_drbg); #ifdef MBEDTLS_DEBUG_C mbedtls_ssl_conf_dbg(&o->conf, mbedtls_debug, NULL); #endif ret = mbedtls_ssl_setup(&o->ssl, &o->conf); if (ret != 0) { goto cleanup; } if (args->server_hostname.u_obj != mp_const_none) { const char *sni = mp_obj_str_get_str(args->server_hostname.u_obj); ret = mbedtls_ssl_set_hostname(&o->ssl, sni); if (ret != 0) { goto cleanup; } } mbedtls_ssl_set_bio(&o->ssl, &o->sock, _mbedtls_ssl_send, _mbedtls_ssl_recv, NULL); if (args->key.u_obj != MP_OBJ_NULL) { size_t key_len; const byte *key = (const byte*)mp_obj_str_get_data(args->key.u_obj, &key_len); // len should include terminating null ret = mbedtls_pk_parse_key(&o->pkey, key, key_len + 1, NULL, 0); assert(ret == 0); size_t cert_len; const byte *cert = (const byte*)mp_obj_str_get_data(args->cert.u_obj, &cert_len); // len should include terminating null ret = mbedtls_x509_crt_parse(&o->cert, cert, cert_len + 1); assert(ret == 0); ret = mbedtls_ssl_conf_own_cert(&o->conf, &o->cert, &o->pkey); assert(ret == 0); } if (args->do_handshake.u_bool) { while ((ret = mbedtls_ssl_handshake(&o->ssl)) != 0) { if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE) { printf("mbedtls_ssl_handshake error: -%x\n", -ret); goto cleanup; } } } return o; cleanup: mbedtls_pk_free(&o->pkey); mbedtls_x509_crt_free(&o->cert); mbedtls_x509_crt_free(&o->cacert); mbedtls_ssl_free(&o->ssl); mbedtls_ssl_config_free(&o->conf); mbedtls_ctr_drbg_free(&o->ctr_drbg); mbedtls_entropy_free(&o->entropy); if (ret == MBEDTLS_ERR_SSL_ALLOC_FAILED) { mp_raise_OSError(MP_ENOMEM); } else { mp_raise_OSError(MP_EIO); } }
socket_obj_t *socket_new(void) { socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t); socket->base.type = (mp_obj_t)&socket_type; socket->state = STATE_NEW; return socket; }
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { lwip_socket_obj_t *socket = self_in; if (socket->pcb == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF))); } if (socket->type != MOD_NETWORK_SOCK_STREAM) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EOPNOTSUPP))); } // I need to do this because "tcp_accepted", later, is a macro. struct tcp_pcb *listener = (struct tcp_pcb*)socket->pcb; if (listener->state != LISTEN) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EINVAL))); } // accept incoming connection if (socket->incoming == NULL) { if (socket->timeout != -1) { for (mp_uint_t retries = socket->timeout / 100; retries--;) { mp_hal_delay_ms(100); if (socket->incoming != NULL) break; } if (socket->incoming == NULL) { nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT))); } } else { while (socket->incoming == NULL) { mp_hal_delay_ms(100); } } } // create new socket object lwip_socket_obj_t *socket2 = m_new_obj_with_finaliser(lwip_socket_obj_t); socket2->base.type = (mp_obj_t)&lwip_socket_type; // We get a new pcb handle... socket2->pcb = socket->incoming; socket->incoming = NULL; // ...and set up the new socket for it. socket2->domain = MOD_NETWORK_AF_INET; socket2->type = MOD_NETWORK_SOCK_STREAM; socket2->incoming = NULL; socket2->timeout = socket->timeout; socket2->connected = 2; socket2->leftover_count = 0; tcp_arg((struct tcp_pcb*)socket2->pcb, (void*)socket2); tcp_err((struct tcp_pcb*)socket2->pcb, _lwip_tcp_error); tcp_recv((struct tcp_pcb*)socket2->pcb, _lwip_tcp_recv); tcp_accepted(listener); // make the return value uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE]; memcpy(ip, &(((struct tcp_pcb*)socket2->pcb)->remote_ip), 4); mp_uint_t port = (mp_uint_t)((struct tcp_pcb*)socket2->pcb)->remote_port; mp_obj_tuple_t *client = mp_obj_new_tuple(2, NULL); client->items[0] = socket2; client->items[1] = netutils_format_inet_addr(ip, port, NETUTILS_BIG); return client; }