Skip to content

Commit 3df65e9

Browse files
committed
zephyr/modusocket: Implement recv() for UDP sockets.
The foundation of recv() support is per-socket queue of incoming packets, implemented using Zephyr FIFO object. This patch implements just recv() for UDP, because TCP recv() requires much more fine-grained control of network fragments and handling other issues, like EOF condition, etc.
1 parent 4c307bf commit 3df65e9

File tree

1 file changed

+87
-0
lines changed

1 file changed

+87
-0
lines changed

zephyr/modusocket.c

Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,13 +29,21 @@
2929

3030
#include "py/runtime.h"
3131

32+
#include <stdio.h>
3233
#include <zephyr.h>
3334
#include <net/net_context.h>
3435
#include <net/nbuf.h>
3536

37+
#if 0 // print debugging info
38+
#define DEBUG_printf printf
39+
#else // don't print debugging info
40+
#define DEBUG_printf(...) (void)0
41+
#endif
42+
3643
typedef struct _socket_obj_t {
3744
mp_obj_base_t base;
3845
struct net_context *ctx;
46+
struct k_fifo recv_q;
3947
} socket_obj_t;
4048

4149
STATIC const mp_obj_type_t socket_type;
@@ -62,6 +70,44 @@ STATIC void parse_inet_addr(socket_obj_t *socket, mp_obj_t addr_in, struct socka
6270
sockaddr_in->sin_port = htons(mp_obj_get_int(addr_items[1]));
6371
}
6472

73+
// Copy data from Zephyr net_buf chain into linear buffer.
74+
// We don't use net_nbuf_read(), because it's weird (e.g., we'd like to
75+
// free processed data fragment ASAP, while net_nbuf_read() holds onto
76+
// the whole fragment chain to do its deeds, and that's minor comparing
77+
// to the fact that it copies data byte by byte).
78+
static char *net_buf_gather(struct net_buf *buf, char *to, unsigned max_len) {
79+
struct net_buf *tmp = buf->frags;
80+
unsigned header_len = net_nbuf_appdata(buf) - tmp->data;
81+
net_buf_pull(tmp, header_len);
82+
83+
while (tmp && max_len) {
84+
unsigned len = tmp->len;
85+
if (len > max_len) {
86+
len = max_len;
87+
}
88+
memcpy(to, tmp->data, len);
89+
to += len;
90+
max_len -= len;
91+
tmp = net_buf_frag_del(buf, tmp);
92+
}
93+
94+
return to;
95+
}
96+
97+
// Callback for incoming packets.
98+
static void sock_received_cb(struct net_context *context, struct net_buf *net_buf, int status, void *user_data) {
99+
socket_obj_t *socket = (socket_obj_t*)user_data;
100+
DEBUG_printf("recv cb: context: %p, status: %d, buf: %p", context, status, net_buf);
101+
if (net_buf) {
102+
DEBUG_printf(" (sz=%d, l=%d), token: %p", net_buf->size, net_buf->len, net_nbuf_token(net_buf));
103+
}
104+
DEBUG_printf("\n");
105+
106+
// net_buf->frags will be overwritten by fifo, so save it
107+
net_nbuf_set_token(net_buf, net_buf->frags);
108+
k_fifo_put(&socket->recv_q, net_buf);
109+
}
110+
65111
// Methods
66112

67113
STATIC void socket_print(const mp_print_t *print, mp_obj_t self_in, mp_print_kind_t kind) {
@@ -79,6 +125,7 @@ STATIC mp_obj_t socket_make_new(const mp_obj_type_t *type, size_t n_args, size_t
79125

80126
socket_obj_t *socket = m_new_obj_with_finaliser(socket_obj_t);
81127
socket->base.type = type;
128+
k_fifo_init(&socket->recv_q);
82129

83130
int family = AF_INET;
84131
int socktype = SOCK_STREAM;
@@ -114,6 +161,8 @@ STATIC mp_obj_t socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
114161
parse_inet_addr(socket, addr_in, &sockaddr);
115162

116163
RAISE_ERRNO(net_context_bind(socket->ctx, &sockaddr, sizeof(sockaddr)));
164+
DEBUG_printf("Setting recv cb after bind\n");
165+
RAISE_ERRNO(net_context_recv(socket->ctx, sock_received_cb, K_NO_WAIT, socket));
117166
return mp_const_none;
118167
}
119168
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_bind_obj, socket_bind);
@@ -126,6 +175,8 @@ STATIC mp_obj_t socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
126175
parse_inet_addr(socket, addr_in, &sockaddr);
127176

128177
RAISE_ERRNO(net_context_connect(socket->ctx, &sockaddr, sizeof(sockaddr), NULL, K_FOREVER, NULL));
178+
DEBUG_printf("Setting recv cb after connect()\n");
179+
RAISE_ERRNO(net_context_recv(socket->ctx, sock_received_cb, K_NO_WAIT, socket));
129180
return mp_const_none;
130181
}
131182
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_connect_obj, socket_connect);
@@ -149,6 +200,41 @@ STATIC mp_obj_t socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
149200
}
150201
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_send_obj, socket_send);
151202

203+
STATIC mp_obj_t socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
204+
socket_obj_t *socket = self_in;
205+
socket_check_closed(socket);
206+
207+
enum net_sock_type sock_type = net_context_get_type(socket->ctx);
208+
mp_int_t max_len = mp_obj_get_int(len_in);
209+
unsigned recv_len;
210+
vstr_t vstr;
211+
212+
if (sock_type == SOCK_DGRAM) {
213+
214+
struct net_buf *net_buf = k_fifo_get(&socket->recv_q, K_FOREVER);
215+
// Restore ->frags overwritten by fifo
216+
net_buf->frags = net_nbuf_token(net_buf);
217+
218+
recv_len = net_nbuf_appdatalen(net_buf);
219+
DEBUG_printf("recv: net_buf=%p, appdatalen: %d\n", net_buf, recv_len);
220+
221+
if (recv_len > max_len) {
222+
recv_len = max_len;
223+
}
224+
225+
vstr_init_len(&vstr, recv_len);
226+
net_buf_gather(net_buf, vstr.buf, recv_len);
227+
net_nbuf_unref(net_buf);
228+
229+
} else {
230+
mp_not_implemented("");
231+
}
232+
233+
mp_obj_t ret = mp_obj_new_str_from_vstr(&mp_type_bytes, &vstr);
234+
return ret;
235+
}
236+
STATIC MP_DEFINE_CONST_FUN_OBJ_2(socket_recv_obj, socket_recv);
237+
152238
STATIC mp_obj_t socket_close(mp_obj_t self_in) {
153239
socket_obj_t *socket = self_in;
154240
if (socket->ctx != NULL) {
@@ -165,6 +251,7 @@ STATIC const mp_map_elem_t socket_locals_dict_table[] = {
165251
{ MP_OBJ_NEW_QSTR(MP_QSTR_bind), (mp_obj_t)&socket_bind_obj },
166252
{ MP_OBJ_NEW_QSTR(MP_QSTR_connect), (mp_obj_t)&socket_connect_obj },
167253
{ MP_OBJ_NEW_QSTR(MP_QSTR_send), (mp_obj_t)&socket_send_obj },
254+
{ MP_OBJ_NEW_QSTR(MP_QSTR_recv), (mp_obj_t)&socket_recv_obj },
168255
};
169256
STATIC MP_DEFINE_CONST_DICT(socket_locals_dict, socket_locals_dict_table);
170257

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy