From 9c3c4a6f4bc7d065e34e3443dc905c7dc80ef71a Mon Sep 17 00:00:00 2001 From: cpq Date: Sat, 20 Aug 2022 00:03:15 +0100 Subject: [PATCH] MIP client --- examples/device-dashboard/net.c | 32 ++++++++++++ examples/stm32/nucleo-f746zg-baremetal/main.c | 35 +------------ mip/mip.c | 49 +++++++++++++------ mongoose.c | 49 +++++++++++++------ mongoose.h | 1 + 5 files changed, 105 insertions(+), 61 deletions(-) diff --git a/examples/device-dashboard/net.c b/examples/device-dashboard/net.c index ec6068b0..ec3c0e30 100644 --- a/examples/device-dashboard/net.c +++ b/examples/device-dashboard/net.c @@ -7,6 +7,16 @@ #define MQTT_PUBLISH_TOPIC "mg/my_device" #define MQTT_SUBSCRIBE_TOPIC "mg/#" +static time_t s_boot_timestamp = 0; // Updated by SNTP +static struct mg_connection *s_sntp_conn = NULL; // SNTP connection + +// Define system time() +time_t time(time_t *tp) { + time_t t = s_boot_timestamp + (time_t) (mg_millis() / 1000); + if (tp != NULL) *tp = t; + return t; +} + // Authenticated user. // A user can be authenticated by: // - a name:pass pair @@ -117,12 +127,34 @@ static void timer_mqtt_fn(void *param) { } } +// SNTP connection event handler. When we get a response from an SNTP server, +// adjust s_boot_timestamp. We'll get a valid time from that point on +static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { + if (ev == MG_EV_SNTP_TIME) { + uint64_t t = *(uint64_t *) ev_data; + MG_INFO(("%lu SNTP: %lld ms from epoch", c->id, t)); + s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); + c->is_closing = 1; + } else if (ev == MG_EV_CLOSE) { + s_sntp_conn = NULL; + } + (void) fn_data; +} + +static void timer_sntp_fn(void *param) { // SNTP timer function. Sync up time + struct mg_mgr *mgr = (struct mg_mgr *) param; + if (s_sntp_conn == NULL && s_boot_timestamp == 0) { + s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); + } +} + // HTTP request handler function void device_dashboard_fn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { if (ev == MG_EV_OPEN && c->is_listening) { mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_metrics_fn, c->mgr); mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_mqtt_fn, c->mgr); + mg_timer_add(c->mgr, 1000, MG_TIMER_REPEAT, timer_sntp_fn, c->mgr); s_config.url = strdup(MQTT_SERVER); s_config.pub = strdup(MQTT_PUBLISH_TOPIC); s_config.sub = strdup(MQTT_SUBSCRIBE_TOPIC); diff --git a/examples/stm32/nucleo-f746zg-baremetal/main.c b/examples/stm32/nucleo-f746zg-baremetal/main.c index 65883dc5..2af2c316 100644 --- a/examples/stm32/nucleo-f746zg-baremetal/main.c +++ b/examples/stm32/nucleo-f746zg-baremetal/main.c @@ -9,40 +9,10 @@ #define LED3 PIN('B', 14) // On-board LED pin (red) #define BTN1 PIN('C', 13) // On-board user button -static uint64_t s_ticks, s_exti; // Counters, increased by IRQ handlers -static time_t s_boot_timestamp = 0; // Updated by SNTP -static struct mg_connection *s_sntp_conn = NULL; // SNTP connection - -// We have no valid system time(), and we need it for TLS. Implement it -time_t time(time_t *tp) { - time_t t = s_boot_timestamp + (time_t) (mg_millis() / 1000); - if (tp != NULL) *tp = t; - return t; -} - -// SNTP connection event handler. When we get a response from an SNTP server, -// adjust s_boot_timestamp. We'll get a valid time from that point on -static void sfn(struct mg_connection *c, int ev, void *ev_data, void *fn_data) { - if (ev == MG_EV_SNTP_TIME) { - uint64_t t = *(uint64_t *) ev_data; - MG_INFO(("%lu SNTP: %lld ms from epoch", c->id, t)); - s_boot_timestamp = (time_t) ((t - mg_millis()) / 1000); - c->is_closing = 1; - } else if (ev == MG_EV_CLOSE) { - s_sntp_conn = NULL; - } - (void) fn_data; -} - -static void sntp_cb(void *param) { // SNTP timer function. Sync up time - struct mg_mgr *mgr = (struct mg_mgr *) param; - if (s_sntp_conn == NULL && s_boot_timestamp == 0) { - s_sntp_conn = mg_sntp_connect(mgr, NULL, sfn, NULL); - } -} +static uint64_t s_ticks, s_exti; // Counters, increased by IRQ handlers static void blink_cb(void *arg) { // Blink periodically - MG_INFO(("ticks: %u", (unsigned) s_ticks)); + // MG_INFO(("ticks: %u", (unsigned) s_ticks)); gpio_toggle(LED2); (void) arg; } @@ -96,7 +66,6 @@ int main(void) { mg_mgr_init(&mgr); // and attach it to the MIP interface mg_log_set(MG_LL_DEBUG); // Set log level mg_timer_add(&mgr, 1000, MG_TIMER_REPEAT, blink_cb, &mgr); - mg_timer_add(&mgr, 5000, MG_TIMER_REPEAT, sntp_cb, &mgr); // Initialise Mongoose network stack // Specify MAC address, and use 0 for IP, mask, GW - i.e. use DHCP diff --git a/mip/mip.c b/mip/mip.c index 654f791b..acb4f2ea 100644 --- a/mip/mip.c +++ b/mip/mip.c @@ -380,7 +380,7 @@ static void rx_arp(struct mip_if *ifp, struct pkt *pkt) { // ARP request. Make a response, then send struct eth *eth = (struct eth *) ifp->tx.buf; struct arp *arp = (struct arp *) (eth + 1); - MG_DEBUG(("ARP op %d %#x %#x\n", NET16(arp->op), arp->spa, arp->tpa)); + MG_DEBUG(("ARP op %d %#x %#x", NET16(arp->op), arp->spa, arp->tpa)); memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); memcpy(eth->src, ifp->mac, sizeof(eth->src)); eth->type = NET16(0x806); @@ -563,11 +563,19 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) { #if 0 MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); #endif - if (c != NULL) { + if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) { + struct tcpstate *s = (struct tcpstate *) (c + 1); + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; + tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); + c->is_connecting = 0; // Client connected + } else if (c != NULL && c->is_connecting) { + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (c != NULL) { #if 0 - MG_DEBUG(("%lu %d %lx:%hx -> %lx:%hx", c->id, (int) pkt->raw.len, - pkt->ip->src, pkt->tcp->sport, pkt->ip->dst, pkt->tcp->dport)); - hexdump(pkt->pay.buf, pkt->pay.len); + MG_DEBUG(("%lu %d %lx:%hu -> %lx:%hu", c->id, (int) pkt->raw.len, + mg_ntohl(pkt->ip->src), mg_ntohs(pkt->tcp->sport), + mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport))); + mg_hexdump(pkt->pay.buf, pkt->pay.len); #endif read_conn(c, pkt); } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { @@ -730,22 +738,31 @@ int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) { return -1; } +#if 0 +static uint16_t mkeport(void) { + uint16_t a = 0, b = mg_millis() & 0xffffU, c = MIP_ETHEMERAL_PORT; + mg_random(&a, sizeof(a)); + c += (a ^ b) % (0xffffU - MIP_ETHEMERAL_PORT); + return c; +} +#endif + void mg_connect_resolved(struct mg_connection *c) { struct mip_if *ifp = (struct mip_if *) c->mgr->priv; c->is_resolving = 0; if (ifp->eport < MIP_ETHEMERAL_PORT) ifp->eport = MIP_ETHEMERAL_PORT; + c->loc.ip = ifp->ip; + c->loc.port = mg_htons(ifp->eport++); + MG_DEBUG(("%lu %08lx.%hu->%08lx.%hu", c->id, mg_ntohl(c->loc.ip), + mg_ntohs(c->loc.port), mg_ntohl(c->rem.ip), mg_ntohs(c->rem.port))); + mg_call(c, MG_EV_RESOLVE, NULL); if (c->is_udp) { - c->loc.ip = ifp->ip; - c->loc.port = mg_htons(ifp->eport++); - MG_DEBUG(("%lu %08lx.%hu->%08lx.%hu", c->id, mg_ntohl(c->loc.ip), - mg_ntohs(c->loc.port), mg_ntohl(c->rem.ip), - mg_ntohs(c->rem.port))); - mg_call(c, MG_EV_RESOLVE, NULL); mg_call(c, MG_EV_CONNECT, NULL); } else { - mg_error(c, "Not implemented"); + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); + tx_tcp(ifp, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, 0); + c->is_connecting = 1; } - c->is_resolving = 0; } bool mg_open_listener(struct mg_connection *c, const char *url) { @@ -774,6 +791,10 @@ static void fin_conn(struct mg_connection *c) { mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); } +static bool can_write(struct mg_connection *c) { + return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0; +} + void mg_mgr_poll(struct mg_mgr *mgr, int ms) { struct mg_connection *c, *tmp; uint64_t now = mg_millis(); @@ -781,7 +802,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { mg_timer_poll(&mgr->timers, now); for (c = mgr->conns; c != NULL; c = tmp) { tmp = c->next; - if (c->send.len > 0) write_conn(c); + if (can_write(c)) write_conn(c); if (c->is_draining && c->send.len == 0) c->is_closing = 1; if (c->is_closing) { if (c->is_udp == false && c->is_listening == false) fin_conn(c); diff --git a/mongoose.c b/mongoose.c index 7186494e..3b75c5dd 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6474,7 +6474,7 @@ static void rx_arp(struct mip_if *ifp, struct pkt *pkt) { // ARP request. Make a response, then send struct eth *eth = (struct eth *) ifp->tx.buf; struct arp *arp = (struct arp *) (eth + 1); - MG_DEBUG(("ARP op %d %#x %#x\n", NET16(arp->op), arp->spa, arp->tpa)); + MG_DEBUG(("ARP op %d %#x %#x", NET16(arp->op), arp->spa, arp->tpa)); memcpy(eth->dst, pkt->eth->src, sizeof(eth->dst)); memcpy(eth->src, ifp->mac, sizeof(eth->src)); eth->type = NET16(0x806); @@ -6657,11 +6657,19 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) { #if 0 MG_INFO(("%lu %hhu %d", c ? c->id : 0, pkt->tcp->flags, (int) pkt->pay.len)); #endif - if (c != NULL) { + if (c != NULL && c->is_connecting && pkt->tcp->flags & (TH_SYN | TH_ACK)) { + struct tcpstate *s = (struct tcpstate *) (c + 1); + s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq) + 1; + tx_tcp_pkt(ifp, pkt, TH_ACK, pkt->tcp->ack, NULL, 0); + c->is_connecting = 0; // Client connected + } else if (c != NULL && c->is_connecting) { + tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); + } else if (c != NULL) { #if 0 - MG_DEBUG(("%lu %d %lx:%hx -> %lx:%hx", c->id, (int) pkt->raw.len, - pkt->ip->src, pkt->tcp->sport, pkt->ip->dst, pkt->tcp->dport)); - hexdump(pkt->pay.buf, pkt->pay.len); + MG_DEBUG(("%lu %d %lx:%hu -> %lx:%hu", c->id, (int) pkt->raw.len, + mg_ntohl(pkt->ip->src), mg_ntohs(pkt->tcp->sport), + mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport))); + mg_hexdump(pkt->pay.buf, pkt->pay.len); #endif read_conn(c, pkt); } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { @@ -6824,22 +6832,31 @@ int mg_mkpipe(struct mg_mgr *m, mg_event_handler_t fn, void *d, bool udp) { return -1; } +#if 0 +static uint16_t mkeport(void) { + uint16_t a = 0, b = mg_millis() & 0xffffU, c = MIP_ETHEMERAL_PORT; + mg_random(&a, sizeof(a)); + c += (a ^ b) % (0xffffU - MIP_ETHEMERAL_PORT); + return c; +} +#endif + void mg_connect_resolved(struct mg_connection *c) { struct mip_if *ifp = (struct mip_if *) c->mgr->priv; c->is_resolving = 0; if (ifp->eport < MIP_ETHEMERAL_PORT) ifp->eport = MIP_ETHEMERAL_PORT; + c->loc.ip = ifp->ip; + c->loc.port = mg_htons(ifp->eport++); + MG_DEBUG(("%lu %08lx.%hu->%08lx.%hu", c->id, mg_ntohl(c->loc.ip), + mg_ntohs(c->loc.port), mg_ntohl(c->rem.ip), mg_ntohs(c->rem.port))); + mg_call(c, MG_EV_RESOLVE, NULL); if (c->is_udp) { - c->loc.ip = ifp->ip; - c->loc.port = mg_htons(ifp->eport++); - MG_DEBUG(("%lu %08lx.%hu->%08lx.%hu", c->id, mg_ntohl(c->loc.ip), - mg_ntohs(c->loc.port), mg_ntohl(c->rem.ip), - mg_ntohs(c->rem.port))); - mg_call(c, MG_EV_RESOLVE, NULL); mg_call(c, MG_EV_CONNECT, NULL); } else { - mg_error(c, "Not implemented"); + uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); + tx_tcp(ifp, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, 0); + c->is_connecting = 1; } - c->is_resolving = 0; } bool mg_open_listener(struct mg_connection *c, const char *url) { @@ -6868,6 +6885,10 @@ static void fin_conn(struct mg_connection *c) { mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); } +static bool can_write(struct mg_connection *c) { + return c->is_connecting == 0 && c->is_resolving == 0 && c->send.len > 0; +} + void mg_mgr_poll(struct mg_mgr *mgr, int ms) { struct mg_connection *c, *tmp; uint64_t now = mg_millis(); @@ -6875,7 +6896,7 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) { mg_timer_poll(&mgr->timers, now); for (c = mgr->conns; c != NULL; c = tmp) { tmp = c->next; - if (c->send.len > 0) write_conn(c); + if (can_write(c)) write_conn(c); if (c->is_draining && c->send.len == 0) c->is_closing = 1; if (c->is_closing) { if (c->is_udp == false && c->is_listening == false) fin_conn(c); diff --git a/mongoose.h b/mongoose.h index b56d93bb..c4e06ec9 100644 --- a/mongoose.h +++ b/mongoose.h @@ -202,6 +202,7 @@ static inline void *mg_calloc(int cnt, size_t size) { #define calloc(a, b) mg_calloc((a), (b)) #define free(a) vPortFree(a) #define malloc(a) pvPortMalloc(a) +#define strdup(s) ((char *) mg_strdup(mg_str(s)).ptr) #define mkdir(a, b) (-1) #ifndef MG_IO_SIZE