Commit 7d570379 authored by Paul Sokolovsky's avatar Paul Sokolovsky
Browse files

extmod/modlwip: Add ability to run callback on "recv" and "accept" events.

To use: .setsockopt(SOL_SOCKET, 20, lambda sock: print(sock)). There's a
single underlying callback slot. For normal sockets, it serves as data
received callback, for listening sockets - connection arrived callback.
parent 67ece471
...@@ -234,6 +234,7 @@ typedef struct _lwip_socket_obj_t { ...@@ -234,6 +234,7 @@ typedef struct _lwip_socket_obj_t {
struct pbuf *pbuf; struct pbuf *pbuf;
struct tcp_pcb *connection; struct tcp_pcb *connection;
} incoming; } incoming;
mp_obj_t callback;
byte peer[4]; byte peer[4];
mp_uint_t peer_port; mp_uint_t peer_port;
mp_uint_t timeout; mp_uint_t timeout;
...@@ -261,6 +262,12 @@ static inline void poll_sockets(void) { ...@@ -261,6 +262,12 @@ static inline void poll_sockets(void) {
/*******************************************************************************/ /*******************************************************************************/
// Callback functions for the lwIP raw API. // Callback functions for the lwIP raw API.
static inline void exec_user_callback(lwip_socket_obj_t *socket) {
if (socket->callback != MP_OBJ_NULL) {
mp_call_function_1(socket->callback, socket);
}
}
// Callback for incoming UDP packets. We simply stash the packet and the source address, // Callback for incoming UDP packets. We simply stash the packet and the source address,
// in case we need it for recvfrom. // in case we need it for recvfrom.
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) { STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
...@@ -315,6 +322,7 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) { ...@@ -315,6 +322,7 @@ STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
return ERR_BUF; return ERR_BUF;
} else { } else {
socket->incoming.connection = newpcb; socket->incoming.connection = newpcb;
exec_user_callback(socket);
return ERR_OK; return ERR_OK;
} }
} }
...@@ -327,12 +335,16 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err ...@@ -327,12 +335,16 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
// Other side has closed connection. // Other side has closed connection.
DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket); DEBUG_printf("_lwip_tcp_recv[%p]: other side closed connection\n", socket);
socket->state = STATE_PEER_CLOSED; socket->state = STATE_PEER_CLOSED;
exec_user_callback(socket);
return ERR_OK; return ERR_OK;
} else if (socket->incoming.pbuf != NULL) { } else if (socket->incoming.pbuf != NULL) {
// No room in the inn, let LWIP know it's still responsible for delivery later // No room in the inn, let LWIP know it's still responsible for delivery later
return ERR_BUF; return ERR_BUF;
} }
socket->incoming.pbuf = p; socket->incoming.pbuf = p;
exec_user_callback(socket);
return ERR_OK; return ERR_OK;
} }
...@@ -542,6 +554,7 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args ...@@ -542,6 +554,7 @@ STATIC mp_obj_t lwip_socket_make_new(const mp_obj_type_t *type, mp_uint_t n_args
socket->base.type = (mp_obj_t)&lwip_socket_type; socket->base.type = (mp_obj_t)&lwip_socket_type;
socket->domain = MOD_NETWORK_AF_INET; socket->domain = MOD_NETWORK_AF_INET;
socket->type = MOD_NETWORK_SOCK_STREAM; socket->type = MOD_NETWORK_SOCK_STREAM;
socket->callback = MP_OBJ_NULL;
if (n_args >= 1) { if (n_args >= 1) {
socket->domain = mp_obj_get_int(args[0]); socket->domain = mp_obj_get_int(args[0]);
if (n_args >= 2) { if (n_args >= 2) {
...@@ -717,6 +730,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) { ...@@ -717,6 +730,7 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
socket2->timeout = socket->timeout; socket2->timeout = socket->timeout;
socket2->state = STATE_CONNECTED; socket2->state = STATE_CONNECTED;
socket2->leftover_count = 0; socket2->leftover_count = 0;
socket2->callback = MP_OBJ_NULL;
tcp_arg(socket2->pcb.tcp, (void*)socket2); tcp_arg(socket2->pcb.tcp, (void*)socket2);
tcp_err(socket2->pcb.tcp, _lwip_tcp_error); tcp_err(socket2->pcb.tcp, _lwip_tcp_error);
tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv); tcp_recv(socket2->pcb.tcp, _lwip_tcp_recv);
...@@ -978,8 +992,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblo ...@@ -978,8 +992,20 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_setblocking_obj, lwip_socket_setblo
STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) { STATIC mp_obj_t lwip_socket_setsockopt(mp_uint_t n_args, const mp_obj_t *args) {
(void)n_args; // always 4 (void)n_args; // always 4
lwip_socket_obj_t *socket = args[0]; lwip_socket_obj_t *socket = args[0];
int opt = mp_obj_get_int(args[2]);
if (opt == 20) {
if (args[3] == mp_const_none) {
socket->callback = MP_OBJ_NULL;
} else {
socket->callback = args[3];
}
return mp_const_none;
}
// Integer options
mp_int_t val = mp_obj_get_int(args[3]); mp_int_t val = mp_obj_get_int(args[3]);
switch (mp_obj_get_int(args[2])) { switch (opt) {
case SOF_REUSEADDR: case SOF_REUSEADDR:
// Options are common for UDP and TCP pcb's. // Options are common for UDP and TCP pcb's.
if (val) { if (val) {
......
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment