Project homepage Mailing List  API Docs  Github Mirror 
{"schema":"libjg2-1", "vpath":"/git/", "avatar":"/git/avatar/", "alang":"en-US,en;q\u003d0.5", "gen_ut":1606540207, "reponame":"libwebsockets", "desc":"libwebsockets lightweight C networking library", "owner": { "name": "Andy Green", "email": "", "md5": "c50933ca2aa61e0fe2c43d46bb6b59cb" },"url":"", "f":3, "items": [ {"schema":"libjg2-1", "cid":"79706954af5444465d41c290fcb62313", "oid":{ "oid": "41240965cf0359128c7c51cd35d6bd6d0bc95bb0", "alias": [ "refs/heads/main","refs/heads/master"]},"blobname": "lib/system/async-dns/async-dns-parse.c", "blob": "/*\n * libwebsockets - small server side websockets and web server implementation\n *\n * Copyright (C) 2010 - 2019 Andy Green \\u003e\n *\n * Permission is hereby granted, free of charge, to any person obtaining a copy\n * of this software and associated documentation files (the \u0022Software\u0022), to\n * deal in the Software without restriction, including without limitation the\n * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or\n * sell copies of the Software, and to permit persons to whom the Software is\n * furnished to do so, subject to the following conditions:\n *\n * The above copyright notice and this permission notice shall be included in\n * all copies or substantial portions of the Software.\n *\n * THE SOFTWARE IS PROVIDED \u0022AS IS\u0022, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\n * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\n * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\n * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\n * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\n * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\n * IN THE SOFTWARE.\n */\n\n#include \u0022private-lib-core.h\u0022\n#include \u0022private-lib-async-dns.h\u0022\n\n\n/* updates *dest, returns chars used from ls directly, else -1 for fail */\n\nstatic int\nlws_adns_parse_label(const uint8_t *pkt, int len, const uint8_t *ls, int budget,\n\t\t char **dest, int dl)\n{\n\tconst uint8_t *e \u003d pkt + len, *ols \u003d ls;\n\tchar pointer \u003d 0, first \u003d 1;\n\tuint8_t ll;\n\tint n;\n\n\tif (budget \u003c 1)\n\t\treturn 0;\n\n\t/* caller must catch end of labels */\n\tassert(*ls);\n\nagain1:\n\tif (ls \u003e\u003d e)\n\t\treturn -1;\n\n\tif (((*ls) \u0026 0xc0) \u003d\u003d 0xc0) {\n\t\tif (budget \u003c 2)\n\t\t\treturn -1;\n\t\t/* pointer into message pkt to name to actually use */\n\t\tn \u003d lws_ser_ru16be(ls) \u0026 0x3fff;\n\t\tif (n \u003e\u003d len) {\n\t\t\tlwsl_notice(\u0022%s: illegal name pointer\u005cn\u0022, __func__);\n\n\t\t\treturn -1;\n\t\t}\n\n\t\t/* dereference the label pointer */\n\t\tls \u003d pkt + n;\n\n\t\t/* are we being fuzzed or messed with? */\n\t\tif (((*ls) \u0026 0xc0) \u003d\u003d 0xc0) {\n\t\t\t/* ... pointer to pointer is unreasonable */\n\t\t\tlwsl_notice(\u0022%s: label ptr to ptr invalid\u005cn\u0022, __func__);\n\n\t\t\treturn -1;\n\t\t}\n\t\tpointer \u003d 1;\n\t}\n\n\tif (ls \u003e\u003d e)\n\t\treturn -1;\n\n\tll \u003d *ls++;\n\tif (ls + ll + 1 \u003e e) {\n\t\tlwsl_notice(\u0022%s: label len invalid, %d vs %d\u005cn\u0022, __func__,\n\t\t\t lws_ptr_diff((ls + ll + 1), pkt), lws_ptr_diff(e, pkt));\n\n\t\treturn -1;\n\t}\n\tif (ll \u003e budget) {\n\t\tlwsl_notice(\u0022%s: label too long %d vs %d\u005cn\u0022, __func__, ll, budget);\n\n\t\treturn -1;\n\t}\n\n\tif (ll + 2 \u003e dl) {\n\t\tlwsl_notice(\u0022%s: qname too large\u005cn\u0022, __func__);\n\n\t\treturn -1;\n\t}\n\n\t/* copy the label content into place */\n\n\tmemcpy(*dest, ls, ll);\n\t(*dest)[ll] \u003d '.';\n\t(*dest)[ll + 1] \u003d '\u005c0';\n\t*dest +\u003d ll + 1;\n\tls +\u003d ll;\n\n\tif (pointer) {\n\t\tif (*ls)\n\t\t\tgoto again1;\n\n\t\t/*\n\t\t * special fun rule... if whole qname was a pointer label,\n\t\t * it has no 00 terminator afterwards\n\t\t */\n\t\tif (first)\n\t\t\treturn 2; /* we just took the 16-bit pointer */\n\n\t\treturn 3;\n\t}\n\n\tfirst \u003d 0;\n\n\tif (*ls)\n\t\tgoto again1;\n\n\tls++;\n\n\treturn lws_ptr_diff(ls, ols);\n}\n\ntypedef int (*lws_async_dns_find_t)(const char *name, void *opaque,\n\t\t\t\t uint32_t ttl, adns_query_type_t type,\n\t\t\t\t const uint8_t *payload);\n\n/* locally query the response packet */\n\nstruct label_stack {\n\tchar name[DNS_MAX];\n\tint enl;\n\tconst uint8_t *p;\n};\n\n/*\n * Walk the response packet, calling back to the user-provided callback for each\n * A (and AAAA if LWS_IPV6\u003d1) record with a matching name found in there.\n *\n * Able to recurse using an explicit non-CPU stack to resolve CNAME usages\n *\n * Return -1: unexpectedly failed\n * 0: found\n * 1: didn't find anything matching\n */\n\nstatic int\nlws_adns_iterate(lws_adns_q_t *q, const uint8_t *pkt, int len,\n\t\t const char *expname, lws_async_dns_find_t cb, void *opaque)\n{\n\tconst uint8_t *e \u003d pkt + len, *p, *pay;\n\tstruct label_stack stack[4];\n\tint n \u003d 0, stp \u003d 0, ansc, m;\n\tuint16_t rrtype, rrpaylen;\n\tchar *sp, inq;\n\tuint32_t ttl;\n\n\tlws_strncpy(stack[0].name, expname, sizeof(stack[0].name));\n\tstack[0].enl \u003d (int)strlen(expname);\n\nstart:\n\tansc \u003d lws_ser_ru16be(pkt + DHO_NANSWERS);\n\tp \u003d pkt + DHO_SIZEOF;\n\tinq \u003d 1;\n\n\t/*\n\t * The response also includes the query... and we have to parse it\n\t * so we can understand we reached the response... there's a QNAME\n\t * made up of labels and then 2 x 16-bit fields, for query type and\n\t * query class\n\t */\n\n\n\twhile (p + 14 \u003c e \u0026\u0026 (inq || ansc)) {\n\n\t\tif (!inq \u0026\u0026 !stp)\n\t\t\tansc--;\n\n\t\t/*\n\t\t * First is the name the query applies to... two main\n\t\t * formats can appear here, one is a pointer to\n\t\t * elsewhere in the message, the other separately\n\t\t * provides len / data for each dotted \u0022label\u0022, so for\n\t\t * \\u0022 warmcat and com are given each with a\n\t\t * prepended length byte. Any of those may be a pointer\n\t\t * to somewhere else in the packet :-/\n\t\t *\n\t\t * Paranoia is appropriate since the name length must be\n\t\t * parsed out before the rest of the RR can be used and\n\t\t * we can be attacked with absolutely any crafted\n\t\t * content easily via UDP.\n\t\t *\n\t\t * So parse the name and additionally confirm it matches\n\t\t * what the query the TID belongs to actually asked for.\n\t\t */\n\n\t\tsp \u003d stack[0].name;\n\n\t\t/* while we have more labels */\n\n\t\tn \u003d lws_adns_parse_label(pkt, len, p, len, \u0026sp,\n\t\t\t\t\t sizeof(stack[0].name) -\n\t\t\t\t\t lws_ptr_diff(sp, stack[0].name));\n\t\t/* includes case name won't fit */\n\t\tif (n \u003c 0)\n\t\t\treturn -1;\n\n\t\tp +\u003d n;\n\n\t\tif (p + (inq ? 5 : 14) \u003e e)\n\t\t\treturn -1;\n\n\t\t/*\n\t\t * p is now just after the decoded RR name, pointing at: type\n\t\t *\n\t\t * We sent class \u003d 1 \u003d IN query... response must match\n\t\t */\n\n\t\tif (lws_ser_ru16be(\u0026p[2]) !\u003d 1) {\n\t\t\tlwsl_err(\u0022%s: non-IN response 0x%x\u005cn\u0022, __func__,\n\t\t\t\t\t\tlws_ser_ru16be(\u0026p[2]));\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tif (inq) {\n\t\t\tlwsl_debug(\u0022%s: reached end of inq\u005cn\u0022, __func__);\n\t\t\tinq \u003d 0;\n\t\t\tp +\u003d 4;\n\t\t\tcontinue;\n\t\t}\n\n\t\t/* carefully validate the claimed RR payload length */\n\n\t\trrpaylen \u003d lws_ser_ru16be(\u0026p[8]);\n\t\tif (p + 10 + rrpaylen \u003e e) { /* it may be \u003d\u003d e */\n\t\t\tlwsl_notice(\u0022%s: invalid RR data length\u005cn\u0022, __func__);\n\n\t\t\treturn -1;\n\t\t}\n\n\t\tttl \u003d lws_ser_ru32be(\u0026p[4]);\n\t\trrtype \u003d lws_ser_ru16be(\u0026p[0]);\n\t\tp +\u003d 10; /* point to the payload */\n\t\tpay \u003d p;\n\n\t\t/*\n\t\t * Compare the RR names, allowing for the decoded labelname\n\t\t * to have an extra '.' at the end.\n\t\t */\n\n\t\tn \u003d lws_ptr_diff(sp, stack[0].name);\n\t\tif (stack[0].name[n - 1] \u003d\u003d '.')\n\t\t\tn--;\n\n\t\tm \u003d stack[stp].enl;\n\t\tif (stack[stp].name[m - 1] \u003d\u003d '.')\n\t\t\tm--;\n\n\t\tif (n \u003c 1 || n !\u003d m ||\n\t\t strncmp(stack[0].name, stack[stp].name, n)) {\n\t\t\tlwsl_notice(\u0022%s: skipping %s vs %s\u005cn\u0022, __func__,\n\t\t\t\t\tstack[0].name, stack[stp].name);\n\t\t\tgoto skip;\n\t\t}\n\n\t\t/*\n\t\t * It's something we could be interested in...\n\t\t *\n\t\t * We can skip RRs we don't understand. But we need to deal\n\t\t * with at least these and their payloads:\n\t\t *\n\t\t * A: 4: ipv4 address\n\t\t * AAAA: 16: ipv6 address (if asked for AAAA)\n\t\t * CNAME: ?: labelized name\n\t\t *\n\t\t * If we hit a CNAME we need to try to dereference it with\n\t\t * stuff that is in the same response packet and judge it\n\t\t * from that, without losing our place here. CNAMEs may\n\t\t * point to CNAMEs to whatever depth we're willing to handle.\n\t\t */\n\n\t\tswitch (rrtype) {\n\n\t\tcase LWS_ADNS_RECORD_AAAA:\n\t\t\tif (rrpaylen !\u003d 16) {\n\t\t\t\tlwsl_err(\u0022%s: unexpected rrpaylen\u005cn\u0022, __func__);\n\t\t\t\treturn -1;\n\t\t\t}\n#if defined(LWS_WITH_IPV6)\n\t\t\tgoto do_cb;\n#else\n\t\t\tbreak;\n#endif\n\n\t\tcase LWS_ADNS_RECORD_A:\n\t\t\tif (rrpaylen !\u003d 4) {\n\t\t\t\tlwsl_err(\u0022%s: unexpected rrpaylen4\u005cn\u0022, __func__);\n\n\t\t\t\treturn -1;\n\t\t\t}\n#if defined(LWS_WITH_IPV6)\ndo_cb:\n#endif\n\t\t\tcb(stack[0].name, opaque, ttl, rrtype, p);\n\t\t\tbreak;\n\n\t\tcase LWS_ADNS_RECORD_CNAME:\n\t\t\t/*\n\t\t\t * The name the CNAME refers to MAY itself be\n\t\t\t * included elsewhere in the response packet.\n\t\t\t *\n\t\t\t * So switch tack, stack where to resume from and\n\t\t\t * search for the decoded CNAME label name definition\n\t\t\t * instead.\n\t\t\t *\n\t\t\t * First decode the CNAME label payload into the next\n\t\t\t * stack level buffer for it.\n\t\t\t */\n\n\t\t\tif (++stp \u003d\u003d (int)LWS_ARRAY_SIZE(stack)) {\n\t\t\t\tlwsl_notice(\u0022%s: CNAMEs too deep\u005cn\u0022, __func__);\n\n\t\t\t\treturn -1;\n\t\t\t}\n\t\t\tsp \u003d stack[stp].name;\n\t\t\t/* get the cname alias */\n\t\t\tn \u003d lws_adns_parse_label(pkt, len, p, rrpaylen, \u0026sp,\n\t\t\t\t\t\t sizeof(stack[stp].name) -\n\t\t\t\t\t\t lws_ptr_diff(sp, stack[stp].name));\n\t\t\t/* includes case name won't fit */\n\t\t\tif (n \u003c 0)\n\t\t\t\treturn -1;\n\n\t\t\tp +\u003d n;\n\n\t\t\tif (p + 14 \u003e e)\n\t\t\t\treturn -1;\n#if 0\n\t\t\t/* it should have exactly reached rrpaylen if only one\n\t\t\t * CNAME, else somewhere in the middle */\n\n\t\t\tif (p !\u003d pay + rrpaylen) {\n\t\t\t\tlwsl_err(\u0022%s: cname name bad len %d\u005cn\u0022, __func__, rrpaylen);\n\n\t\t\t\treturn -1;\n\t\t\t}\n#endif\n\t\t\tlwsl_notice(\u0022%s: recursing looking for %s\u005cn\u0022, __func__, stack[stp].name);\n\n\t\t\tlwsl_info(\u0022%s: recursing looking for %s\u005cn\u0022, __func__,\n\t\t\t\t\tstack[stp].name);\n\n\t\t\tstack[stp].enl \u003d lws_ptr_diff(sp, stack[stp].name);\n\t\t\t/* when we unstack, resume from here */\n\t\t\tstack[stp].p \u003d pay + rrpaylen;\n\t\t\tgoto start;\n\n\t\tdefault:\n\t\t\tbreak;\n\t\t}\n\nskip:\n\t\tp +\u003d rrpaylen;\n\t}\n\n\tif (!stp)\n\t\treturn 1; /* we didn't find anything, but we didn't error */\n\n\tlwsl_info(\u0022%s: '%s' -\u003e CNAME '%s' resolution not provided, recursing\u005cn\u0022,\n\t\t\t__func__, ((const char *)\u0026q[1]) + DNS_MAX,\n\t\t\tstack[stp].name);\n\n\t/*\n\t * This implies there wasn't any usable definition for the\n\t * CNAME in the end, eg, only AAAA when we needed an A.\n\t *\n\t * It's also legit if the DNS just returns the CNAME, and that server\n\t * did not directly know the next step in resolution of the CNAME, so\n\t * instead of putting the resolution elsewhere in the response, has\n\t * told us just the CNAME and left it to us to find out its resolution\n\t * separately.\n\t *\n\t * Reset this request to be for the CNAME, and restart the request\n\t * action with a new tid.\n\t */\n\n\tif (lws_async_dns_get_new_tid(q-\u003econtext, q))\n\t\treturn -1;\n\n\tq-\u003etid \u0026\u003d 0xfffe;\n\tq-\u003easked \u003d q-\u003eresponded \u003d 0;\n#if defined(LWS_WITH_IPV6)\n\tq-\u003esent[1] \u003d 0;\n#endif\n\tq-\u003esent[0] \u003d 0;\n\tq-\u003erecursion++;\n\tif (q-\u003erecursion \u003d\u003d DNS_RECURSION_LIMIT) {\n\t\tlwsl_err(\u0022%s: recursion overflow\u005cn\u0022, __func__);\n\n\t\treturn -1;\n\t}\n\n\tif (q-\u003efirstcache)\n\t\tlws_adns_cache_destroy(q-\u003efirstcache);\n\tq-\u003efirstcache \u003d NULL;\n\n\t/* overwrite the query name with the CNAME */\n\n\tn \u003d 0;\n\t{\n\t\tchar *cp \u003d (char *)\u0026q[1];\n\n\t\twhile (stack[stp].name[n])\n\t\t\t*cp++ \u003d tolower(stack[stp].name[n++]);\n\t\t/* trim the following . if any */\n\t\tif (n \u0026\u0026 cp[-1] \u003d\u003d '.')\n\t\t\tcp--;\n\t\t*cp \u003d '\u005c0';\n\t}\n\n\tlws_callback_on_writable(q-\u003edns-\u003ewsi);\n\n\treturn 2;\n}\n\nint\nlws_async_dns_estimate(const char *name, void *opaque, uint32_t ttl,\n\t\t\tadns_query_type_t type, const uint8_t *payload)\n{\n\tsize_t *est \u003d (size_t *)opaque, my;\n\n\tmy \u003d sizeof(struct addrinfo);\n\tif (type \u003d\u003d LWS_ADNS_RECORD_AAAA)\n\t\tmy +\u003d sizeof(struct sockaddr_in6);\n\telse\n\t\tmy +\u003d sizeof(struct sockaddr_in);\n\n\t*est +\u003d my;\n\n\treturn 0;\n}\n\nstruct adstore {\n\tconst char *name;\n\tstruct addrinfo *pos;\n\tstruct addrinfo *prev;\n\tint ctr;\n\tuint32_t smallest_ttl;\n\tuint8_t flags;\n};\n\n/*\n * Callback for each A or AAAA record, creating getaddrinfo-compatible results\n * into the preallocated exact-sized storage.\n */\nint\nlws_async_dns_store(const char *name, void *opaque, uint32_t ttl,\n\t\t adns_query_type_t type, const uint8_t *payload)\n{\n\tstruct adstore *adst \u003d (struct adstore *)opaque;\n#if defined(_DEBUG)\n\tchar buf[48];\n#endif\n\tsize_t i;\n\n\tif (ttl \u003c adst-\u003esmallest_ttl || !adst-\u003ectr)\n\t\tadst-\u003esmallest_ttl \u003d ttl;\n\n\tif (adst-\u003eprev)\n\t\tadst-\u003eprev-\u003eai_next \u003d adst-\u003epos;\n\tadst-\u003eprev \u003d adst-\u003epos;\n\n\tadst-\u003epos-\u003eai_flags \u003d 0;\n\tadst-\u003epos-\u003eai_family \u003d type \u003d\u003d LWS_ADNS_RECORD_AAAA ?\n\t\t\t\t\t\tAF_INET6 : AF_INET;\n\tadst-\u003epos-\u003eai_socktype \u003d SOCK_STREAM;\n\tadst-\u003epos-\u003eai_protocol \u003d IPPROTO_UDP; /* no meaning */\n\tadst-\u003epos-\u003eai_addrlen \u003d type \u003d\u003d LWS_ADNS_RECORD_AAAA ?\n\t\t\t\t\t\tsizeof(struct sockaddr_in6) :\n\t\t\t\t\t\tsizeof(struct sockaddr_in);\n\tadst-\u003epos-\u003eai_canonname \u003d (char *)adst-\u003ename;\n\tadst-\u003epos-\u003eai_addr \u003d (struct sockaddr *)\u0026adst-\u003epos[1];\n\tadst-\u003epos-\u003eai_next \u003d NULL;\n\n#if defined(LWS_WITH_IPV6)\n\tif (type \u003d\u003d LWS_ADNS_RECORD_AAAA) {\n\t\tstruct sockaddr_in6 *in6 \u003d (struct sockaddr_in6 *)\u0026adst-\u003epos[1];\n\n\t\ti \u003d sizeof(*in6);\n\t\tmemset(in6, 0, i);\n\t\tin6-\u003esin6_family \u003d adst-\u003epos-\u003eai_family;\n\t\tmemcpy(in6-\u003esin6_addr.s6_addr, payload, 16);\n\t\tadst-\u003eflags |\u003d 2;\n\t} else\n#endif\n\t{\n\t\tstruct sockaddr_in *in \u003d (struct sockaddr_in *)\u0026adst-\u003epos[1];\n\n\t\ti \u003d sizeof(*in);\n\t\tmemset(in, 0, i);\n\t\tin-\u003esin_family \u003d adst-\u003epos-\u003eai_family;\n\t\tmemcpy(\u0026in-\u003esin_addr.s_addr, payload, 4);\n\t\tadst-\u003eflags |\u003d 1;\n\t}\n\n\tadst-\u003epos \u003d (struct addrinfo *)((uint8_t *)adst-\u003epos +\n\t\t\t\t\tsizeof(struct addrinfo) + i);\n\n#if defined(_DEBUG)\n\tif (lws_write_numeric_address(payload,\n\t\t\t\ttype \u003d\u003d LWS_ADNS_RECORD_AAAA ? 16 : 4,\n\t\t\t\t\t\t\tbuf, sizeof(buf)) \u003e 0)\n\t\tlwsl_info(\u0022%s: %d: %s: %s\u005cn\u0022, __func__, adst-\u003ectr,\n\t\t\t\tadst-\u003ename, buf);\n#endif\n\tadst-\u003ectr++;\n\n\treturn 0;\n}\n\n/*\n * We want to parse out all A or AAAA records\n */\n\nvoid\nlws_adns_parse_udp(lws_async_dns_t *dns, const uint8_t *pkt, size_t len)\n{\n\tconst char *nm, *nmcname;\n\tlws_adns_cache_t *c;\n\tstruct adstore adst;\n\tlws_adns_q_t *q;\n\tint n, ncname;\n\tsize_t est;\n\n\t// lwsl_hexdump_notice(pkt, len);\n\n\t/* we have to at least have the header */\n\n\tif (len \u003c DHO_SIZEOF)\n\t\treturn;\n\n\t/* we asked with one query, so anything else is bogus */\n\n\tif (lws_ser_ru16be(pkt + DHO_NQUERIES) !\u003d 1)\n\t\treturn;\n\n\t/* match both A and AAAA queries if any */\n\n\tq \u003d lws_adns_get_query(dns, 0, \u0026dns-\u003ewaiting,\n\t\t\t lws_ser_ru16be(pkt + DHO_TID), NULL);\n\tif (!q) {\n\t\tlwsl_notice(\u0022%s: dropping unknown query tid 0x%x\u005cn\u0022,\n\t\t\t __func__, lws_ser_ru16be(pkt + DHO_TID));\n\n\t\treturn;\n\t}\n\n\t/* we can get dups... drop any that have already happened */\n\n\tn \u003d 1 \u003c\u003c (lws_ser_ru16be(pkt + DHO_TID) \u0026 1);\n\tif (q-\u003eresponded \u0026 n) {\n\t\tlwsl_notice(\u0022%s: dup\u005cn\u0022, __func__);\n\t\tgoto fail_out;\n\t}\n\n\tq-\u003eresponded |\u003d n;\n\n\t/* we want to confirm the results against what we last requested... */\n\n\tnmcname \u003d ((const char *)\u0026q[1]);\n\n\t/*\n\t * First walk the packet figuring out the allocation needed for all\n\t * the results. Produce the following layout at c\n\t *\n\t * lws_adns_cache_t: new cache object\n\t * [struct addrinfo + struct sockaddr_in or _in6]: for each A or AAAA\n\t * char []: copy of resolved name\n\t */\n\n\tncname \u003d (int)strlen(nmcname) + 1;\n\n\test \u003d sizeof(lws_adns_cache_t) + ncname;\n\tif (lws_ser_ru16be(pkt + DHO_NANSWERS)) {\n\t\tint ir \u003d lws_adns_iterate(q, pkt, (int)len, nmcname,\n\t\t\t\t\t lws_async_dns_estimate, \u0026est);\n\t\tif (ir \u003c 0)\n\t\t\tgoto fail_out;\n\n\t\tif (ir \u003d\u003d 2) /* CNAME recursive resolution */\n\t\t\treturn;\n\t}\n\n\t/* but we want to create the cache entry against the original request */\n\n\tnm \u003d ((const char *)\u0026q[1]) + DNS_MAX;\n\tn \u003d (int)strlen(nm) + 1;\n\n\tlwsl_info(\u0022%s: create cache entry for %s, %zu\u005cn\u0022, __func__, nm,\n\t\t\test - sizeof(lws_adns_cache_t));\n\tc \u003d lws_malloc(est, \u0022async-dns-entry\u0022);\n\tif (!c) {\n\t\tlwsl_err(\u0022%s: OOM %zu\u005cn\u0022, __func__, est);\n\t\tgoto fail_out;\n\t}\n\tmemset(c, 0, sizeof(*c));\n\n\t/* place it at end, no need to care about alignment padding */\n\ \u003d ((const char *)c) + est - n;\n\tmemcpy((char *), nm, n);\n\n\t/*\n\t * Then walk the packet again, placing the objects we accounted for\n\t * the first time into the result allocation after the cache object\n\t * and copy of the name\n\t */\n\n\tadst.pos \u003d (struct addrinfo *)\u0026c[1];\n\tadst.prev \u003d NULL;\n\tadst.ctr \u003d 0;\n\tadst.smallest_ttl \u003d 3600;\n\tadst.flags \u003d 0;\n\n\t/*\n\t * smallest_ttl applies as it is to empty results (NXDOMAIN), or is\n\t * set to the minimum ttl seen in all the results.\n\t */\n\n\tif (lws_ser_ru16be(pkt + DHO_NANSWERS) \u0026\u0026\n\t lws_adns_iterate(q, pkt, (int)len, nmcname, lws_async_dns_store, \u0026adst) \u003c 0) {\n\t\tlws_free(c);\n\t\tgoto fail_out;\n\t}\n\n\tif (lws_ser_ru16be(pkt + DHO_NANSWERS)) {\n\t\tc-\u003eresults \u003d (struct addrinfo *)\u0026c[1];\n\t\tif (q-\u003elast) /* chain the second one on */\n\t\t\t*q-\u003elast \u003d c-\u003eresults;\n\t\telse /* first one had no results, set first guy's c-\u003eresults */\n\t\t\tif (q-\u003efirstcache)\n\t\t\t\tq-\u003efirstcache-\u003eresults \u003d c-\u003eresults;\n\t}\n\n\tif (adst.prev) /* so we know where to continue the addrinfo list */\n\t\t/* can be NULL if first resp empty */\n\t\tq-\u003elast \u003d \u0026adst.prev-\u003eai_next;\n\n\tif (q-\u003efirstcache) { /* also need to free chain when we free this guy */\n\t\tq-\u003efirstcache-\u003echain \u003d c;\n\t\tc-\u003efirstcache \u003d q-\u003efirstcache;\n\t} else {\n\n\t\tq-\u003efirstcache \u003d c;\n\t\tc-\u003eincomplete \u003d q-\u003eresponded !\u003d q-\u003easked;\n\n\t\t/*\n\t\t * Only register the first one into the cache...\n\t\t * Trim the oldest cache entry if necessary\n\t\t */\n\n\t\tlws_async_dns_trim_cache(dns);\n\n\t\t/*\n\t\t * cache the first results object... if a second one comes,\n\t\t * we won't directly register it but will chain it on to this\n\t\t * first one and continue to addinfo ai_next linked list from\n\t\t * the first into the second\n\t\t */\n\n\t\tc-\u003eflags \u003d adst.flags;\n\t\tlws_dll2_add_head(\u0026c-\u003elist, \u0026dns-\u003ecached);\n\t\tlws_sul_schedule(q-\u003econtext, 0, \u0026c-\u003esul, sul_cb_expire,\n\t\t\t\t lws_now_usecs() +\n\t\t\t\t (adst.smallest_ttl * LWS_US_PER_SEC));\n\t}\n\n\tif (q-\u003eresponded !\u003d q-\u003easked)\n\t\treturn;\n\n\t/*\n\t * Now we captured everything into the new object, return the\n\t * addrinfo results, if any, to all interested wsi, if any...\n\t */\n\n\tc-\u003eincomplete \u003d 0;\n\tlws_async_dns_complete(q, q-\u003efirstcache);\n\n\t/*\n\t * the query is completely finished with\n\t */\n\nfail_out:\n\tlws_adns_q_destroy(q);\n}\n\n","s":{"c":1606540207,"u": 438}} ],"g": 2669,"chitpc": 0,"ehitpc": 0,"indexed":0 , "ab": 1, "si": 0, "db":0, "di":0, "sat":0, "lfc": "0000"}