Skip to content

Commit bd16d64

Browse files
committed
Merge pull request #1666 from pguyot/w20/add-support-for-loopback-on-rp2
Add support to connect to loopback address on RP2 platform These changes are made under both the "Apache 2.0" and the "GNU Lesser General Public License 2.1 or later" license terms (dual license). SPDX-License-Identifier: Apache-2.0 OR LGPL-2.1-or-later
2 parents cdef344 + fbc52e8 commit bd16d64

File tree

4 files changed

+59
-1
lines changed

4 files changed

+59
-1
lines changed

libs/estdlib/src/socket.erl

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -400,7 +400,7 @@ recv0(Socket, Length, Timeout) ->
400400

401401
recv0_nowait(Socket, Length, Ref) ->
402402
case ?MODULE:nif_recv(Socket, Length) of
403-
{error, timeout} ->
403+
{error, Reason} when Reason =:= timeout orelse Reason =:= eagain ->
404404
case ?MODULE:nif_select_read(Socket, Ref) of
405405
ok ->
406406
{select, {select_info, recv, Ref}};

src/libAtomVM/otp_socket.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ struct UDPReceivedItem
146146

147147
static err_t tcp_recv_cb(void *arg, struct tcp_pcb *tpcb, struct pbuf *p, err_t err);
148148
static void udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip_addr_t *addr, u16_t port);
149+
static void tcp_err_cb(void *arg, err_t err);
149150

150151
#endif
151152

@@ -620,6 +621,7 @@ static term nif_socket_open(Context *ctx, int argc, term argv[])
620621
if (rsrc_obj->socket_state & SocketStateTCP) {
621622
LWIP_BEGIN();
622623
tcp_arg(rsrc_obj->tcp_pcb, rsrc_obj);
624+
tcp_err(rsrc_obj->tcp_pcb, tcp_err_cb);
623625
tcp_recv(rsrc_obj->tcp_pcb, tcp_recv_cb);
624626
LWIP_END();
625627
} else {
@@ -996,6 +998,23 @@ static void udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p, const ip
996998
otp_socket_lwip_enqueue(&event);
997999
} // Otherwise socket was closed.
9981000
}
1001+
1002+
// LwIP tcpip_try_callback uses queue.
1003+
static void tcpip_try_callback_handler(struct LWIPEvent *event)
1004+
{
1005+
event->tcpip_try_callback.function(event->tcpip_try_callback.ctx);
1006+
}
1007+
1008+
int tcpip_try_callback(tcpip_callback_fn function, void *ctx)
1009+
{
1010+
struct LWIPEvent event;
1011+
event.handler = tcpip_try_callback_handler;
1012+
event.tcpip_try_callback.function = function;
1013+
event.tcpip_try_callback.ctx = ctx;
1014+
otp_socket_lwip_enqueue(&event);
1015+
return ERR_OK;
1016+
}
1017+
9991018
#endif
10001019

10011020
static term nif_socket_select_read(Context *ctx, int argc, term argv[])
@@ -2639,6 +2658,25 @@ static err_t tcp_connected_cb(void *arg, struct tcp_pcb *tpcb, err_t err)
26392658
} // else: sender died
26402659
return ERR_OK;
26412660
}
2661+
2662+
static void tcp_err_cb(void *arg, err_t err)
2663+
{
2664+
UNUSED(err);
2665+
2666+
struct SocketResource *rsrc_obj = (struct SocketResource *) arg;
2667+
struct RefcBinary *rsrc_refc = refc_binary_from_data(rsrc_obj);
2668+
GlobalContext *global = rsrc_refc->resource_type->global;
2669+
int32_t target_pid = rsrc_obj->selecting_process_id;
2670+
rsrc_obj->selecting_process_id = INVALID_PROCESS_ID;
2671+
rsrc_obj->socket_state = SocketStateTCPConnected;
2672+
if (target_pid != INVALID_PROCESS_ID) {
2673+
struct LWIPEvent event;
2674+
event.handler = trap_answer_closed;
2675+
event.trap_answer_closed.global = global;
2676+
event.trap_answer_closed.target_pid = target_pid;
2677+
otp_socket_lwip_enqueue(&event);
2678+
} // else: sender died
2679+
}
26422680
#endif
26432681

26442682
static term nif_socket_connect(Context *ctx, int argc, term argv[])
@@ -2741,6 +2779,9 @@ static term nif_socket_connect(Context *ctx, int argc, term argv[])
27412779
LWIP_END();
27422780

27432781
if (UNLIKELY(err != ERR_OK)) {
2782+
if (err == ERR_USE || err == ERR_RTE) {
2783+
return make_error_tuple(CLOSED_ATOM, ctx);
2784+
}
27442785
RAISE_ERROR(OUT_OF_MEMORY_ATOM);
27452786
}
27462787
if (rsrc_obj->socket_state & SocketStateUDP) {

src/libAtomVM/otp_socket.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,11 @@ struct LWIPEvent
131131
{
132132
struct SocketResource *rsrc_obj;
133133
} finalize_close;
134+
struct
135+
{
136+
tcpip_callback_fn function;
137+
void *ctx;
138+
} tcpip_try_callback;
134139
// Used by otp_net
135140
struct
136141
{

src/platforms/rp2/src/lib/lwipopts.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,4 +107,16 @@ void sntp_set_system_time_us(unsigned long sec, unsigned long usec);
107107
#define SNTP_SET_SYSTEM_TIME_US(sec, usec) sntp_set_system_time_us(sec, usec)
108108

109109
#define TCP_LISTEN_BACKLOG 1
110+
111+
#define LWIP_NETIF_LOOPBACK 1
112+
#define LWIP_NETIF_LOOPBACK_MULTITHREADING 1
113+
#define LWIP_HAVE_LOOPIF 0
114+
115+
// To support loopback, we implement our own version of tcpip_try_callback that
116+
// enqueues a call to netif_poll.
117+
struct netif;
118+
void netif_poll(struct netif *netif);
119+
typedef void (*tcpip_callback_fn)(void *ctx);
120+
int tcpip_try_callback(tcpip_callback_fn function, void *ctx);
121+
110122
#endif /* __LWIPOPTS_H__ */

0 commit comments

Comments
 (0)