mirror of
https://github.com/cesanta/mongoose.git
synced 2024-12-27 06:51:04 +08:00
Introduce mg_timer_expired(). Adopt DHCP and link status to use it
This commit is contained in:
parent
a113e344a1
commit
f9272d0959
25
mip/mip.c
25
mip/mip.c
@ -43,8 +43,7 @@ struct mip_if {
|
|||||||
struct mg_mgr *mgr; // Mongoose event manager
|
struct mg_mgr *mgr; // Mongoose event manager
|
||||||
|
|
||||||
// Internal state, user can use it but should not change it
|
// Internal state, user can use it but should not change it
|
||||||
uint64_t curtime; // Last poll timestamp in millis
|
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
||||||
uint64_t timer; // Timer
|
|
||||||
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
|
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
|
||||||
uint16_t eport; // Next ephemeral port
|
uint16_t eport; // Next ephemeral port
|
||||||
int state; // Current state
|
int state; // Current state
|
||||||
@ -572,13 +571,13 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
||||||
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
||||||
#endif
|
#endif
|
||||||
if(read_conn(c, pkt)) {
|
if (read_conn(c, pkt)) {
|
||||||
// Send ACK immediately, no piggyback yet
|
// Send ACK immediately, no piggyback yet
|
||||||
// TODO() Set a timer and send ACK if timer expires and no segment was sent ?
|
// TODO() Set a timer and send ACK if timer expires and no segment was
|
||||||
// (clear timer on segment sent)
|
// sent ? (clear timer on segment sent)
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
||||||
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
||||||
mg_htonl(s->ack), NULL, 0);
|
mg_htonl(s->ack), NULL, 0);
|
||||||
}
|
}
|
||||||
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
||||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
@ -673,19 +672,17 @@ static void mip_rx(struct mip_if *ifp, void *buf, size_t len) {
|
|||||||
|
|
||||||
static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
||||||
if (ifp == NULL || ifp->driver == NULL) return;
|
if (ifp == NULL || ifp->driver == NULL) return;
|
||||||
ifp->curtime = uptime_ms;
|
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
||||||
|
|
||||||
if (ifp->ip == 0 && uptime_ms > ifp->timer) {
|
if (ifp->ip == 0 && expired_1000ms) {
|
||||||
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
||||||
ifp->timer = uptime_ms + 1000; // with some interval
|
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
||||||
} else if (ifp->use_dhcp == false && uptime_ms > ifp->timer &&
|
|
||||||
arp_cache_find(ifp, ifp->gw) == NULL) {
|
arp_cache_find(ifp, ifp->gw) == NULL) {
|
||||||
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
||||||
ifp->timer = uptime_ms + 1000; // send ARP who-has request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle physical interface up/down status
|
// Handle physical interface up/down status
|
||||||
if (ifp->driver->up) {
|
if (expired_1000ms && ifp->driver->up) {
|
||||||
bool up = ifp->driver->up(ifp->driver_data);
|
bool up = ifp->driver->up(ifp->driver_data);
|
||||||
bool current = ifp->state != MIP_STATE_DOWN;
|
bool current = ifp->state != MIP_STATE_DOWN;
|
||||||
if (up != current) {
|
if (up != current) {
|
||||||
|
56
mongoose.c
56
mongoose.c
@ -4970,8 +4970,8 @@ char *mg_remove_double_dots(char *s) {
|
|||||||
|
|
||||||
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
|
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
|
||||||
unsigned flags, void (*fn)(void *), void *arg) {
|
unsigned flags, void (*fn)(void *), void *arg) {
|
||||||
struct mg_timer tmp = {0U, ms, 0U, 0U, flags, fn, arg, *head};
|
t->id = 0, t->period_ms = ms, t->expire = 0;
|
||||||
*t = tmp;
|
t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
|
||||||
*head = t;
|
*head = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -4980,28 +4980,27 @@ void mg_timer_free(struct mg_timer **head, struct mg_timer *t) {
|
|||||||
if (*head) *head = t->next;
|
if (*head) *head = t->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t: expiration time, prd: period, now: current time. Return true if expired
|
||||||
|
bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) {
|
||||||
|
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
|
||||||
|
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
|
||||||
|
if (*t > now) return false; // Not expired yet, return
|
||||||
|
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
|
||||||
|
return true; // Expired, return true
|
||||||
|
}
|
||||||
|
|
||||||
void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
|
void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
|
||||||
// If time goes back (wrapped around), reset timers
|
|
||||||
struct mg_timer *t, *tmp;
|
struct mg_timer *t, *tmp;
|
||||||
for (t = *head; t != NULL; t = tmp) {
|
for (t = *head; t != NULL; t = tmp) {
|
||||||
|
bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
|
||||||
|
!(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once
|
||||||
|
bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms);
|
||||||
tmp = t->next;
|
tmp = t->next;
|
||||||
if (t->prev_ms > now_ms) t->expire = 0; // Handle time wrap
|
if (!once && !expired) continue;
|
||||||
t->prev_ms = now_ms;
|
|
||||||
if (t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
|
|
||||||
!(t->flags & MG_TIMER_CALLED)) {
|
|
||||||
// Handle MG_TIMER_NOW only once
|
|
||||||
} else if (t->expire == 0) {
|
|
||||||
t->expire = now_ms + t->period_ms;
|
|
||||||
}
|
|
||||||
if (t->expire > now_ms) continue;
|
|
||||||
if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
|
if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
|
||||||
t->fn(t->arg);
|
t->fn(t->arg);
|
||||||
}
|
}
|
||||||
t->flags |= MG_TIMER_CALLED;
|
t->flags |= MG_TIMER_CALLED;
|
||||||
// Try to tick timers with the given period as accurate as possible,
|
|
||||||
// even if this polling function is called with some random period.
|
|
||||||
t->expire = now_ms - t->expire > t->period_ms ? now_ms + t->period_ms
|
|
||||||
: t->expire + t->period_ms;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -6327,8 +6326,7 @@ struct mip_if {
|
|||||||
struct mg_mgr *mgr; // Mongoose event manager
|
struct mg_mgr *mgr; // Mongoose event manager
|
||||||
|
|
||||||
// Internal state, user can use it but should not change it
|
// Internal state, user can use it but should not change it
|
||||||
uint64_t curtime; // Last poll timestamp in millis
|
uint64_t timer_1000ms; // 1000 ms timer: for DHCP and link state
|
||||||
uint64_t timer; // Timer
|
|
||||||
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
|
uint8_t arp_cache[MIP_ARP_CS]; // Each entry is 12 bytes
|
||||||
uint16_t eport; // Next ephemeral port
|
uint16_t eport; // Next ephemeral port
|
||||||
int state; // Current state
|
int state; // Current state
|
||||||
@ -6856,13 +6854,13 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) {
|
|||||||
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
mg_ntohl(pkt->ip->dst), mg_ntohs(pkt->tcp->dport)));
|
||||||
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
mg_hexdump(pkt->pay.buf, pkt->pay.len);
|
||||||
#endif
|
#endif
|
||||||
if(read_conn(c, pkt)) {
|
if (read_conn(c, pkt)) {
|
||||||
// Send ACK immediately, no piggyback yet
|
// Send ACK immediately, no piggyback yet
|
||||||
// TODO() Set a timer and send ACK if timer expires and no segment was sent ?
|
// TODO() Set a timer and send ACK if timer expires and no segment was
|
||||||
// (clear timer on segment sent)
|
// sent ? (clear timer on segment sent)
|
||||||
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
struct tcpstate *s = (struct tcpstate *) (c + 1);
|
||||||
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq),
|
||||||
mg_htonl(s->ack), NULL, 0);
|
mg_htonl(s->ack), NULL, 0);
|
||||||
}
|
}
|
||||||
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
} else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) {
|
||||||
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0);
|
||||||
@ -6957,19 +6955,17 @@ static void mip_rx(struct mip_if *ifp, void *buf, size_t len) {
|
|||||||
|
|
||||||
static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) {
|
||||||
if (ifp == NULL || ifp->driver == NULL) return;
|
if (ifp == NULL || ifp->driver == NULL) return;
|
||||||
ifp->curtime = uptime_ms;
|
bool expired_1000ms = mg_timer_expired(&ifp->timer_1000ms, 1000, uptime_ms);
|
||||||
|
|
||||||
if (ifp->ip == 0 && uptime_ms > ifp->timer) {
|
if (ifp->ip == 0 && expired_1000ms) {
|
||||||
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
tx_dhcp_discover(ifp); // If IP not configured, send DHCP
|
||||||
ifp->timer = uptime_ms + 1000; // with some interval
|
} else if (ifp->use_dhcp == false && expired_1000ms &&
|
||||||
} else if (ifp->use_dhcp == false && uptime_ms > ifp->timer &&
|
|
||||||
arp_cache_find(ifp, ifp->gw) == NULL) {
|
arp_cache_find(ifp, ifp->gw) == NULL) {
|
||||||
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
arp_ask(ifp, ifp->gw); // If GW's MAC address in not in ARP cache
|
||||||
ifp->timer = uptime_ms + 1000; // send ARP who-has request
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle physical interface up/down status
|
// Handle physical interface up/down status
|
||||||
if (ifp->driver->up) {
|
if (expired_1000ms && ifp->driver->up) {
|
||||||
bool up = ifp->driver->up(ifp->driver_data);
|
bool up = ifp->driver->up(ifp->driver_data);
|
||||||
bool current = ifp->state != MIP_STATE_DOWN;
|
bool current = ifp->state != MIP_STATE_DOWN;
|
||||||
if (up != current) {
|
if (up != current) {
|
||||||
|
@ -828,7 +828,6 @@ void mg_log_set_fn(mg_pfn_t fn, void *param);
|
|||||||
struct mg_timer {
|
struct mg_timer {
|
||||||
unsigned long id; // Timer ID
|
unsigned long id; // Timer ID
|
||||||
uint64_t period_ms; // Timer period in milliseconds
|
uint64_t period_ms; // Timer period in milliseconds
|
||||||
uint64_t prev_ms; // Timestamp of a previous poll
|
|
||||||
uint64_t expire; // Expiration timestamp in milliseconds
|
uint64_t expire; // Expiration timestamp in milliseconds
|
||||||
unsigned flags; // Possible flags values below
|
unsigned flags; // Possible flags values below
|
||||||
#define MG_TIMER_ONCE 0 // Call function once
|
#define MG_TIMER_ONCE 0 // Call function once
|
||||||
@ -844,6 +843,7 @@ void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
|
|||||||
void *arg);
|
void *arg);
|
||||||
void mg_timer_free(struct mg_timer **head, struct mg_timer *);
|
void mg_timer_free(struct mg_timer **head, struct mg_timer *);
|
||||||
void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
|
void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
|
||||||
|
bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
31
src/timer.c
31
src/timer.c
@ -5,8 +5,8 @@
|
|||||||
|
|
||||||
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
|
void mg_timer_init(struct mg_timer **head, struct mg_timer *t, uint64_t ms,
|
||||||
unsigned flags, void (*fn)(void *), void *arg) {
|
unsigned flags, void (*fn)(void *), void *arg) {
|
||||||
struct mg_timer tmp = {0U, ms, 0U, 0U, flags, fn, arg, *head};
|
t->id = 0, t->period_ms = ms, t->expire = 0;
|
||||||
*t = tmp;
|
t->flags = flags, t->fn = fn, t->arg = arg, t->next = *head;
|
||||||
*head = t;
|
*head = t;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -15,27 +15,26 @@ void mg_timer_free(struct mg_timer **head, struct mg_timer *t) {
|
|||||||
if (*head) *head = t->next;
|
if (*head) *head = t->next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// t: expiration time, prd: period, now: current time. Return true if expired
|
||||||
|
bool mg_timer_expired(uint64_t *t, uint64_t prd, uint64_t now) {
|
||||||
|
if (now + prd < *t) *t = 0; // Time wrapped? Reset timer
|
||||||
|
if (*t == 0) *t = now + prd; // Firt poll? Set expiration
|
||||||
|
if (*t > now) return false; // Not expired yet, return
|
||||||
|
*t = (now - *t) > prd ? now + prd : *t + prd; // Next expiration time
|
||||||
|
return true; // Expired, return true
|
||||||
|
}
|
||||||
|
|
||||||
void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
|
void mg_timer_poll(struct mg_timer **head, uint64_t now_ms) {
|
||||||
// If time goes back (wrapped around), reset timers
|
|
||||||
struct mg_timer *t, *tmp;
|
struct mg_timer *t, *tmp;
|
||||||
for (t = *head; t != NULL; t = tmp) {
|
for (t = *head; t != NULL; t = tmp) {
|
||||||
|
bool once = t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
|
||||||
|
!(t->flags & MG_TIMER_CALLED); // Handle MG_TIMER_NOW only once
|
||||||
|
bool expired = mg_timer_expired(&t->expire, t->period_ms, now_ms);
|
||||||
tmp = t->next;
|
tmp = t->next;
|
||||||
if (t->prev_ms > now_ms) t->expire = 0; // Handle time wrap
|
if (!once && !expired) continue;
|
||||||
t->prev_ms = now_ms;
|
|
||||||
if (t->expire == 0 && (t->flags & MG_TIMER_RUN_NOW) &&
|
|
||||||
!(t->flags & MG_TIMER_CALLED)) {
|
|
||||||
// Handle MG_TIMER_NOW only once
|
|
||||||
} else if (t->expire == 0) {
|
|
||||||
t->expire = now_ms + t->period_ms;
|
|
||||||
}
|
|
||||||
if (t->expire > now_ms) continue;
|
|
||||||
if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
|
if ((t->flags & MG_TIMER_REPEAT) || !(t->flags & MG_TIMER_CALLED)) {
|
||||||
t->fn(t->arg);
|
t->fn(t->arg);
|
||||||
}
|
}
|
||||||
t->flags |= MG_TIMER_CALLED;
|
t->flags |= MG_TIMER_CALLED;
|
||||||
// Try to tick timers with the given period as accurate as possible,
|
|
||||||
// even if this polling function is called with some random period.
|
|
||||||
t->expire = now_ms - t->expire > t->period_ms ? now_ms + t->period_ms
|
|
||||||
: t->expire + t->period_ms;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
struct mg_timer {
|
struct mg_timer {
|
||||||
unsigned long id; // Timer ID
|
unsigned long id; // Timer ID
|
||||||
uint64_t period_ms; // Timer period in milliseconds
|
uint64_t period_ms; // Timer period in milliseconds
|
||||||
uint64_t prev_ms; // Timestamp of a previous poll
|
|
||||||
uint64_t expire; // Expiration timestamp in milliseconds
|
uint64_t expire; // Expiration timestamp in milliseconds
|
||||||
unsigned flags; // Possible flags values below
|
unsigned flags; // Possible flags values below
|
||||||
#define MG_TIMER_ONCE 0 // Call function once
|
#define MG_TIMER_ONCE 0 // Call function once
|
||||||
@ -21,3 +20,4 @@ void mg_timer_init(struct mg_timer **head, struct mg_timer *timer,
|
|||||||
void *arg);
|
void *arg);
|
||||||
void mg_timer_free(struct mg_timer **head, struct mg_timer *);
|
void mg_timer_free(struct mg_timer **head, struct mg_timer *);
|
||||||
void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
|
void mg_timer_poll(struct mg_timer **head, uint64_t new_ms);
|
||||||
|
bool mg_timer_expired(uint64_t *expiration, uint64_t period, uint64_t now);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user