mirror of
https://github.com/cesanta/mongoose.git
synced 2025-01-14 01:38:01 +08:00
LWIP: (Ab)use mg_conection.priv_2 to pass input interface address
This is required to distinguish input interface for multicast traffic and select correct output interface for outgoing traffic (advertisements). http://savannah.nongnu.org/bugs/?49662 removed ability to receive multicast traffic on on interface-bound sockets (making the previous change useless, hence the revert), so for LWIP 2.0.1 and newer multicast packets can only be received on INADDR_ANY listeners. User is then required to distinguish input interface in the receive path. This information is only available in the udp_recv callback, so we must pass this down to dns-sd library somehow, and priv_2 is the how. It is normally used for DNS resolver state, and is never used on listening sockets. We thus avoid growing the mg_connection structure.
This commit is contained in:
parent
e3a140c9a7
commit
da1e5438bd
46
mongoose.c
46
mongoose.c
@ -2907,10 +2907,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
|
||||
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
|
||||
}
|
||||
}
|
||||
/* Copy input interface address. */
|
||||
if (nc != NULL) nc->priv_2 = lc->priv_2;
|
||||
}
|
||||
if (nc != NULL) {
|
||||
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
|
||||
ntohs(nc->sa.sin.sin_port)));
|
||||
DBG(("%p <- %d bytes from %s:%d ia %#x", nc, n,
|
||||
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port),
|
||||
(int) (intptr_t) nc->priv_2));
|
||||
if (nc == lc) {
|
||||
nc->recv_mbuf.len += n;
|
||||
} else {
|
||||
@ -15171,6 +15174,11 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc,
|
||||
mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
|
||||
}
|
||||
|
||||
struct udp_info {
|
||||
union socket_address remote_addr;
|
||||
uint32_t local_ip4;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lwip included in the SDKs for nRF5x chips has different type for the
|
||||
* callback of `udp_recv()`
|
||||
@ -15187,18 +15195,22 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||
DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
|
||||
/* Put address in a separate pbuf and tack it onto the packet. */
|
||||
struct pbuf *sap =
|
||||
pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
|
||||
pbuf_alloc(PBUF_RAW, sizeof(struct udp_info), PBUF_RAM);
|
||||
if (sap == NULL) {
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
union socket_address *sa = (union socket_address *) sap->payload;
|
||||
struct udp_info *ui = (struct udp_info *) sap->payload;
|
||||
struct netif *nif = ip_current_netif();
|
||||
#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
|
||||
sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
|
||||
ui->remote_addr.sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
|
||||
ui->local_ip4 = ip_2_ip4(&nif->ip_addr)->addr;
|
||||
#else
|
||||
sa->sin.sin_addr.s_addr = addr->addr;
|
||||
ui->remote_addr.sin.sin_addr.s_addr = addr->addr;
|
||||
ui->local_ip4 = nif->ip_addr.addr;
|
||||
#endif
|
||||
sa->sin.sin_port = htons(port);
|
||||
ui->remote_addr.sin.sin_port = htons(port);
|
||||
|
||||
/* Logic in the recv handler requires that there be exactly one data pbuf. */
|
||||
p = pbuf_coalesce(p, PBUF_RAW);
|
||||
pbuf_chain(sap, p);
|
||||
@ -15238,6 +15250,13 @@ static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
|
||||
res = MIN(dp->len, len);
|
||||
pbuf_copy_partial(dp, buf, res, 0);
|
||||
pbuf_free(dp);
|
||||
const struct udp_info *ui = (struct udp_info *) ap->payload;
|
||||
*sa = ui->remote_addr;
|
||||
/* Store local interface address for incoming packets.
|
||||
* Only for listener because outgoing connections may use priv_2 for DNS. */
|
||||
if (nc->listener == NULL) {
|
||||
nc->priv_2 = (void *) (uintptr_t) ui->local_ip4;
|
||||
}
|
||||
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
|
||||
pbuf_free(ap);
|
||||
}
|
||||
@ -15451,11 +15470,19 @@ struct udp_sendto_ctx {
|
||||
struct pbuf *p;
|
||||
ip_addr_t *ip;
|
||||
uint16_t port;
|
||||
uint32_t mcast_ip4;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void udp_sendto_tcpip(void *arg) {
|
||||
struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
|
||||
if (ctx->mcast_ip4 != 0) {
|
||||
#if LWIP_VERSION_MAJOR > 1 && LWIP_MULTICAST_TX_OPTIONS
|
||||
ctx->upcb->mcast_ip4.addr = ctx->mcast_ip4;
|
||||
#elif LWIP_VERSION_MAJOR == 1 && LWIP_IGMP
|
||||
ctx->upcb->multicast_ip.addr = ctx->mcast_ip4;
|
||||
#endif
|
||||
}
|
||||
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
|
||||
}
|
||||
|
||||
@ -15474,8 +15501,13 @@ static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
|
||||
if (p == NULL) return 0;
|
||||
memcpy(p->payload, data, len);
|
||||
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
|
||||
if (ip_addr_ismulticast(&ip)) {
|
||||
ctx.mcast_ip4 = (uint32_t) (uintptr_t) nc->priv_2;
|
||||
}
|
||||
mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
|
||||
cs->err = ctx.ret;
|
||||
DBG(("%p udp_sendto %x mc4 %x res %d", nc, (int) ip_2_ip4(ctx.ip)->addr,
|
||||
(int) ctx.mcast_ip4, (int) cs->err));
|
||||
pbuf_free(p);
|
||||
return (cs->err == ERR_OK ? (int) len : -2);
|
||||
}
|
||||
|
@ -250,6 +250,11 @@ void mg_lwip_if_connect_tcp(struct mg_connection *nc,
|
||||
mg_lwip_netif_run_on_tcpip(mg_lwip_if_connect_tcp_tcpip, &ctx);
|
||||
}
|
||||
|
||||
struct udp_info {
|
||||
union socket_address remote_addr;
|
||||
uint32_t local_ip4;
|
||||
};
|
||||
|
||||
/*
|
||||
* Lwip included in the SDKs for nRF5x chips has different type for the
|
||||
* callback of `udp_recv()`
|
||||
@ -266,18 +271,22 @@ static void mg_lwip_udp_recv_cb(void *arg, struct udp_pcb *pcb, struct pbuf *p,
|
||||
DBG(("%p %s:%u %p %u %u", nc, IPADDR_NTOA(addr), port, p, p->ref, p->len));
|
||||
/* Put address in a separate pbuf and tack it onto the packet. */
|
||||
struct pbuf *sap =
|
||||
pbuf_alloc(PBUF_RAW, sizeof(union socket_address), PBUF_RAM);
|
||||
pbuf_alloc(PBUF_RAW, sizeof(struct udp_info), PBUF_RAM);
|
||||
if (sap == NULL) {
|
||||
pbuf_free(p);
|
||||
return;
|
||||
}
|
||||
union socket_address *sa = (union socket_address *) sap->payload;
|
||||
struct udp_info *ui = (struct udp_info *) sap->payload;
|
||||
struct netif *nif = ip_current_netif();
|
||||
#if ((LWIP_VERSION_MAJOR << 8) | LWIP_VERSION_MINOR) >= 0x0105
|
||||
sa->sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
|
||||
ui->remote_addr.sin.sin_addr.s_addr = ip_2_ip4(addr)->addr;
|
||||
ui->local_ip4 = ip_2_ip4(&nif->ip_addr)->addr;
|
||||
#else
|
||||
sa->sin.sin_addr.s_addr = addr->addr;
|
||||
ui->remote_addr.sin.sin_addr.s_addr = addr->addr;
|
||||
ui->local_ip4 = nif->ip_addr.addr;
|
||||
#endif
|
||||
sa->sin.sin_port = htons(port);
|
||||
ui->remote_addr.sin.sin_port = htons(port);
|
||||
|
||||
/* Logic in the recv handler requires that there be exactly one data pbuf. */
|
||||
p = pbuf_coalesce(p, PBUF_RAW);
|
||||
pbuf_chain(sap, p);
|
||||
@ -317,6 +326,13 @@ static int mg_lwip_if_udp_recv(struct mg_connection *nc, void *buf, size_t len,
|
||||
res = MIN(dp->len, len);
|
||||
pbuf_copy_partial(dp, buf, res, 0);
|
||||
pbuf_free(dp);
|
||||
const struct udp_info *ui = (struct udp_info *) ap->payload;
|
||||
*sa = ui->remote_addr;
|
||||
/* Store local interface address for incoming packets.
|
||||
* Only for listener because outgoing connections may use priv_2 for DNS. */
|
||||
if (nc->listener == NULL) {
|
||||
nc->priv_2 = (void *) (uintptr_t) ui->local_ip4;
|
||||
}
|
||||
pbuf_copy_partial(ap, sa, MIN(*sa_len, ap->len), 0);
|
||||
pbuf_free(ap);
|
||||
}
|
||||
@ -530,11 +546,19 @@ struct udp_sendto_ctx {
|
||||
struct pbuf *p;
|
||||
ip_addr_t *ip;
|
||||
uint16_t port;
|
||||
uint32_t mcast_ip4;
|
||||
int ret;
|
||||
};
|
||||
|
||||
static void udp_sendto_tcpip(void *arg) {
|
||||
struct udp_sendto_ctx *ctx = (struct udp_sendto_ctx *) arg;
|
||||
if (ctx->mcast_ip4 != 0) {
|
||||
#if LWIP_VERSION_MAJOR > 1 && LWIP_MULTICAST_TX_OPTIONS
|
||||
ctx->upcb->mcast_ip4.addr = ctx->mcast_ip4;
|
||||
#elif LWIP_VERSION_MAJOR == 1 && LWIP_IGMP
|
||||
ctx->upcb->multicast_ip.addr = ctx->mcast_ip4;
|
||||
#endif
|
||||
}
|
||||
ctx->ret = udp_sendto(ctx->upcb, ctx->p, ctx->ip, ctx->port);
|
||||
}
|
||||
|
||||
@ -553,8 +577,13 @@ static int mg_lwip_if_udp_send(struct mg_connection *nc, const void *data,
|
||||
if (p == NULL) return 0;
|
||||
memcpy(p->payload, data, len);
|
||||
struct udp_sendto_ctx ctx = {.upcb = upcb, .p = p, .ip = &ip, .port = port};
|
||||
if (ip_addr_ismulticast(&ip)) {
|
||||
ctx.mcast_ip4 = (uint32_t) (uintptr_t) nc->priv_2;
|
||||
}
|
||||
mg_lwip_netif_run_on_tcpip(udp_sendto_tcpip, &ctx);
|
||||
cs->err = ctx.ret;
|
||||
DBG(("%p udp_sendto %x mc4 %x res %d", nc, (int) ip_2_ip4(ctx.ip)->addr,
|
||||
(int) ctx.mcast_ip4, (int) cs->err));
|
||||
pbuf_free(p);
|
||||
return (cs->err == ERR_OK ? (int) len : -2);
|
||||
}
|
||||
|
@ -680,10 +680,13 @@ static int mg_recv_udp(struct mg_connection *nc, char *buf, size_t len) {
|
||||
mg_call(nc, NULL, nc->user_data, MG_EV_ACCEPT, &nc->sa);
|
||||
}
|
||||
}
|
||||
/* Copy input interface address. */
|
||||
if (nc != NULL) nc->priv_2 = lc->priv_2;
|
||||
}
|
||||
if (nc != NULL) {
|
||||
DBG(("%p <- %d bytes from %s:%d", nc, n, inet_ntoa(nc->sa.sin.sin_addr),
|
||||
ntohs(nc->sa.sin.sin_port)));
|
||||
DBG(("%p <- %d bytes from %s:%d ia %#x", nc, n,
|
||||
inet_ntoa(nc->sa.sin.sin_addr), ntohs(nc->sa.sin.sin_port),
|
||||
(int) (intptr_t) nc->priv_2));
|
||||
if (nc == lc) {
|
||||
nc->recv_mbuf.len += n;
|
||||
} else {
|
||||
|
Loading…
x
Reference in New Issue
Block a user