diff --git a/mongoose.c b/mongoose.c index 705b093a0f..549242fb1c 100644 --- a/mongoose.c +++ b/mongoose.c @@ -5827,11 +5827,16 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { if (expired_1000ms && ifp->driver->up) { bool up = ifp->driver->up(ifp); bool current = ifp->state != MG_TCPIP_STATE_DOWN; - if (up != current) { - ifp->state = up == false ? MG_TCPIP_STATE_DOWN - : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP - : MG_TCPIP_STATE_READY; - if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (up != current) { // link state has changed + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client || ifp->ip == 0 + ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_READY; + onstatechange(ifp); + } else if (!ifp->enable_dhcp_client && ifp->state == MG_TCPIP_STATE_UP && + ifp->ip) { + ifp->state = MG_TCPIP_STATE_READY; // ifp->fn has set an IP onstatechange(ifp); } if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); @@ -5840,18 +5845,20 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { if (ifp->state == MG_TCPIP_STATE_DOWN) return; // DHCP RFC-2131 (4.4) - if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { - tx_dhcp_discover(ifp); // INIT (4.4.1) - } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && - ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING - if (ifp->now >= ifp->lease_expire) { - ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP - onstatechange(ifp); - } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && - ((ifp->now / 1000) % 60) == 0) { - // hack: 30 min before deadline, try to rebind (4.3.6) every min - tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); - } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + if (ifp->enable_dhcp_client && expired_1000ms) { + if (ifp->state == MG_TCPIP_STATE_UP) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } } // Read data from the network diff --git a/src/net_builtin.c b/src/net_builtin.c index 9bd2a18acc..6e1fffdd2e 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -905,11 +905,16 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { if (expired_1000ms && ifp->driver->up) { bool up = ifp->driver->up(ifp); bool current = ifp->state != MG_TCPIP_STATE_DOWN; - if (up != current) { - ifp->state = up == false ? MG_TCPIP_STATE_DOWN - : ifp->enable_dhcp_client ? MG_TCPIP_STATE_UP - : MG_TCPIP_STATE_READY; - if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (!up && ifp->enable_dhcp_client) ifp->ip = 0; + if (up != current) { // link state has changed + ifp->state = up == false ? MG_TCPIP_STATE_DOWN + : ifp->enable_dhcp_client || ifp->ip == 0 + ? MG_TCPIP_STATE_UP + : MG_TCPIP_STATE_READY; + onstatechange(ifp); + } else if (!ifp->enable_dhcp_client && ifp->state == MG_TCPIP_STATE_UP && + ifp->ip) { + ifp->state = MG_TCPIP_STATE_READY; // ifp->fn has set an IP onstatechange(ifp); } if (ifp->state == MG_TCPIP_STATE_DOWN) MG_ERROR(("Network is down")); @@ -918,18 +923,20 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { if (ifp->state == MG_TCPIP_STATE_DOWN) return; // DHCP RFC-2131 (4.4) - if (ifp->state == MG_TCPIP_STATE_UP && expired_1000ms) { - tx_dhcp_discover(ifp); // INIT (4.4.1) - } else if (expired_1000ms && ifp->state == MG_TCPIP_STATE_READY && - ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING - if (ifp->now >= ifp->lease_expire) { - ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP - onstatechange(ifp); - } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && - ((ifp->now / 1000) % 60) == 0) { - // hack: 30 min before deadline, try to rebind (4.3.6) every min - tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); - } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + if (ifp->enable_dhcp_client && expired_1000ms) { + if (ifp->state == MG_TCPIP_STATE_UP) { + tx_dhcp_discover(ifp); // INIT (4.4.1) + } else if (ifp->state == MG_TCPIP_STATE_READY && + ifp->lease_expire > 0) { // BOUND / RENEWING / REBINDING + if (ifp->now >= ifp->lease_expire) { + ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; // expired, release IP + onstatechange(ifp); + } else if (ifp->now + 30UL * 60UL * 1000UL > ifp->lease_expire && + ((ifp->now / 1000) % 60) == 0) { + // hack: 30 min before deadline, try to rebind (4.3.6) every min + tx_dhcp_request_re(ifp, (uint8_t *) broadcast, ifp->ip, 0xffffffff); + } // TODO(): Handle T1 (RENEWING) and T2 (REBINDING) (4.4.5) + } } // Read data from the network diff --git a/tutorials/tcpip/pcap-driver/main.c b/tutorials/tcpip/pcap-driver/main.c index 7e93e79f8d..01beacf1f9 100644 --- a/tutorials/tcpip/pcap-driver/main.c +++ b/tutorials/tcpip/pcap-driver/main.c @@ -165,6 +165,8 @@ static void http_ev_handler(struct mg_connection *c, int ev, void *ev_data) { (void) ev_data; } +static struct mg_connection *mqtt_conn = NULL; + static void mqtt_ev_handler(struct mg_connection *c, int ev, void *ev_data) { if (ev == MG_EV_OPEN) { MG_INFO(("%lu CREATED", c->id)); @@ -189,36 +191,58 @@ static void mqtt_ev_handler(struct mg_connection *c, int ev, void *ev_data) { mm->data.buf, (int) mm->topic.len, mm->topic.buf)); } else if (ev == MG_EV_CLOSE) { MG_INFO(("%lu CLOSED", c->id)); + mqtt_conn = NULL; // Mark that we're closed } } static void if_ev_handler(struct mg_tcpip_if *ifp, int ev, void *ev_data) { - static uint32_t ip = 0; - static unsigned counter = 0; - - // Set initial self-assigned IP - if (ip == 0) ip = MG_IPV4(169, 254, 2, 100); - - // Catch ARP packets. Parse them yourself, that's easy. - if (ev == MG_TCPIP_EV_ARP) { - struct mg_str *frame = ev_data; - MG_INFO(("Iface %p: Got ARP frame", ifp)); - mg_hexdump(frame->buf, frame->len); - // TODO: check for conflict. On conflict, increment ip and reset counter + // Trigger MQTT connection when we have an IP address + if (ifp->state == MG_TCPIP_STATE_READY && + (ev == MG_TCPIP_EV_ST_CHG || ev == MG_TCPIP_EV_TIMER_1S)) { + struct mg_mqtt_opts opts = {.clean = true}; + if (mqtt_conn == NULL) { + // mqtt_conn = mg_mqtt_connect(ifp->mgr, MQTT_URL, &opts, mqtt_ev_handler, + // NULL); + mqtt_conn = mg_mqtt_connect(ifp->mgr, MQTTS_URL, &opts, mqtt_ev_handler, + "tls enabled"); + } } - // Catch 1 second timer events - if (ev == MG_TCPIP_EV_TIMER_1S && ifp->ip == 0) { - MG_INFO(("Sending ARP probe")); - mg_tcpip_arp_request(ifp, ip, NULL); +#if defined(DISABLE_DHCP) + { + static uint32_t ip = 0; + static unsigned counter = 0; + // Set initial self-assigned IP + if (ip == 0) ip = MG_IPV4(169, 254, 2, 100); + + // restart process on link change + if (ev == MG_TCPIP_EV_ST_CHG && ifp->state == MG_TCPIP_STATE_DOWN) + ifp->ip = 0; + + // Catch ARP packets. Parse them yourself, that's easy. + if (ev == MG_TCPIP_EV_ARP) { + struct mg_str *frame = ev_data; + MG_INFO(("Iface %p: Got ARP frame", ifp)); + mg_hexdump(frame->buf, frame->len); + // TODO: check for conflict. On conflict, increment ip and reset counter + } + + // Catch 1 second timer events + if (ev == MG_TCPIP_EV_TIMER_1S && ifp->state == MG_TCPIP_STATE_UP) { + MG_INFO(("Sending ARP probe")); + mg_tcpip_arp_request(ifp, ip, NULL); - // Seems to be no conflict. Assign us an IP - if (counter++ > 2) { - MG_INFO(("Assigning %M, sending ARP probe", mg_print_ip4, &ip)); - ifp->ip = ip; - mg_tcpip_arp_request(ifp, ip, ifp->mac); + // Seems to be no conflict. Assign us an IP + if (counter++ > 2) { + MG_INFO(("Assigning %M, sending ARP probe", mg_print_ip4, &ip)); + ifp->ip = ip; // state will change to MG_TCPIP_STATE_READY on next poll + mg_tcpip_arp_request(ifp, ip, ifp->mac); + } } } +#else + (void) ev_data; +#endif } int main(int argc, char *argv[]) { @@ -276,31 +300,29 @@ int main(int argc, char *argv[]) { mg_log_set(MG_LL_DEBUG); // Set log level struct mg_tcpip_driver driver = {.tx = pcap_tx, .up = pcap_up, .rx = pcap_rx}; - struct mg_tcpip_if mif = {.driver = &driver, .driver_data = ph}; + struct mg_tcpip_if mif = {.driver = &driver, + .driver_data = ph, +#if defined(DISABLE_DHCP) + .mask = MG_IPV4(255, 255, 255, 0), + .gw = MG_IPV4(169, 254, 2, 1) +#endif +}; sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1], &mif.mac[2], &mif.mac[3], &mif.mac[4], &mif.mac[5]); mg_tcpip_init(&mgr, &mif); // Call order is important: call after mg_tcpip_init() mif.fn = if_ev_handler; +#if defined(DISABLE_DHCP) mif.enable_dhcp_client = false; +#endif MG_INFO(("Init done, starting main loop")); mg_http_listen(&mgr, "http://0.0.0.0:8000", http_ev_handler, NULL); mg_http_listen(&mgr, "https://0.0.0.0:8443", http_ev_handler, "tls enabled"); - bool got_ip = false; - while (s_signo == 0) { mg_mgr_poll(&mgr, 100); - - // Trigger MQTT connection when we receive IP address - if (mif.state == MG_TCPIP_STATE_READY && got_ip == false) { - struct mg_mqtt_opts opts = {.clean = true}; - // mg_mqtt_connect(&mgr, MQTT_URL, &opts, mqtt_ev_handler, NULL); - mg_mqtt_connect(&mgr, MQTTS_URL, &opts, mqtt_ev_handler, "tls enabled"); - got_ip = true; - } } mg_mgr_free(&mgr);