extmod/lwip: Change void pointers to unions, include new mphal.h file

This commit is contained in:
Galen Hazelwood 2015-11-01 22:46:58 -08:00 committed by Paul Sokolovsky
parent 53ea2b5ce2
commit af3e45419c
2 changed files with 80 additions and 75 deletions

View File

@ -3,7 +3,7 @@
#include <py/mpconfig.h>
#include <py/misc.h>
#include MICROPY_HAL_H
#include <py/mphal.h>
// We're running without an OS for this port. We don't provide any services except light protection.
#define NO_SYS 1

View File

@ -32,7 +32,7 @@
#include "py/objlist.h"
#include "py/runtime.h"
#include "py/stream.h"
#include MICROPY_HAL_H
#include "py/mphal.h"
#include "netutils.h"
@ -183,8 +183,14 @@ static const int error_lookup_table[] = {
typedef struct _lwip_socket_obj_t {
mp_obj_base_t base;
void *pcb;
void *volatile incoming;
union {
struct tcp_pcb *tcp;
struct udp_pcb *udp;
} pcb;
union {
struct pbuf *pbuf;
struct tcp_pcb *connection;
} incoming;
byte peer[4];
mp_uint_t peer_port;
mp_uint_t timeout;
@ -205,11 +211,11 @@ typedef struct _lwip_socket_obj_t {
STATIC void _lwip_udp_incoming(void *arg, struct udp_pcb *upcb, struct pbuf *p, ip_addr_t *addr, u16_t port) {
lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
if (socket->incoming != NULL) {
if (socket->incoming.pbuf != NULL) {
// That's why they call it "unreliable". No room in the inn, drop the packet.
pbuf_free(p);
} else {
socket->incoming = (void*)p;
socket->incoming.pbuf = p;
socket->peer_port = (mp_uint_t)port;
memcpy(&socket->peer, addr, 4);
}
@ -222,7 +228,7 @@ STATIC void _lwip_tcp_error(void *arg, err_t err) {
// Pass the error code back via the connection variable.
socket->connected = err;
// If we got here, the lwIP stack either has deallocated or will deallocate the pcb.
socket->pcb = NULL;
socket->pcb.tcp = NULL;
}
// Callback for tcp connection requests. Error code err is unused. (See tcp.h)
@ -237,12 +243,12 @@ STATIC err_t _lwip_tcp_connected(void *arg, struct tcp_pcb *tpcb, err_t err) {
STATIC err_t _lwip_tcp_accept(void *arg, struct tcp_pcb *newpcb, err_t err) {
lwip_socket_obj_t *socket = (lwip_socket_obj_t*)arg;
if (socket->incoming != NULL) {
if (socket->incoming.connection != NULL) {
// We need to handle this better. This single-level structure makes the
// backlog setting kind of pointless. FIXME
return ERR_BUF;
} else {
socket->incoming = (void*)newpcb;
socket->incoming.connection = newpcb;
return ERR_OK;
}
}
@ -255,11 +261,11 @@ STATIC err_t _lwip_tcp_recv(void *arg, struct tcp_pcb *tcpb, struct pbuf *p, err
// Other side has closed connection.
socket->connected = 3;
return ERR_OK;
} else if (socket->incoming != NULL) {
} else if (socket->incoming.pbuf != NULL) {
// No room in the inn, let LWIP know it's still responsible for delivery later
return ERR_BUF;
}
socket->incoming = (void*)p;
socket->incoming.pbuf = p;
return ERR_OK;
}
@ -298,11 +304,11 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
err_t err;
if (ip == NULL) {
err = udp_send((struct udp_pcb*)socket->pcb, p);
err = udp_send(socket->pcb.udp, p);
} else {
ip_addr_t dest;
IP4_ADDR(&dest, ip[0], ip[1], ip[2], ip[3]);
err = udp_sendto((struct udp_pcb*)socket->pcb, p, &dest, port);
err = udp_sendto(socket->pcb.udp, p, &dest, port);
}
pbuf_free(p);
@ -318,18 +324,18 @@ STATIC mp_uint_t lwip_udp_send(lwip_socket_obj_t *socket, const byte *buf, mp_ui
// Helper function for recv/recvfrom to handle UDP packets
STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_t len, byte *ip, mp_uint_t *port, int *_errno) {
if (socket->incoming == NULL) {
if (socket->incoming.pbuf == 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.pbuf != NULL) break;
}
if (socket->incoming == NULL) {
if (socket->incoming.pbuf == NULL) {
*_errno = ETIMEDOUT;
return -1;
}
} else {
while (socket->incoming == NULL) {
while (socket->incoming.pbuf == NULL) {
mp_hal_delay_ms(100);
}
}
@ -340,22 +346,21 @@ STATIC mp_uint_t lwip_udp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
*port = socket->peer_port;
}
struct pbuf *p = (struct pbuf*)socket->incoming;
struct pbuf *p = socket->incoming.pbuf;
u16_t result = pbuf_copy_partial(p, buf, ((p->tot_len > len) ? len : p->tot_len), 0);
pbuf_free(p);
socket->incoming = NULL;
socket->incoming.pbuf = NULL;
return (mp_uint_t) result;
}
// Helper function for send/sendto to handle TCP packets
STATIC mp_uint_t lwip_tcp_send(lwip_socket_obj_t *socket, const byte *buf, mp_uint_t len, int *_errno) {
struct tcp_pcb *pcb = (struct tcp_pcb *)socket->pcb;
u16_t available = tcp_sndbuf(pcb);
u16_t available = tcp_sndbuf(socket->pcb.tcp);
u16_t write_len = MIN(available, len);
err_t err = tcp_write(pcb, buf, write_len, TCP_WRITE_FLAG_COPY);
err_t err = tcp_write(socket->pcb.tcp, buf, write_len, TCP_WRITE_FLAG_COPY);
if (err != ERR_OK) {
*_errno = error_lookup_table[-err];
@ -372,24 +377,24 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
return 0;
}
if (socket->incoming == NULL) {
if (socket->incoming.pbuf == 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.pbuf != NULL) break;
}
if (socket->incoming == NULL) {
if (socket->incoming.pbuf == NULL) {
*_errno = ETIMEDOUT;
return -1;
}
} else {
while (socket->incoming == NULL) {
while (socket->incoming.pbuf == NULL) {
mp_hal_delay_ms(100);
}
}
}
struct pbuf *p = (struct pbuf *)socket->incoming;
struct pbuf *p = socket->incoming.pbuf;
if (socket->leftover_count == 0) {
socket->leftover_count = p->tot_len;
@ -401,11 +406,11 @@ STATIC mp_uint_t lwip_tcp_receive(lwip_socket_obj_t *socket, byte *buf, mp_uint_
socket->leftover_count -= len;
} else {
pbuf_free(p);
socket->incoming = NULL;
socket->incoming.pbuf = NULL;
socket->leftover_count = 0;
}
tcp_recved((struct tcp_pcb *)socket->pcb, result);
tcp_recved(socket->pcb.tcp, result);
return (mp_uint_t) result;
}
@ -431,33 +436,33 @@ STATIC mp_obj_t lwip_socket_make_new(mp_obj_t type_in, mp_uint_t n_args,
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: socket->pcb = (void*)tcp_new(); break;
case MOD_NETWORK_SOCK_DGRAM: socket->pcb = (void*)udp_new(); break;
//case MOD_NETWORK_SOCK_RAW: socket->pcb = (void*)raw_new(); break;
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(EINVAL)));
}
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM)));
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
// Register the socket object as our callback argument.
tcp_arg((struct tcp_pcb*)socket->pcb, (void*)socket);
tcp_arg(socket->pcb.tcp, (void*)socket);
// Register our error callback.
tcp_err((struct tcp_pcb*)socket->pcb, _lwip_tcp_error);
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((struct udp_pcb*)socket->pcb, _lwip_udp_incoming, (void*)socket);
udp_recv(socket->pcb.udp, _lwip_udp_incoming, (void*)socket);
break;
}
}
socket->incoming = NULL;
socket->incoming.pbuf = NULL;
socket->timeout = -1;
socket->connected = 0;
socket->leftover_count = 0;
@ -468,31 +473,31 @@ STATIC mp_obj_t lwip_socket_close(mp_obj_t self_in) {
lwip_socket_obj_t *socket = self_in;
bool socket_is_listener = false;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
return mp_const_none;
}
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
if (((struct tcp_pcb*)socket->pcb)->state == LISTEN) {
if (socket->pcb.tcp->state == LISTEN) {
socket_is_listener = true;
}
if (tcp_close((struct tcp_pcb*)socket->pcb) != ERR_OK) {
tcp_abort((struct tcp_pcb*)socket->pcb);
if (tcp_close(socket->pcb.tcp) != ERR_OK) {
tcp_abort(socket->pcb.tcp);
}
break;
}
case MOD_NETWORK_SOCK_DGRAM: udp_remove((struct udp_pcb*)socket->pcb); break;
//case MOD_NETWORK_SOCK_RAW: raw_remove((struct raw_pcb*)socket->pcb); break;
case MOD_NETWORK_SOCK_DGRAM: udp_remove(socket->pcb.udp); break;
//case MOD_NETWORK_SOCK_RAW: raw_remove(socket->pcb.raw); break;
}
socket->pcb = NULL;
socket->pcb.tcp = NULL;
socket->connected = -16; // EBADF
if (socket->incoming != NULL) {
if (socket->incoming.pbuf != NULL) {
if (!socket_is_listener) {
pbuf_free((struct pbuf*)socket->incoming);
pbuf_free(socket->incoming.pbuf);
} else {
tcp_abort((struct tcp_pcb*)socket->incoming);
tcp_abort(socket->incoming.connection);
}
socket->incoming = NULL;
socket->incoming.pbuf = NULL;
}
return mp_const_none;
@ -511,11 +516,11 @@ STATIC mp_obj_t lwip_socket_bind(mp_obj_t self_in, mp_obj_t addr_in) {
err_t err = ERR_ARG;
switch (socket->type) {
case MOD_NETWORK_SOCK_STREAM: {
err = tcp_bind((struct tcp_pcb*)socket->pcb, &bind_addr, port);
err = tcp_bind(socket->pcb.tcp, &bind_addr, port);
break;
}
case MOD_NETWORK_SOCK_DGRAM: {
err = udp_bind((struct udp_pcb*)socket->pcb, &bind_addr, port);
err = udp_bind(socket->pcb.udp, &bind_addr, port);
break;
}
}
@ -532,18 +537,18 @@ STATIC mp_obj_t lwip_socket_listen(mp_obj_t self_in, mp_obj_t backlog_in) {
lwip_socket_obj_t *socket = self_in;
mp_int_t backlog = mp_obj_get_int(backlog_in);
if (socket->pcb == NULL) {
if (socket->pcb.tcp == 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)));
}
struct tcp_pcb *new_pcb = tcp_listen_with_backlog((struct tcp_pcb*)socket->pcb, (u8_t)backlog);
struct tcp_pcb *new_pcb = tcp_listen_with_backlog(socket->pcb.tcp, (u8_t)backlog);
if (new_pcb == NULL) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ENOMEM)));
}
socket->pcb = (void*)new_pcb;
socket->pcb.tcp = new_pcb;
tcp_accept(new_pcb, _lwip_tcp_accept);
return mp_const_none;
@ -553,30 +558,30 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_2(lwip_socket_listen_obj, lwip_socket_listen);
STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
lwip_socket_obj_t *socket = self_in;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == 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;
struct tcp_pcb *listener = socket->pcb.tcp;
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->incoming.connection == 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.connection != NULL) break;
}
if (socket->incoming == NULL) {
if (socket->incoming.connection == NULL) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(ETIMEDOUT)));
}
} else {
while (socket->incoming == NULL) {
while (socket->incoming.connection == NULL) {
mp_hal_delay_ms(100);
}
}
@ -587,26 +592,26 @@ STATIC mp_obj_t lwip_socket_accept(mp_obj_t self_in) {
socket2->base.type = (mp_obj_t)&lwip_socket_type;
// We get a new pcb handle...
socket2->pcb = socket->incoming;
socket->incoming = NULL;
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 = NULL;
socket2->incoming.pbuf = 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_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, &(((struct tcp_pcb*)socket2->pcb)->remote_ip), 4);
mp_uint_t port = (mp_uint_t)((struct tcp_pcb*)socket2->pcb)->remote_port;
memcpy(ip, &(socket2->pcb.tcp->remote_ip), 4);
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);
@ -618,7 +623,7 @@ STATIC MP_DEFINE_CONST_FUN_OBJ_1(lwip_socket_accept_obj, lwip_socket_accept);
STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
lwip_socket_obj_t *socket = self_in;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(EBADF)));
}
@ -640,10 +645,10 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
}
}
// Register our recieve callback.
tcp_recv((struct tcp_pcb*)socket->pcb, _lwip_tcp_recv);
tcp_recv(socket->pcb.tcp, _lwip_tcp_recv);
// Mark us as "connecting"
socket->connected = 1;
err = tcp_connect((struct tcp_pcb*)socket->pcb, &dest, port, _lwip_tcp_connected);
err = tcp_connect(socket->pcb.tcp, &dest, port, _lwip_tcp_connected);
if (err != ERR_OK) {
socket->connected = 0;
nlr_raise(mp_obj_new_exception_arg1(&mp_type_OSError, MP_OBJ_NEW_SMALL_INT(error_lookup_table[-err])));
@ -672,7 +677,7 @@ STATIC mp_obj_t lwip_socket_connect(mp_obj_t self_in, mp_obj_t addr_in) {
break;
}
case MOD_NETWORK_SOCK_DGRAM: {
err = udp_connect((struct udp_pcb*)socket->pcb, &dest, port);
err = udp_connect(socket->pcb.udp, &dest, port);
break;
}
}
@ -689,7 +694,7 @@ STATIC mp_obj_t lwip_socket_send(mp_obj_t self_in, mp_obj_t buf_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->connected)];
socket->connected = -16;
@ -722,7 +727,7 @@ STATIC mp_obj_t lwip_socket_recv(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->connected)];
socket->connected = -16;
@ -760,7 +765,7 @@ STATIC mp_obj_t lwip_socket_sendto(mp_obj_t self_in, mp_obj_t data_in, mp_obj_t
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->connected)];
socket->connected = -16;
@ -796,7 +801,7 @@ STATIC mp_obj_t lwip_socket_recvfrom(mp_obj_t self_in, mp_obj_t len_in) {
lwip_socket_obj_t *socket = self_in;
int _errno;
if (socket->pcb == NULL) {
if (socket->pcb.tcp == NULL) {
// not connected
_errno = error_lookup_table[-(socket->connected)];
socket->connected = -16;