diff --git a/CHANGELOG.md b/CHANGELOG.md index 851f7da70..c66beda65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -62,7 +62,6 @@ All scripts in the mympd-scripts repository are updated accordingly, do not forg - Upd: Playlist pictures are moved in a separate folder `/var/lib/mympd/pics/playlists` - Upd: Latest libmympdclient based on libmpdclient master - Upd: Hide advanced search by default -- Upd: Mongoose 7.15 - Fix: Send JSONRPC_EVENT_UPDATE_OPTIONS only on feature change *** diff --git a/dist/mongoose/mongoose.c b/dist/mongoose/mongoose.c index 8bd21ad72..8d2a896f8 100644 --- a/dist/mongoose/mongoose.c +++ b/dist/mongoose/mongoose.c @@ -2401,7 +2401,7 @@ int mg_url_decode(const char *src, size_t src_len, char *dst, size_t dst_len, } static bool isok(uint8_t c) { - return c == '\n' || c == '\r' || c == '\t' || c >= ' '; + return c == '\n' || c == '\r' || c >= ' '; } int mg_http_get_request_len(const unsigned char *buf, size_t buf_len) { @@ -2463,11 +2463,9 @@ static bool mg_http_parse_headers(const char *s, const char *end, if (s >= end || clen(s, end) == 0) return false; // Invalid UTF-8 if (*s++ != ':') return false; // Invalid, not followed by : // if (clen(s, end) == 0) return false; // Invalid UTF-8 - while (s < end && (s[0] == ' ' || s[0] == '\t')) s++; // Skip spaces + while (s < end && s[0] == ' ') s++; // Skip spaces if ((s = skiptorn(s, end, &v)) == NULL) return false; - while (v.len > 0 && (v.buf[v.len - 1] == ' ' || v.buf[v.len - 1] == '\t')) { - v.len--; // Trim spaces - } + while (v.len > 0 && v.buf[v.len - 1] == ' ') v.len--; // Trim spaces // MG_INFO(("--HH [%.*s] [%.*s]", (int) k.len, k.buf, (int) v.len, v.buf)); h[i].name = k, h[i].value = v; // Success. Assign values } @@ -2737,7 +2735,7 @@ static struct mg_str s_known_types[] = { // clang-format on static struct mg_str guess_content_type(struct mg_str path, const char *extra) { - struct mg_str entry, k, v, s = mg_str(extra), asterisk = mg_str_n("*", 1); + struct mg_str entry, k, v, s = mg_str(extra); size_t i = 0; // Shrink path to its extension only @@ -2747,9 +2745,7 @@ static struct mg_str guess_content_type(struct mg_str path, const char *extra) { // Process user-provided mime type overrides, if any while (mg_span(s, &entry, &s, ',')) { - if (mg_span(entry, &k, &v, '=') && - (mg_strcmp(asterisk, k) == 0 || mg_strcmp(path, k) == 0)) - return v; + if (mg_span(entry, &k, &v, '=') && mg_strcmp(path, k) == 0) return v; } // Process built-in mime types @@ -2855,6 +2851,7 @@ void mg_http_serve_file(struct mg_connection *c, struct mg_http_message *hm, etag, (uint64_t) cl, gzip ? "Content-Encoding: gzip\r\n" : "", range, opts->extra_headers ? opts->extra_headers : ""); if (mg_strcasecmp(hm->method, mg_str("HEAD")) == 0) { + c->is_draining = 1; c->is_resp = 0; mg_fs_close(fd); } else { @@ -3215,9 +3212,7 @@ static int skip_chunk(const char *buf, int len, int *pl, int *dl) { } static void http_cb(struct mg_connection *c, int ev, void *ev_data) { - if (ev == MG_EV_READ || ev == MG_EV_CLOSE || - (ev == MG_EV_POLL && c->is_accepted && !c->is_draining && - c->recv.len > 0)) { // see #2796 + if (ev == MG_EV_READ || ev == MG_EV_CLOSE) { struct mg_http_message hm; size_t ofs = 0; // Parsing offset while (c->is_resp == 0 && ofs < c->recv.len) { @@ -3258,7 +3253,6 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { // contain a Content-length header. Other requests can also contain a // body, but their content has no defined semantics (RFC 7231) require_content_len = true; - ofs += (size_t) n; // this request has been processed } else if (is_response) { // HTTP spec 7.2 Entity body: All other responses must include a body // or Content-Length header field defined with a value of 0. @@ -3301,13 +3295,6 @@ static void http_cb(struct mg_connection *c, int ev, void *ev_data) { if (c->is_accepted) c->is_resp = 1; // Start generating response mg_call(c, MG_EV_HTTP_MSG, &hm); // User handler can clear is_resp - if (c->is_accepted) { - struct mg_str *cc = mg_http_get_header(&hm, "Connection"); - if (cc != NULL && mg_strcasecmp(*cc, mg_str("close")) == 0) { - c->is_draining = 1; // honor "Connection: close" - break; - } - } } if (ofs > 0) mg_iobuf_del(&c->recv, 0, ofs); // Delete processed data } @@ -4716,7 +4703,7 @@ static bool mg_aton6(struct mg_str str, struct mg_addr *addr) { if ((str.buf[i] >= '0' && str.buf[i] <= '9') || (str.buf[i] >= 'a' && str.buf[i] <= 'f') || (str.buf[i] >= 'A' && str.buf[i] <= 'F')) { - unsigned long val = 0; // TODO(): This loops on chars, refactor + unsigned long val; // TODO(): This loops on chars, refactor if (i > j + 3) return false; // MG_DEBUG(("%lu %lu [%.*s]", i, j, (int) (i - j + 1), &str.buf[j])); mg_str_to_num(mg_str_n(&str.buf[j], i - j + 1), 16, &val, sizeof(val)); @@ -5051,10 +5038,6 @@ struct pkt { struct dhcp *dhcp; }; -static void mg_tcpip_call(struct mg_tcpip_if *ifp, int ev, void *ev_data) { - if (ifp->fn != NULL) ifp->fn(ifp, ev, ev_data); -} - static void send_syn(struct mg_connection *c); static void mkpay(struct pkt *pkt, void *p) { @@ -5117,14 +5100,13 @@ static void onstatechange(struct mg_tcpip_if *ifp) { MG_INFO(("READY, IP: %M", mg_print_ip4, &ifp->ip)); MG_INFO((" GW: %M", mg_print_ip4, &ifp->gw)); MG_INFO((" MAC: %M", mg_print_mac, &ifp->mac)); - arp_ask(ifp, ifp->gw); // unsolicited GW ARP request + arp_ask(ifp, ifp->gw); } else if (ifp->state == MG_TCPIP_STATE_UP) { MG_ERROR(("Link up")); srand((unsigned int) mg_millis()); } else if (ifp->state == MG_TCPIP_STATE_DOWN) { MG_ERROR(("Link down")); } - mg_tcpip_call(ifp, MG_TCPIP_EV_ST_CHG, &ifp->state); } static struct ip *tx_ip(struct mg_tcpip_if *ifp, uint8_t *mac_dst, @@ -5185,25 +5167,20 @@ static void tx_dhcp(struct mg_tcpip_if *ifp, uint8_t *mac_dst, uint32_t ip_src, static const uint8_t broadcast[] = {255, 255, 255, 255, 255, 255}; -// RFC-2131 #4.3.6, #4.4.1; RFC-2132 #9.8 +// RFC-2131 #4.3.6, #4.4.1 static void tx_dhcp_request_sel(struct mg_tcpip_if *ifp, uint32_t ip_req, uint32_t ip_srv) { uint8_t opts[] = { - 53, 1, 3, // Type: DHCP request - 12, 3, 'm', 'i', 'p', // Host name: "mip" - 54, 4, 0, 0, 0, 0, // DHCP server ID - 50, 4, 0, 0, 0, 0, // Requested IP - 55, 2, 1, 3, 255, 255, // GW, mask [DNS] [SNTP] - 255 // End of options + 53, 1, 3, // Type: DHCP request + 55, 2, 1, 3, // GW and mask + 12, 3, 'm', 'i', 'p', // Host name: "mip" + 54, 4, 0, 0, 0, 0, // DHCP server ID + 50, 4, 0, 0, 0, 0, // Requested IP + 255 // End of options }; - uint8_t addopts = 0; - memcpy(opts + 10, &ip_srv, sizeof(ip_srv)); - memcpy(opts + 16, &ip_req, sizeof(ip_req)); - if (ifp->enable_req_dns) opts[24 + addopts++] = 6; // DNS - if (ifp->enable_req_sntp) opts[24 + addopts++] = 42; // SNTP - opts[21] += addopts; - tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, - sizeof(opts) + addopts - 2, false); + memcpy(opts + 14, &ip_srv, sizeof(ip_srv)); + memcpy(opts + 20, &ip_req, sizeof(ip_req)); + tx_dhcp(ifp, (uint8_t *) broadcast, 0, 0xffffffff, opts, sizeof(opts), false); MG_DEBUG(("DHCP req sent")); } @@ -5299,7 +5276,7 @@ static void rx_icmp(struct mg_tcpip_if *ifp, struct pkt *pkt) { } static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { - uint32_t ip = 0, gw = 0, mask = 0, lease = 0, dns = 0, sntp = 0; + uint32_t ip = 0, gw = 0, mask = 0, lease = 0; uint8_t msgtype = 0, state = ifp->state; // perform size check first, then access fields uint8_t *p = pkt->dhcp->options, @@ -5312,12 +5289,6 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { } else if (p[0] == 3 && p[1] == sizeof(ifp->gw) && p + 6 < end) { // GW memcpy(&gw, p + 2, sizeof(gw)); ip = pkt->dhcp->yiaddr; - } else if (ifp->enable_req_dns && p[0] == 6 && p[1] == sizeof(dns) && - p + 6 < end) { // DNS - memcpy(&dns, p + 2, sizeof(dns)); - } else if (ifp->enable_req_sntp && p[0] == 42 && p[1] == sizeof(sntp) && - p + 6 < end) { // SNTP - memcpy(&sntp, p + 2, sizeof(sntp)); } else if (p[0] == 51 && p[1] == 4 && p + 6 < end) { // Lease memcpy(&lease, p + 2, sizeof(lease)); lease = mg_ntohl(lease); @@ -5346,10 +5317,6 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { uint64_t rand; mg_random(&rand, sizeof(rand)); srand((unsigned int) (rand + mg_millis())); - if (ifp->enable_req_dns && dns != 0) - mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_DNS, &dns); - if (ifp->enable_req_sntp && sntp != 0) - mg_tcpip_call(ifp, MG_TCPIP_EV_DHCP_SNTP, &sntp); } else if (ifp->state == MG_TCPIP_STATE_READY && ifp->ip == ip) { // renew ifp->lease_expire = ifp->now + lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); @@ -5657,7 +5624,6 @@ static void rx_tcp(struct mg_tcpip_if *ifp, struct pkt *pkt) { c->is_connecting = 0; // Client connected settmout(c, MIP_TTYPE_KEEPALIVE); mg_call(c, MG_EV_CONNECT, NULL); // Let user know - if (c->is_tls_hs) mg_tls_handshake(c); } else if (c != NULL && c->is_connecting && pkt->tcp->flags != TH_ACK) { // mg_hexdump(pkt->raw.buf, pkt->raw.len); tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); @@ -5966,8 +5932,7 @@ void mg_connect_resolved(struct mg_connection *c) { if (c->is_udp && (rem_ip == 0xffffffff || rem_ip == (ifp->ip | ~ifp->mask))) { struct connstate *s = (struct connstate *) (c + 1); memset(s->mac, 0xFF, sizeof(s->mac)); // global or local broadcast - } else if (ifp->ip && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask)) && - rem_ip != ifp->gw) { // skip if gw (onstatechange -> READY -> ARP) + } else if (ifp->ip && ((rem_ip & ifp->mask) == (ifp->ip & ifp->mask))) { // If we're in the same LAN, fire an ARP lookup. MG_DEBUG(("%lu ARP lookup...", c->id)); arp_ask(ifp, rem_ip); @@ -6666,7 +6631,8 @@ void mg_rpc_add(struct mg_rpc **head, struct mg_str method, void (*fn)(struct mg_rpc_req *), void *fn_data) { struct mg_rpc *rpc = (struct mg_rpc *) calloc(1, sizeof(*rpc)); if (rpc != NULL) { - rpc->method = mg_strdup(method); + rpc->method.buf = mg_mprintf("%.*s", method.len, method.buf); + rpc->method.len = method.len; rpc->fn = fn; rpc->fn_data = fn_data; rpc->next = *head, *head = rpc; @@ -7158,12 +7124,6 @@ void mg_hmac_sha256(uint8_t dst[32], uint8_t *key, size_t keysz, uint8_t *data, #define SNTP_TIME_OFFSET 2208988800U // (1970 - 1900) in seconds #define SNTP_MAX_FRAC 4294967295.0 // 2 ** 32 - 1 -static uint64_t s_boot_timestamp = 0; // Updated by SNTP - -uint64_t mg_now(void) { - return mg_millis() + s_boot_timestamp; -} - static int64_t gettimestamp(const uint32_t *data) { uint32_t sec = mg_ntohl(data[0]), frac = mg_ntohl(data[1]); if (sec) sec -= SNTP_TIME_OFFSET; @@ -7171,7 +7131,7 @@ static int64_t gettimestamp(const uint32_t *data) { } int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { - int64_t epoch_milliseconds = -1; + int64_t res = -1; int mode = len > 0 ? buf[0] & 7 : 0; int version = len > 0 ? (buf[0] >> 3) & 7 : 0; if (len < 48) { @@ -7182,36 +7142,31 @@ int64_t mg_sntp_parse(const unsigned char *buf, size_t len) { MG_ERROR(("%s", "server sent a kiss of death")); } else if (version == 4 || version == 3) { // int64_t ref = gettimestamp((uint32_t *) &buf[16]); - int64_t origin_time = gettimestamp((uint32_t *) &buf[24]); - int64_t receive_time = gettimestamp((uint32_t *) &buf[32]); - int64_t transmit_time = gettimestamp((uint32_t *) &buf[40]); - int64_t now = (int64_t) mg_millis(); - int64_t latency = (now - origin_time) - (transmit_time - receive_time); - epoch_milliseconds = transmit_time + latency / 2; - s_boot_timestamp = (uint64_t) (epoch_milliseconds - now); + int64_t t0 = gettimestamp((uint32_t *) &buf[24]); + int64_t t1 = gettimestamp((uint32_t *) &buf[32]); + int64_t t2 = gettimestamp((uint32_t *) &buf[40]); + int64_t t3 = (int64_t) mg_millis(); + int64_t delta = (t3 - t0) - (t2 - t1); + MG_VERBOSE(("%lld %lld %lld %lld delta:%lld", t0, t1, t2, t3, delta)); + res = t2 + delta / 2; } else { MG_ERROR(("unexpected version: %d", version)); } - return epoch_milliseconds; + return res; } static void sntp_cb(struct mg_connection *c, int ev, void *ev_data) { - uint64_t *expiration_time = (uint64_t *) c->data; - if (ev == MG_EV_OPEN) { - *expiration_time = mg_millis() + 3000; // Store expiration time in 3s - } else if (ev == MG_EV_CONNECT) { - mg_sntp_request(c); - } else if (ev == MG_EV_READ) { + if (ev == MG_EV_READ) { int64_t milliseconds = mg_sntp_parse(c->recv.buf, c->recv.len); if (milliseconds > 0) { - s_boot_timestamp = (uint64_t) milliseconds - mg_millis(); - mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); MG_DEBUG(("%lu got time: %lld ms from epoch", c->id, milliseconds)); + mg_call(c, MG_EV_SNTP_TIME, (uint64_t *) &milliseconds); + MG_VERBOSE(("%u.%u", (unsigned) (milliseconds / 1000), + (unsigned) (milliseconds % 1000))); } - // mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer - c->is_closing = 1; - } else if (ev == MG_EV_POLL) { - if (mg_millis() > *expiration_time) c->is_closing = 1; + mg_iobuf_del(&c->recv, 0, c->recv.len); // Free receive buffer + } else if (ev == MG_EV_CONNECT) { + mg_sntp_request(c); } else if (ev == MG_EV_CLOSE) { } (void) ev_data; @@ -7236,10 +7191,7 @@ struct mg_connection *mg_sntp_connect(struct mg_mgr *mgr, const char *url, mg_event_handler_t fn, void *fnd) { struct mg_connection *c = NULL; if (url == NULL) url = "udp://time.google.com:123"; - if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) { - c->pfn = sntp_cb; - sntp_cb(c, MG_EV_OPEN, (void *) url); - } + if ((c = mg_connect(mgr, url, fn, fnd)) != NULL) c->pfn = sntp_cb; return c; } @@ -7524,28 +7476,16 @@ static void read_conn(struct mg_connection *c) { size_t len = c->recv.size - c->recv.len; long n = -1; if (c->is_tls) { - // Do not read to the raw TLS buffer if it already has enough. - // This is to prevent overflowing c->rtls if our reads are slow - if (c->rtls.len < 16 * 1024 + 40) { // TLS record, header, MAC, padding - long m; - if (!ioalloc(c, &c->rtls)) return; - n = recv_raw(c, (char *) &c->rtls.buf[c->rtls.len], - c->rtls.size - c->rtls.len); + if (!ioalloc(c, &c->rtls)) return; + n = recv_raw(c, (char *) &c->rtls.buf[c->rtls.len], + c->rtls.size - c->rtls.len); + if (n == MG_IO_ERR && c->rtls.len == 0) { + // Close only if we have fully drained both raw (rtls) and TLS buffers + c->is_closing = 1; + } else { if (n > 0) c->rtls.len += (size_t) n; - m = c->is_tls_hs ? (long) MG_IO_WAIT : mg_tls_recv(c, buf, len); - if (n == MG_IO_ERR) { - if (c->rtls.len == 0 || m < 0) { - // Close only when we have fully drained both rtls and TLS buffers - c->is_closing = 1; // or there's nothing we can do about it. - m = -1; - } else { // see #2885 - // TLS buffer is capped to max record size, even though, there can - // be more than one record, give TLS a chance to process them. - } - } else if (c->is_tls_hs) { - mg_tls_handshake(c); - } - n = m; + if (c->is_tls_hs) mg_tls_handshake(c); + n = c->is_tls_hs ? (long) MG_IO_WAIT : mg_tls_recv(c, buf, len); } } else { n = recv_raw(c, buf, len); @@ -7613,9 +7553,8 @@ static void setsockopts(struct mg_connection *c) { void mg_connect_resolved(struct mg_connection *c) { int type = c->is_udp ? SOCK_DGRAM : SOCK_STREAM; - int proto = type == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP; int rc, af = c->rem.is_ip6 ? AF_INET6 : AF_INET; // c->rem has resolved IP - c->fd = S2PTR(socket(af, type, proto)); // Create outbound socket + c->fd = S2PTR(socket(af, type, 0)); // Create outbound socket c->is_resolving = 0; // Clear resolving flag if (FD(c) == MG_INVALID_SOCKET) { mg_error(c, "socket(): %d", MG_SOCK_ERR(-1)); @@ -7768,15 +7707,15 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) { n = 0; for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { c->is_readable = c->is_writable = 0; - if (c->is_closing) ms = 1; if (skip_iotest(c)) { // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + ms = 1; // Don't wait if TLS is ready } else { - // Don't wait if TLS is ready - if (c->rtls.len > 0 || mg_tls_pending(c) > 0) ms = 1; fds[n].fd = FD(c); if (can_read(c)) fds[n].events |= POLLIN; if (can_write(c)) fds[n].events |= POLLOUT; + if (c->is_closing) ms = 1; n++; } } @@ -7792,6 +7731,8 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) { for (struct mg_connection *c = mgr->conns; c != NULL; c = c->next) { if (skip_iotest(c)) { // Socket not valid, ignore + } else if (c->rtls.len > 0 || mg_tls_pending(c) > 0) { + c->is_readable = 1; } else { if (fds[n].revents & POLLERR) { mg_error(c, "socket error"); @@ -7823,7 +7764,7 @@ static void mg_iotest(struct mg_mgr *mgr, int ms) { if (can_write(c)) FD_SET(FD(c), &wset); if (c->rtls.len > 0 || mg_tls_pending(c) > 0) tvp = &tv_zero; if (FD(c) > maxfd) maxfd = FD(c); - if (c->is_closing) tvp = &tv_zero; + if (c->is_closing) ms = 1; } if ((rc = select((int) maxfd + 1, &rset, &wset, &eset, tvp)) < 0) { @@ -7859,8 +7800,8 @@ static bool mg_socketpair(MG_SOCKET_TYPE sp[2], union usa usa[2]) { *(uint32_t *) &usa->sin.sin_addr = mg_htonl(0x7f000001U); // 127.0.0.1 usa[1] = usa[0]; - if ((sp[0] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != MG_INVALID_SOCKET && - (sp[1] = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP)) != MG_INVALID_SOCKET && + if ((sp[0] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && + (sp[1] = socket(AF_INET, SOCK_DGRAM, 0)) != MG_INVALID_SOCKET && bind(sp[0], &usa[0].sa, n) == 0 && // bind(sp[1], &usa[1].sa, n) == 0 && // getsockname(sp[0], &usa[0].sa, &n) == 0 && // @@ -8003,7 +7944,7 @@ static char *mg_ssi(const char *path, const char *root, int depth) { if (intag && ch == '>' && buf[len - 1] == '-' && buf[len - 2] == '-') { buf[len++] = (char) (ch & 0xff); buf[len] = '\0'; - if (sscanf(buf, "