Skip to content

Commit 74cdf42

Browse files
committed
pico w: implement bind, listen, accept
this works with some simple tcp & udp echo service code
1 parent 12ea04c commit 74cdf42

File tree

1 file changed

+140
-6
lines changed
  • ports/raspberrypi/common-hal/socketpool

1 file changed

+140
-6
lines changed

ports/raspberrypi/common-hal/socketpool/Socket.c

Lines changed: 140 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include "py/stream.h"
3838
#include "shared-bindings/socketpool/SocketPool.h"
3939
#include "shared/runtime/interrupt_char.h"
40+
#include "shared/netutils/netutils.h"
4041
#include "supervisor/port.h"
4142
#include "supervisor/shared/tick.h"
4243
#include "supervisor/workflow.h"
@@ -115,6 +116,10 @@ static inline void poll_sockets(void) {
115116
#ifdef MICROPY_EVENT_POLL_HOOK
116117
MICROPY_EVENT_POLL_HOOK;
117118
#else
119+
RUN_BACKGROUND_TASKS;
120+
if (MP_STATE_THREAD(mp_pending_exception) != MP_OBJ_NULL) {
121+
mp_handle_pending(true);
122+
}
118123
mp_hal_delay_ms(1);
119124
#endif
120125
}
@@ -739,14 +744,117 @@ int socketpool_socket_accept(socketpool_socket_obj_t *self, uint8_t *ip, uint32_
739744
return -MP_EBADF;
740745
}
741746

742-
socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *self,
747+
socketpool_socket_obj_t *common_hal_socketpool_socket_accept(socketpool_socket_obj_t *socket,
743748
uint8_t *ip, uint32_t *port) {
744-
mp_raise_NotImplementedError(NULL);
749+
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
750+
mp_raise_OSError(MP_EOPNOTSUPP);
751+
}
752+
753+
// Create new socket object, do it here because we must not raise an out-of-memory
754+
// exception when the LWIP concurrency lock is held
755+
socketpool_socket_obj_t *socket2 = m_new_ll_obj_with_finaliser(socketpool_socket_obj_t);
756+
socket2->base.type = &socketpool_socket_type;
757+
758+
MICROPY_PY_LWIP_ENTER
759+
760+
if (socket->pcb.tcp == NULL) {
761+
MICROPY_PY_LWIP_EXIT
762+
m_del_obj(socketpool_socket_obj_t, socket2);
763+
mp_raise_OSError(MP_EBADF);
764+
}
765+
766+
// I need to do this because "tcp_accepted", later, is a macro.
767+
struct tcp_pcb *listener = socket->pcb.tcp;
768+
if (listener->state != LISTEN) {
769+
MICROPY_PY_LWIP_EXIT
770+
m_del_obj(socketpool_socket_obj_t, socket2);
771+
mp_raise_OSError(MP_EINVAL);
772+
}
773+
774+
// accept incoming connection
775+
struct tcp_pcb *volatile *incoming_connection = &lwip_socket_incoming_array(socket)[socket->incoming.connection.iget];
776+
if (*incoming_connection == NULL) {
777+
if (socket->timeout == 0) {
778+
MICROPY_PY_LWIP_EXIT
779+
m_del_obj(socketpool_socket_obj_t, socket2);
780+
mp_raise_OSError(MP_EAGAIN);
781+
} else if (socket->timeout != -1) {
782+
mp_uint_t retries = socket->timeout / 100;
783+
while (*incoming_connection == NULL) {
784+
MICROPY_PY_LWIP_EXIT
785+
if (retries-- == 0) {
786+
m_del_obj(socketpool_socket_obj_t, socket2);
787+
mp_raise_OSError(MP_ETIMEDOUT);
788+
}
789+
mp_hal_delay_ms(100);
790+
MICROPY_PY_LWIP_REENTER
791+
}
792+
} else {
793+
while (*incoming_connection == NULL) {
794+
MICROPY_PY_LWIP_EXIT
795+
poll_sockets();
796+
MICROPY_PY_LWIP_REENTER
797+
}
798+
}
799+
}
800+
801+
// We get a new pcb handle...
802+
socket2->pcb.tcp = *incoming_connection;
803+
if (++socket->incoming.connection.iget >= socket->incoming.connection.alloc) {
804+
socket->incoming.connection.iget = 0;
805+
}
806+
*incoming_connection = NULL;
807+
808+
// ...and set up the new socket for it.
809+
socket2->domain = MOD_NETWORK_AF_INET;
810+
socket2->type = MOD_NETWORK_SOCK_STREAM;
811+
socket2->incoming.pbuf = NULL;
812+
socket2->timeout = socket->timeout;
813+
socket2->state = STATE_CONNECTED;
814+
socket2->recv_offset = 0;
815+
socket2->callback = MP_OBJ_NULL;
816+
tcp_arg(socket2->pcb.tcp, (void *)socket2);
817+
tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
818+
tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
819+
820+
tcp_accepted(listener);
821+
822+
MICROPY_PY_LWIP_EXIT
823+
824+
// output values
825+
memcpy(ip, &(socket2->pcb.tcp->remote_ip), NETUTILS_IPV4ADDR_BUFSIZE);
826+
*port = (mp_uint_t)socket2->pcb.tcp->remote_port;
827+
return MP_OBJ_FROM_PTR(socket2);
745828
}
746829

747-
bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *self,
830+
bool common_hal_socketpool_socket_bind(socketpool_socket_obj_t *socket,
748831
const char *host, size_t hostlen, uint32_t port) {
749-
mp_raise_NotImplementedError(NULL);
832+
uint8_t ip[NETUTILS_IPV4ADDR_BUFSIZE];
833+
834+
// get address
835+
ip_addr_t bind_addr;
836+
int error = socketpool_resolve_host(socket->pool, host, &bind_addr);
837+
if (error != 0) {
838+
mp_raise_OSError(EHOSTUNREACH);
839+
}
840+
841+
err_t err = ERR_ARG;
842+
switch (socket->type) {
843+
case MOD_NETWORK_SOCK_STREAM: {
844+
err = tcp_bind(socket->pcb.tcp, &bind_addr, port);
845+
break;
846+
}
847+
case MOD_NETWORK_SOCK_DGRAM: {
848+
err = udp_bind(socket->pcb.udp, &bind_addr, port);
849+
break;
850+
}
851+
}
852+
853+
if (err != ERR_OK) {
854+
mp_raise_OSError(error_lookup_table[-err]);
855+
}
856+
857+
return mp_const_none;
750858
}
751859

752860
STATIC err_t _lwip_tcp_close_poll(void *arg, struct tcp_pcb *pcb) {
@@ -891,8 +999,34 @@ bool common_hal_socketpool_socket_get_connected(socketpool_socket_obj_t *socket)
891999
return socket->state == STATE_CONNECTED;
8921000
}
8931001

894-
bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *self, int backlog) {
895-
mp_raise_NotImplementedError(NULL);
1002+
bool common_hal_socketpool_socket_listen(socketpool_socket_obj_t *socket, int backlog) {
1003+
if (socket->type != MOD_NETWORK_SOCK_STREAM) {
1004+
mp_raise_OSError(MP_EOPNOTSUPP);
1005+
}
1006+
1007+
struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
1008+
if (new_pcb == NULL) {
1009+
mp_raise_OSError(MP_ENOMEM);
1010+
}
1011+
socket->pcb.tcp = new_pcb;
1012+
1013+
// Allocate memory for the backlog of connections
1014+
if (backlog <= 1) {
1015+
socket->incoming.connection.alloc = 0;
1016+
socket->incoming.connection.tcp.item = NULL;
1017+
} else {
1018+
socket->incoming.connection.alloc = backlog;
1019+
socket->incoming.connection.tcp.array = m_new0(struct tcp_pcb *, backlog);
1020+
}
1021+
socket->incoming.connection.iget = 0;
1022+
socket->incoming.connection.iput = 0;
1023+
1024+
tcp_accept(new_pcb, _lwip_tcp_accept);
1025+
1026+
// Socket is no longer considered "new" for purposes of polling
1027+
socket->state = STATE_LISTENING;
1028+
1029+
return mp_const_none;
8961030
}
8971031

8981032
mp_uint_t common_hal_socketpool_socket_recvfrom_into(socketpool_socket_obj_t *socket,

0 commit comments

Comments
 (0)