optimized mg_addr structure

This commit is contained in:
robert 2023-06-09 08:56:08 -04:00
parent dcfa7ad657
commit dd32deb2ad
9 changed files with 134 additions and 91 deletions

View File

@ -238,7 +238,7 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
break; // Return success break; // Return success
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
dm->addr.is_ip6 = true; dm->addr.is_ip6 = true;
memcpy(&dm->addr.ip6, &buf[ofs - 16], 16); memcpy(&dm->addr.ip, &buf[ofs - 16], 16);
dm->resolved = true; dm->resolved = true;
break; // Return success break; // Return success
} }
@ -3484,15 +3484,16 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
} }
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) { static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_vcasecmp(&str, "localhost") != 0) return false; if (mg_vcasecmp(&str, "localhost") != 0) return false;
addr->ip = mg_htonl(0x7f000001); memcpy(addr->ip, &localhost, sizeof(uint32_t));
addr->is_ip6 = false; addr->is_ip6 = false;
return true; return true;
} }
static bool mg_atone(struct mg_str str, struct mg_addr *addr) { static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
if (str.len > 0) return false; if (str.len > 0) return false;
addr->ip = 0; memset(addr->ip, 0, sizeof(addr->ip));
addr->is_ip6 = false; addr->is_ip6 = false;
return true; return true;
} }
@ -3520,15 +3521,18 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) { static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
int i; int i;
uint32_t ipv4;
if (str.len < 14) return false; if (str.len < 14) return false;
if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false; if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
for (i = 2; i < 6; i++) { for (i = 2; i < 6; i++) {
if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false; if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
} }
//struct mg_str s = mg_str_n(&str.ptr[7], str.len - 7);
if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false; if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
memset(addr->ip6, 0, sizeof(addr->ip6)); memcpy(&ipv4, addr->ip, sizeof(ipv4));
addr->ip6[10] = addr->ip6[11] = 255; memset(addr->ip, 0, sizeof(addr->ip));
memcpy(&addr->ip6[12], &addr->ip, 4); addr->ip[10] = addr->ip[11] = 255;
memcpy(&addr->ip[12], &ipv4, 4);
addr->is_ip6 = true; addr->is_ip6 = true;
return true; return true;
} }
@ -3545,8 +3549,8 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
if (i > j + 3) return false; if (i > j + 3) return false;
// MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j])); // MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
val = mg_unhexn(&str.ptr[j], i - j + 1); val = mg_unhexn(&str.ptr[j], i - j + 1);
addr->ip6[n] = (uint8_t) ((val >> 8) & 255); addr->ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip6[n + 1] = (uint8_t) (val & 255); addr->ip[n + 1] = (uint8_t) (val & 255);
} else if (str.ptr[i] == ':') { } else if (str.ptr[i] == ':') {
j = i + 1; j = i + 1;
if (i > 0 && str.ptr[i - 1] == ':') { if (i > 0 && str.ptr[i - 1] == ':') {
@ -3556,16 +3560,17 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
n += 2; n += 2;
} }
if (n > 14) return false; if (n > 14) return false;
addr->ip6[n] = addr->ip6[n + 1] = 0; // For trailing :: addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
} else { } else {
return false; return false;
} }
} }
if (n < 14 && dc == 42) return false; if (n < 14 && dc == 42) return false;
if (n < 14) { if (n < 14) {
memmove(&addr->ip6[dc + (14 - n)], &addr->ip6[dc], n - dc + 2); memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
memset(&addr->ip6[dc], 0, 14 - n); memset(&addr->ip[dc], 0, 14 - n);
} }
addr->is_ip6 = true; addr->is_ip6 = true;
return true; return true;
} }
@ -3815,7 +3820,7 @@ size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) { size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
struct mg_addr *addr = va_arg(*ap, struct mg_addr *); struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip6); if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
return print_ip4(out, arg, (uint8_t *) &addr->ip); return print_ip4(out, arg, (uint8_t *) &addr->ip);
} }
@ -4446,12 +4451,12 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
memset(usa, 0, sizeof(*usa)); memset(usa, 0, sizeof(*usa));
usa->sin.sin_family = AF_INET; usa->sin.sin_family = AF_INET;
usa->sin.sin_port = a->port; usa->sin.sin_port = a->port;
*(uint32_t *) &usa->sin.sin_addr = a->ip; memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (a->is_ip6) { if (a->is_ip6) {
usa->sin.sin_family = AF_INET6; usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port; usa->sin6.sin6_port = a->port;
memcpy(&usa->sin6.sin6_addr, a->ip6, sizeof(a->ip6)); memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
len = sizeof(usa->sin6); len = sizeof(usa->sin6);
} }
#endif #endif
@ -4461,10 +4466,10 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) { static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
a->is_ip6 = is_ip6; a->is_ip6 = is_ip6;
a->port = usa->sin.sin_port; a->port = usa->sin.sin_port;
memcpy(&a->ip, &usa->sin.sin_addr, sizeof(a->ip)); memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (is_ip6) { if (is_ip6) {
memcpy(a->ip6, &usa->sin6.sin6_addr, sizeof(a->ip6)); memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
a->port = usa->sin6.sin6_port; a->port = usa->sin6.sin6_port;
} }
#endif #endif
@ -7776,7 +7781,7 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (c != NULL && c->is_arplooking) { if (c != NULL && c->is_arplooking) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, pkt->arp->sha, sizeof(s->mac)); memcpy(s->mac, pkt->arp->sha, sizeof(s->mac));
MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, &c->rem.ip, MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip,
mg_print_mac, s->mac)); mg_print_mac, s->mac));
c->is_arplooking = 0; c->is_arplooking = 0;
} }
@ -7875,7 +7880,7 @@ static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
// No UDP listener on this port. Should send ICMP, but keep silent. // No UDP listener on this port. Should send ICMP, but keep silent.
} else { } else {
c->rem.port = pkt->udp->sport; c->rem.port = pkt->udp->sport;
c->rem.ip = pkt->ip->src; memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
if (c->recv.len >= MG_MAX_RECV_SIZE) { if (c->recv.len >= MG_MAX_RECV_SIZE) {
@ -7949,7 +7954,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
settmout(c, MIP_TTYPE_KEEPALIVE); settmout(c, MIP_TTYPE_KEEPALIVE);
c->rem.ip = pkt->ip->src; memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
c->rem.port = pkt->tcp->sport; c->rem.port = pkt->tcp->sport;
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
@ -7968,17 +7973,19 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (c->is_udp) { if (c->is_udp) {
size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */; size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */;
if (len + max_headers_len > ifp->tx.len) { if (len + max_headers_len > ifp->tx.len) {
len = ifp->tx.len - max_headers_len; len = ifp->tx.len - max_headers_len;
} }
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len); tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
} else { } else {
size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */; size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */;
if (len + max_headers_len > ifp->tx.len) if (len + max_headers_len > ifp->tx.len)
len = ifp->tx.len - max_headers_len; len = ifp->tx.len - max_headers_len;
if (tx_tcp(ifp, s->mac, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, if (tx_tcp(ifp, s->mac, rem_ip, TH_PUSH | TH_ACK, c->loc.port,
c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) { c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
s->seq += (uint32_t) len; s->seq += (uint32_t) len;
if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
@ -8261,17 +8268,19 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) {
if (c->is_udp || c->is_listening) continue; if (c->is_udp || c->is_listening) continue;
if (c->is_connecting || c->is_resolving) continue; if (c->is_connecting || c->is_resolving) continue;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (uptime_ms > s->timer) { if (uptime_ms > s->timer) {
if (s->ttype == MIP_TTYPE_ACK) { if (s->ttype == MIP_TTYPE_ACK) {
MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack)); MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack));
tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0); mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
} else { } else {
if (s->tmiss++ > 2) { if (s->tmiss++ > 2) {
mg_error(c, "keepalive"); mg_error(c, "keepalive");
} else { } else {
MG_DEBUG(("%lu keepalive", c->id)); MG_DEBUG(("%lu keepalive", c->id));
tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
} }
} }
@ -8339,32 +8348,36 @@ static void send_syn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
tx_tcp(ifp, s->mac, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL,
0); 0);
} }
void mg_connect_resolved(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
c->is_resolving = 0; c->is_resolving = 0;
if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE; if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE;
c->loc.ip = ifp->ip; memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t));
c->loc.port = mg_htons(ifp->eport++); c->loc.port = mg_htons(ifp->eport++);
MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port, MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port,
&c->rem)); &c->rem));
mg_call(c, MG_EV_RESOLVE, NULL); mg_call(c, MG_EV_RESOLVE, NULL);
if (((c->rem.ip & ifp->mask) == (ifp->ip & ifp->mask))) { if (((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) {
// If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this! // If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this!
MG_DEBUG(("%lu ARP lookup...", c->id)); MG_DEBUG(("%lu ARP lookup...", c->id));
arp_ask(ifp, c->rem.ip); arp_ask(ifp, rem_ip);
c->is_arplooking = 1; c->is_arplooking = 1;
} else if (c->rem.ip == (ifp->ip | ~ifp->mask)) { } else if (rem_ip == (ifp->ip | ~ifp->mask)) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast
} else if ((*((uint8_t *) &c->rem.ip) & 0xE0) == 0xE0) { } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF
uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group
memcpy(s->mac, mcastp, 3); memcpy(s->mac, mcastp, 3);
memcpy(s->mac + 3, ((uint8_t *) &c->rem.ip) + 1, 3); // 23 LSb memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb
s->mac[3] &= 0x7F; s->mac[3] &= 0x7F;
} else { } else {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
@ -8394,11 +8407,13 @@ static void write_conn(struct mg_connection *c) {
static void close_conn(struct mg_connection *c) { static void close_conn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
mg_iobuf_free(&s->raw); // For TLS connections, release raw data mg_iobuf_free(&s->raw); // For TLS connections, release raw data
if (c->is_udp == false && c->is_listening == false) { // For TCP conns, if (c->is_udp == false && c->is_listening == false) { // For TCP conns,
struct mg_tcpip_if *ifp = struct mg_tcpip_if *ifp =
(struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN
tx_tcp(ifp, s->mac, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
} }
mg_close_conn(c); mg_close_conn(c);
@ -8431,11 +8446,13 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
bool mg_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
bool res = false; bool res = false;
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) { if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) {
mg_error(c, "net down"); mg_error(c, "net down");
} else if (c->is_udp) { } else if (c->is_udp) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len); tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
res = true; res = true;
} else { } else {
res = mg_iobuf_add(&c->send, c->send.len, buf, len); res = mg_iobuf_add(&c->send, c->send.len, buf, len);

View File

@ -1137,10 +1137,9 @@ struct mg_dns {
}; };
struct mg_addr { struct mg_addr {
uint16_t port; // TCP or UDP port in network byte order uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
uint32_t ip; // IP address in network byte order uint16_t port; // TCP or UDP port in network byte order
uint8_t ip6[16]; // IPv6 address bool is_ip6; // True when address is IPv6 address
bool is_ip6; // True when address is IPv6 address
}; };
struct mg_mgr { struct mg_mgr {
@ -1152,6 +1151,7 @@ struct mg_mgr {
unsigned long nextid; // Next connection ID unsigned long nextid; // Next connection ID
unsigned long timerid; // Next timer ID unsigned long timerid; // Next timer ID
void *userdata; // Arbitrary user data pointer void *userdata; // Arbitrary user data pointer
void *tls_ctx; // TLS context shared by all TLS sessions
uint16_t mqtt_id; // MQTT IDs for pub/sub uint16_t mqtt_id; // MQTT IDs for pub/sub
void *active_dns_requests; // DNS requests in progress void *active_dns_requests; // DNS requests in progress
struct mg_timer *timers; // Active timers struct mg_timer *timers; // Active timers

View File

@ -126,7 +126,7 @@ bool mg_dns_parse(const uint8_t *buf, size_t len, struct mg_dns_message *dm) {
break; // Return success break; // Return success
} else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) { } else if (rr.alen == 16 && rr.atype == 28 && rr.aclass == 1) {
dm->addr.is_ip6 = true; dm->addr.is_ip6 = true;
memcpy(&dm->addr.ip6, &buf[ofs - 16], 16); memcpy(&dm->addr.ip, &buf[ofs - 16], 16);
dm->resolved = true; dm->resolved = true;
break; // Return success break; // Return success
} }

View File

@ -22,15 +22,16 @@ size_t mg_printf(struct mg_connection *c, const char *fmt, ...) {
} }
static bool mg_atonl(struct mg_str str, struct mg_addr *addr) { static bool mg_atonl(struct mg_str str, struct mg_addr *addr) {
uint32_t localhost = mg_htonl(0x7f000001);
if (mg_vcasecmp(&str, "localhost") != 0) return false; if (mg_vcasecmp(&str, "localhost") != 0) return false;
addr->ip = mg_htonl(0x7f000001); memcpy(addr->ip, &localhost, sizeof(uint32_t));
addr->is_ip6 = false; addr->is_ip6 = false;
return true; return true;
} }
static bool mg_atone(struct mg_str str, struct mg_addr *addr) { static bool mg_atone(struct mg_str str, struct mg_addr *addr) {
if (str.len > 0) return false; if (str.len > 0) return false;
addr->ip = 0; memset(addr->ip, 0, sizeof(addr->ip));
addr->is_ip6 = false; addr->is_ip6 = false;
return true; return true;
} }
@ -58,15 +59,18 @@ static bool mg_aton4(struct mg_str str, struct mg_addr *addr) {
static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) { static bool mg_v4mapped(struct mg_str str, struct mg_addr *addr) {
int i; int i;
uint32_t ipv4;
if (str.len < 14) return false; if (str.len < 14) return false;
if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false; if (str.ptr[0] != ':' || str.ptr[1] != ':' || str.ptr[6] != ':') return false;
for (i = 2; i < 6; i++) { for (i = 2; i < 6; i++) {
if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false; if (str.ptr[i] != 'f' && str.ptr[i] != 'F') return false;
} }
//struct mg_str s = mg_str_n(&str.ptr[7], str.len - 7);
if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false; if (!mg_aton4(mg_str_n(&str.ptr[7], str.len - 7), addr)) return false;
memset(addr->ip6, 0, sizeof(addr->ip6)); memcpy(&ipv4, addr->ip, sizeof(ipv4));
addr->ip6[10] = addr->ip6[11] = 255; memset(addr->ip, 0, sizeof(addr->ip));
memcpy(&addr->ip6[12], &addr->ip, 4); addr->ip[10] = addr->ip[11] = 255;
memcpy(&addr->ip[12], &ipv4, 4);
addr->is_ip6 = true; addr->is_ip6 = true;
return true; return true;
} }
@ -83,8 +87,8 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
if (i > j + 3) return false; if (i > j + 3) return false;
// MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j])); // MG_DEBUG(("%zu %zu [%.*s]", i, j, (int) (i - j + 1), &str.ptr[j]));
val = mg_unhexn(&str.ptr[j], i - j + 1); val = mg_unhexn(&str.ptr[j], i - j + 1);
addr->ip6[n] = (uint8_t) ((val >> 8) & 255); addr->ip[n] = (uint8_t) ((val >> 8) & 255);
addr->ip6[n + 1] = (uint8_t) (val & 255); addr->ip[n + 1] = (uint8_t) (val & 255);
} else if (str.ptr[i] == ':') { } else if (str.ptr[i] == ':') {
j = i + 1; j = i + 1;
if (i > 0 && str.ptr[i - 1] == ':') { if (i > 0 && str.ptr[i - 1] == ':') {
@ -94,16 +98,17 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) {
n += 2; n += 2;
} }
if (n > 14) return false; if (n > 14) return false;
addr->ip6[n] = addr->ip6[n + 1] = 0; // For trailing :: addr->ip[n] = addr->ip[n + 1] = 0; // For trailing ::
} else { } else {
return false; return false;
} }
} }
if (n < 14 && dc == 42) return false; if (n < 14 && dc == 42) return false;
if (n < 14) { if (n < 14) {
memmove(&addr->ip6[dc + (14 - n)], &addr->ip6[dc], n - dc + 2); memmove(&addr->ip[dc + (14 - n)], &addr->ip[dc], n - dc + 2);
memset(&addr->ip6[dc], 0, 14 - n); memset(&addr->ip[dc], 0, 14 - n);
} }
addr->is_ip6 = true; addr->is_ip6 = true;
return true; return true;
} }

View File

@ -13,10 +13,9 @@ struct mg_dns {
}; };
struct mg_addr { struct mg_addr {
uint16_t port; // TCP or UDP port in network byte order uint8_t ip[16]; // Holds IPv4 or IPv6 address, in network byte order
uint32_t ip; // IP address in network byte order uint16_t port; // TCP or UDP port in network byte order
uint8_t ip6[16]; // IPv6 address bool is_ip6; // True when address is IPv6 address
bool is_ip6; // True when address is IPv6 address
}; };
struct mg_mgr { struct mg_mgr {

View File

@ -101,7 +101,7 @@ size_t mg_print_ip6(void (*out)(char, void *), void *arg, va_list *ap) {
size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) { size_t mg_print_ip(void (*out)(char, void *), void *arg, va_list *ap) {
struct mg_addr *addr = va_arg(*ap, struct mg_addr *); struct mg_addr *addr = va_arg(*ap, struct mg_addr *);
if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip6); if (addr->is_ip6) return print_ip6(out, arg, (uint16_t *) addr->ip);
return print_ip4(out, arg, (uint8_t *) &addr->ip); return print_ip4(out, arg, (uint8_t *) &addr->ip);
} }

View File

@ -57,12 +57,12 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
memset(usa, 0, sizeof(*usa)); memset(usa, 0, sizeof(*usa));
usa->sin.sin_family = AF_INET; usa->sin.sin_family = AF_INET;
usa->sin.sin_port = a->port; usa->sin.sin_port = a->port;
*(uint32_t *) &usa->sin.sin_addr = a->ip; memcpy(&usa->sin.sin_addr, a->ip, sizeof(uint32_t));
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (a->is_ip6) { if (a->is_ip6) {
usa->sin.sin_family = AF_INET6; usa->sin.sin_family = AF_INET6;
usa->sin6.sin6_port = a->port; usa->sin6.sin6_port = a->port;
memcpy(&usa->sin6.sin6_addr, a->ip6, sizeof(a->ip6)); memcpy(&usa->sin6.sin6_addr, a->ip, sizeof(a->ip));
len = sizeof(usa->sin6); len = sizeof(usa->sin6);
} }
#endif #endif
@ -72,10 +72,10 @@ static socklen_t tousa(struct mg_addr *a, union usa *usa) {
static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) { static void tomgaddr(union usa *usa, struct mg_addr *a, bool is_ip6) {
a->is_ip6 = is_ip6; a->is_ip6 = is_ip6;
a->port = usa->sin.sin_port; a->port = usa->sin.sin_port;
memcpy(&a->ip, &usa->sin.sin_addr, sizeof(a->ip)); memcpy(&a->ip, &usa->sin.sin_addr, sizeof(uint32_t));
#if MG_ENABLE_IPV6 #if MG_ENABLE_IPV6
if (is_ip6) { if (is_ip6) {
memcpy(a->ip6, &usa->sin6.sin6_addr, sizeof(a->ip6)); memcpy(a->ip, &usa->sin6.sin6_addr, sizeof(a->ip));
a->port = usa->sin6.sin6_port; a->port = usa->sin6.sin6_port;
} }
#endif #endif

View File

@ -308,7 +308,7 @@ static void rx_arp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
if (c != NULL && c->is_arplooking) { if (c != NULL && c->is_arplooking) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, pkt->arp->sha, sizeof(s->mac)); memcpy(s->mac, pkt->arp->sha, sizeof(s->mac));
MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, &c->rem.ip, MG_DEBUG(("%lu ARP resolved %M -> %M", c->id, mg_print_ip4, c->rem.ip,
mg_print_mac, s->mac)); mg_print_mac, s->mac));
c->is_arplooking = 0; c->is_arplooking = 0;
} }
@ -407,7 +407,7 @@ static void rx_udp(struct mg_tcpip_if *ifp, struct pkt *pkt) {
// No UDP listener on this port. Should send ICMP, but keep silent. // No UDP listener on this port. Should send ICMP, but keep silent.
} else { } else {
c->rem.port = pkt->udp->sport; c->rem.port = pkt->udp->sport;
c->rem.ip = pkt->ip->src; memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
if (c->recv.len >= MG_MAX_RECV_SIZE) { if (c->recv.len >= MG_MAX_RECV_SIZE) {
@ -481,7 +481,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq); s->seq = mg_ntohl(pkt->tcp->ack), s->ack = mg_ntohl(pkt->tcp->seq);
memcpy(s->mac, pkt->eth->src, sizeof(s->mac)); memcpy(s->mac, pkt->eth->src, sizeof(s->mac));
settmout(c, MIP_TTYPE_KEEPALIVE); settmout(c, MIP_TTYPE_KEEPALIVE);
c->rem.ip = pkt->ip->src; memcpy(c->rem.ip, &pkt->ip->src, sizeof(uint32_t));
c->rem.port = pkt->tcp->sport; c->rem.port = pkt->tcp->sport;
MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem)); MG_DEBUG(("%lu accepted %M", c->id, mg_print_ip_port, &c->rem));
LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c); LIST_ADD_HEAD(struct mg_connection, &lsn->mgr->conns, c);
@ -500,17 +500,19 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn,
long mg_io_send(struct mg_connection *c, const void *buf, size_t len) { long mg_io_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (c->is_udp) { if (c->is_udp) {
size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */; size_t max_headers_len = 14 + 24 /* max IP */ + 8 /* UDP */;
if (len + max_headers_len > ifp->tx.len) { if (len + max_headers_len > ifp->tx.len) {
len = ifp->tx.len - max_headers_len; len = ifp->tx.len - max_headers_len;
} }
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len); tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
} else { } else {
size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */; size_t max_headers_len = 14 + 24 /* max IP */ + 60 /* max TCP */;
if (len + max_headers_len > ifp->tx.len) if (len + max_headers_len > ifp->tx.len)
len = ifp->tx.len - max_headers_len; len = ifp->tx.len - max_headers_len;
if (tx_tcp(ifp, s->mac, c->rem.ip, TH_PUSH | TH_ACK, c->loc.port, if (tx_tcp(ifp, s->mac, rem_ip, TH_PUSH | TH_ACK, c->loc.port,
c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) { c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), buf, len) > 0) {
s->seq += (uint32_t) len; s->seq += (uint32_t) len;
if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE); if (s->ttype == MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_KEEPALIVE);
@ -793,17 +795,19 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) {
if (c->is_udp || c->is_listening) continue; if (c->is_udp || c->is_listening) continue;
if (c->is_connecting || c->is_resolving) continue; if (c->is_connecting || c->is_resolving) continue;
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (uptime_ms > s->timer) { if (uptime_ms > s->timer) {
if (s->ttype == MIP_TTYPE_ACK) { if (s->ttype == MIP_TTYPE_ACK) {
MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack)); MG_DEBUG(("%lu ack %x %x", c->id, s->seq, s->ack));
tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), "", 0); mg_htonl(s->seq), mg_htonl(s->ack), "", 0);
} else { } else {
if (s->tmiss++ > 2) { if (s->tmiss++ > 2) {
mg_error(c, "keepalive"); mg_error(c, "keepalive");
} else { } else {
MG_DEBUG(("%lu keepalive", c->id)); MG_DEBUG(("%lu keepalive", c->id));
tx_tcp(ifp, s->mac, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0);
} }
} }
@ -871,32 +875,36 @@ static void send_syn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port)); uint32_t isn = mg_htonl((uint32_t) mg_ntohs(c->loc.port));
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
tx_tcp(ifp, s->mac, c->rem.ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL, uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
tx_tcp(ifp, s->mac, rem_ip, TH_SYN, c->loc.port, c->rem.port, isn, 0, NULL,
0); 0);
} }
void mg_connect_resolved(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
c->is_resolving = 0; c->is_resolving = 0;
if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE; if (ifp->eport < MG_EPHEMERAL_PORT_BASE) ifp->eport = MG_EPHEMERAL_PORT_BASE;
c->loc.ip = ifp->ip; memcpy(c->loc.ip, &ifp->ip, sizeof(uint32_t));
c->loc.port = mg_htons(ifp->eport++); c->loc.port = mg_htons(ifp->eport++);
MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port, MG_DEBUG(("%lu %M -> %M", c->id, mg_print_ip_port, &c->loc, mg_print_ip_port,
&c->rem)); &c->rem));
mg_call(c, MG_EV_RESOLVE, NULL); mg_call(c, MG_EV_RESOLVE, NULL);
if (((c->rem.ip & ifp->mask) == (ifp->ip & ifp->mask))) { if (((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) {
// If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this! // If we're in the same LAN, fire an ARP lookup. TODO(cpq): handle this!
MG_DEBUG(("%lu ARP lookup...", c->id)); MG_DEBUG(("%lu ARP lookup...", c->id));
arp_ask(ifp, c->rem.ip); arp_ask(ifp, rem_ip);
c->is_arplooking = 1; c->is_arplooking = 1;
} else if (c->rem.ip == (ifp->ip | ~ifp->mask)) { } else if (rem_ip == (ifp->ip | ~ifp->mask)) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast memset(s->mac, 0xFF, sizeof(s->mac)); // local broadcast
} else if ((*((uint8_t *) &c->rem.ip) & 0xE0) == 0xE0) { } else if ((*((uint8_t *) &rem_ip) & 0xE0) == 0xE0) {
struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF struct connstate *s = (struct connstate *) (c + 1); // 224 to 239, E0 to EF
uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group uint8_t mcastp[3] = {0x01, 0x00, 0x5E}; // multicast group
memcpy(s->mac, mcastp, 3); memcpy(s->mac, mcastp, 3);
memcpy(s->mac + 3, ((uint8_t *) &c->rem.ip) + 1, 3); // 23 LSb memcpy(s->mac + 3, ((uint8_t *) &rem_ip) + 1, 3); // 23 LSb
s->mac[3] &= 0x7F; s->mac[3] &= 0x7F;
} else { } else {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
@ -926,11 +934,13 @@ static void write_conn(struct mg_connection *c) {
static void close_conn(struct mg_connection *c) { static void close_conn(struct mg_connection *c) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
mg_iobuf_free(&s->raw); // For TLS connections, release raw data mg_iobuf_free(&s->raw); // For TLS connections, release raw data
if (c->is_udp == false && c->is_listening == false) { // For TCP conns, if (c->is_udp == false && c->is_listening == false) { // For TCP conns,
struct mg_tcpip_if *ifp = struct mg_tcpip_if *ifp =
(struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN
tx_tcp(ifp, s->mac, c->rem.ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port,
mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0);
} }
mg_close_conn(c); mg_close_conn(c);
@ -963,11 +973,13 @@ void mg_mgr_poll(struct mg_mgr *mgr, int ms) {
bool mg_send(struct mg_connection *c, const void *buf, size_t len) { bool mg_send(struct mg_connection *c, const void *buf, size_t len) {
struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv;
bool res = false; bool res = false;
uint32_t rem_ip;
memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t));
if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) { if (ifp->ip == 0 || ifp->state != MG_TCPIP_STATE_READY) {
mg_error(c, "net down"); mg_error(c, "net down");
} else if (c->is_udp) { } else if (c->is_udp) {
struct connstate *s = (struct connstate *) (c + 1); struct connstate *s = (struct connstate *) (c + 1);
tx_udp(ifp, s->mac, ifp->ip, c->loc.port, c->rem.ip, c->rem.port, buf, len); tx_udp(ifp, s->mac, ifp->ip, c->loc.port, rem_ip, c->rem.port, buf, len);
res = true; res = true;
} else { } else {
res = mg_iobuf_add(&c->send, c->send.len, buf, len); res = mg_iobuf_add(&c->send, c->send.len, buf, len);

View File

@ -1887,12 +1887,20 @@ static void test_str(void) {
{ {
char buf[100]; char buf[100];
struct mg_addr a = {mg_htons(3), mg_htonl(0x2000001), {1, 100, 33}, false}; struct mg_addr a;
uint32_t addr = mg_htonl(0x2000001);
memcpy(a.ip, &addr, sizeof(uint32_t));
a.port = mg_htons(3);
a.is_ip6 = false;
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 9); ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 9);
ASSERT(strcmp(buf, "2.0.0.1 7") == 0); ASSERT(strcmp(buf, "2.0.0.1 7") == 0);
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip_port, &a, 7) == ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip_port, &a, 7) ==
11); 11);
ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0); ASSERT(strcmp(buf, "2.0.0.1:3 7") == 0);
memset(a.ip, 0, sizeof(a.ip));
a.ip[0] = 1, a.ip[1] = 100, a.ip[2] = 33;
a.is_ip6 = true; a.is_ip6 = true;
ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24); ASSERT(mg_snprintf(buf, sizeof(buf), "%M %d", mg_print_ip, &a, 7) == 24);
ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0); ASSERT(strcmp(buf, "[164:2100:0:0:0:0:0:0] 7") == 0);
@ -1980,6 +1988,7 @@ static void test_dns(void) {
static void test_util(void) { static void test_util(void) {
char buf[100], *p, *s; char buf[100], *p, *s;
struct mg_addr a; struct mg_addr a;
uint32_t ipv4;
memset(&a, 0, sizeof(a)); memset(&a, 0, sizeof(a));
ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true); ASSERT(mg_file_printf(&mg_fs_posix, "data.txt", "%s", "hi") == true);
// if (system("ls -l") != 0) (void) 0; // if (system("ls -l") != 0) (void) 0;
@ -1993,54 +2002,55 @@ static void test_util(void) {
ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false); ASSERT(mg_aton(mg_str("0.0.0.-1"), &a) == false);
ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true); ASSERT(mg_aton(mg_str("127.0.0.1"), &a) == true);
ASSERT(a.is_ip6 == false); ASSERT(a.is_ip6 == false);
ASSERT(a.ip == mg_htonl(0x7f000001)); memcpy(&ipv4, a.ip, sizeof(ipv4));
ASSERT(ipv4 == mg_htonl(0x7f000001));
ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true); ASSERT(mg_aton(mg_str("1:2:3:4:5:6:7:8"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(
memcmp(a.ip6, memcmp(a.ip,
"\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08", "\x00\x01\x00\x02\x00\x03\x00\x04\x00\x05\x00\x06\x00\x07\x00\x08",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
memset(a.ip6, 0xaa, sizeof(a.ip6)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1::1"), &a) == true); ASSERT(mg_aton(mg_str("1::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(
memcmp(a.ip6, memcmp(a.ip,
"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
memset(a.ip6, 0xaa, sizeof(a.ip6)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true); ASSERT(mg_aton(mg_str("::fFff:1.2.3.4"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT(memcmp(a.ip6, ASSERT(memcmp(a.ip,
"\x00\x00\x00\x00\x00\x00\x00\x00" "\x00\x00\x00\x00\x00\x00\x00\x00"
"\x00\x00\xff\xff\x01\x02\x03\x04", "\x00\x00\xff\xff\x01\x02\x03\x04",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
memset(a.ip6, 0xaa, sizeof(a.ip6)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("::1"), &a) == true); ASSERT(mg_aton(mg_str("::1"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(
memcmp(a.ip6, memcmp(a.ip,
"\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01", "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
memset(a.ip6, 0xaa, sizeof(a.ip6)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("1::"), &a) == true); ASSERT(mg_aton(mg_str("1::"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(
memcmp(a.ip6, memcmp(a.ip,
"\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00", "\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
memset(a.ip6, 0xaa, sizeof(a.ip6)); memset(a.ip, 0xaa, sizeof(a.ip));
ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true); ASSERT(mg_aton(mg_str("2001:4860:4860::8888"), &a) == true);
ASSERT(a.is_ip6 == true); ASSERT(a.is_ip6 == true);
ASSERT( ASSERT(
memcmp(a.ip6, memcmp(a.ip,
"\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88", "\x20\x01\x48\x60\x48\x60\x00\x00\x00\x00\x00\x00\x00\x00\x88\x88",
sizeof(a.ip6)) == 0); sizeof(a.ip)) == 0);
ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0); ASSERT(strcmp(mg_hex("abc", 3, buf), "616263") == 0);
ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0); ASSERT(mg_url_decode("a=%", 3, buf, sizeof(buf), 0) < 0);