| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860 |
- /*
- * libwebsockets - small server side websockets and web server implementation
- *
- * Copyright (C) 2010 - 2019 Andy Green <[email protected]>
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to
- * deal in the Software without restriction, including without limitation the
- * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- * sell copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in
- * all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- * IN THE SOFTWARE.
- */
- #include "private-lib-core.h"
- #include <errno.h>
- #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
- static int
- interface_to_sa(struct lws_vhost *vh, const char *ifname,
- struct sockaddr_in *addr, size_t addrlen, int allow_ipv6)
- {
- int ipv6 = 0;
- #ifdef LWS_WITH_IPV6
- if (allow_ipv6)
- ipv6 = LWS_IPV6_ENABLED(vh);
- #endif
- (void)vh;
- return lws_interface_to_sa(ipv6, ifname, addr, addrlen);
- }
- #endif
- #ifndef LWS_PLAT_OPTEE
- static int
- lws_get_addresses(struct lws_vhost *vh, void *ads, char *name,
- int name_len, char *rip, int rip_len)
- {
- struct addrinfo ai, *res;
- struct sockaddr_in addr4;
- rip[0] = '\0';
- name[0] = '\0';
- addr4.sin_family = AF_UNSPEC;
- #ifdef LWS_WITH_IPV6
- if (LWS_IPV6_ENABLED(vh)) {
- if (!lws_plat_inet_ntop(AF_INET6,
- &((struct sockaddr_in6 *)ads)->sin6_addr,
- rip, rip_len)) {
- lwsl_err("inet_ntop: %s", strerror(LWS_ERRNO));
- return -1;
- }
- // Strip off the IPv4 to IPv6 header if one exists
- if (strncmp(rip, "::ffff:", 7) == 0)
- memmove(rip, rip + 7, strlen(rip) - 6);
- getnameinfo((struct sockaddr *)ads, sizeof(struct sockaddr_in6),
- name, name_len, NULL, 0, 0);
- return 0;
- } else
- #endif
- {
- struct addrinfo *result;
- memset(&ai, 0, sizeof ai);
- ai.ai_family = PF_UNSPEC;
- ai.ai_socktype = SOCK_STREAM;
- #if !defined(LWS_PLAT_FREERTOS)
- if (getnameinfo((struct sockaddr *)ads,
- sizeof(struct sockaddr_in),
- name, name_len, NULL, 0, 0))
- return -1;
- #endif
- if (getaddrinfo(name, NULL, &ai, &result))
- return -1;
- res = result;
- while (addr4.sin_family == AF_UNSPEC && res) {
- switch (res->ai_family) {
- case AF_INET:
- addr4.sin_addr =
- ((struct sockaddr_in *)res->ai_addr)->sin_addr;
- addr4.sin_family = AF_INET;
- break;
- }
- res = res->ai_next;
- }
- freeaddrinfo(result);
- }
- if (addr4.sin_family == AF_UNSPEC)
- return -1;
- if (lws_plat_inet_ntop(AF_INET, &addr4.sin_addr, rip, rip_len) == NULL)
- return -1;
- return 0;
- }
- const char *
- lws_get_peer_simple_fd(lws_sockfd_type fd, char *name, size_t namelen)
- {
- lws_sockaddr46 sa46;
- socklen_t len = sizeof(sa46);
- if (getpeername(fd, (struct sockaddr *)&sa46, &len) < 0) {
- lws_snprintf(name, namelen, "getpeername: %s",
- strerror(LWS_ERRNO));
- return name;
- }
- lws_sa46_write_numeric_address(&sa46, name, namelen);
- return name;
- }
- const char *
- lws_get_peer_simple(struct lws *wsi, char *name, size_t namelen)
- {
- wsi = lws_get_network_wsi(wsi);
- return lws_get_peer_simple_fd(wsi->desc.sockfd, name, namelen);
- }
- #endif
- void
- lws_get_peer_addresses(struct lws *wsi, lws_sockfd_type fd, char *name,
- int name_len, char *rip, int rip_len)
- {
- #ifndef LWS_PLAT_OPTEE
- socklen_t len;
- #ifdef LWS_WITH_IPV6
- struct sockaddr_in6 sin6;
- #endif
- struct sockaddr_in sin4;
- void *p;
- rip[0] = '\0';
- name[0] = '\0';
- #ifdef LWS_WITH_IPV6
- if (LWS_IPV6_ENABLED(wsi->a.vhost)) {
- len = sizeof(sin6);
- p = &sin6;
- } else
- #endif
- {
- len = sizeof(sin4);
- p = &sin4;
- }
- if (getpeername(fd, p, &len) < 0) {
- lwsl_warn("getpeername: %s\n", strerror(LWS_ERRNO));
- goto bail;
- }
- lws_get_addresses(wsi->a.vhost, p, name, name_len, rip, rip_len);
- bail:
- #endif
- (void)wsi;
- (void)fd;
- (void)name;
- (void)name_len;
- (void)rip;
- (void)rip_len;
- }
- /* note: this returns a random port, or one of these <= 0 return codes:
- *
- * LWS_ITOSA_USABLE: the interface is usable, returned if so and sockfd invalid
- * LWS_ITOSA_NOT_EXIST: the requested iface does not even exist
- * LWS_ITOSA_NOT_USABLE: the requested iface exists but is not usable (eg, no IP)
- * LWS_ITOSA_BUSY: the port at the requested iface + port is already in use
- */
- int
- lws_socket_bind(struct lws_vhost *vhost, lws_sockfd_type sockfd, int port,
- const char *iface, int ipv6_allowed)
- {
- #ifdef LWS_WITH_UNIX_SOCK
- struct sockaddr_un serv_unix;
- #endif
- #ifdef LWS_WITH_IPV6
- struct sockaddr_in6 serv_addr6;
- #endif
- struct sockaddr_in serv_addr4;
- #ifndef LWS_PLAT_OPTEE
- socklen_t len = sizeof(struct sockaddr_storage);
- #endif
- int n;
- #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
- int m;
- #endif
- struct sockaddr_storage sin;
- struct sockaddr *v;
- memset(&sin, 0, sizeof(sin));
- #if defined(LWS_WITH_UNIX_SOCK)
- if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
- v = (struct sockaddr *)&serv_unix;
- memset(&serv_unix, 0, sizeof(serv_unix));
- serv_unix.sun_family = AF_UNIX;
- if (!iface)
- return LWS_ITOSA_NOT_EXIST;
- if (sizeof(serv_unix.sun_path) <= strlen(iface)) {
- lwsl_err("\"%s\" too long for UNIX domain socket\n",
- iface);
- return LWS_ITOSA_NOT_EXIST;
- }
- n = (int)(sizeof(uint16_t) + strlen(iface));
- strcpy(serv_unix.sun_path, iface);
- if (serv_unix.sun_path[0] == '@')
- serv_unix.sun_path[0] = '\0';
- else
- unlink(serv_unix.sun_path);
- // lwsl_hexdump_notice(v, n);
- } else
- #endif
- #if defined(LWS_WITH_IPV6) && !defined(LWS_PLAT_FREERTOS)
- if (ipv6_allowed && LWS_IPV6_ENABLED(vhost)) {
- v = (struct sockaddr *)&serv_addr6;
- n = sizeof(struct sockaddr_in6);
- memset(&serv_addr6, 0, sizeof(serv_addr6));
- if (iface) {
- m = interface_to_sa(vhost, iface,
- (struct sockaddr_in *)v, n, 1);
- if (m == LWS_ITOSA_NOT_USABLE) {
- lwsl_info("%s: netif %s: Not usable\n",
- __func__, iface);
- return m;
- }
- if (m == LWS_ITOSA_NOT_EXIST) {
- lwsl_info("%s: netif %s: Does not exist\n",
- __func__, iface);
- return m;
- }
- serv_addr6.sin6_scope_id = lws_get_addr_scope(iface);
- }
- serv_addr6.sin6_family = AF_INET6;
- serv_addr6.sin6_port = htons(port);
- } else
- #endif
- {
- v = (struct sockaddr *)&serv_addr4;
- n = sizeof(serv_addr4);
- memset(&serv_addr4, 0, sizeof(serv_addr4));
- serv_addr4.sin_addr.s_addr = INADDR_ANY;
- serv_addr4.sin_family = AF_INET;
- #if !defined(LWS_PLAT_FREERTOS) && !defined(LWS_PLAT_OPTEE)
- if (iface) {
- m = interface_to_sa(vhost, iface,
- (struct sockaddr_in *)v, n, 0);
- if (m == LWS_ITOSA_NOT_USABLE) {
- lwsl_info("%s: netif %s: Not usable\n",
- __func__, iface);
- return m;
- }
- if (m == LWS_ITOSA_NOT_EXIST) {
- lwsl_info("%s: netif %s: Does not exist\n",
- __func__, iface);
- return m;
- }
- }
- #endif
- serv_addr4.sin_port = htons(port);
- } /* ipv4 */
- /* just checking for the interface extant */
- if (sockfd == LWS_SOCK_INVALID)
- return LWS_ITOSA_USABLE;
- n = bind(sockfd, v, n);
- #ifdef LWS_WITH_UNIX_SOCK
- if (n < 0 && LWS_UNIX_SOCK_ENABLED(vhost)) {
- lwsl_err("ERROR on binding fd %d to \"%s\" (%d %d)\n",
- sockfd, iface, n, LWS_ERRNO);
- return LWS_ITOSA_NOT_EXIST;
- } else
- #endif
- if (n < 0) {
- int _lws_errno = LWS_ERRNO;
- lwsl_err("ERROR on binding fd %d to port %d (%d %d)\n",
- sockfd, port, n, _lws_errno);
- /* if something already listening, tell caller to fail permanently */
- if (_lws_errno == LWS_EADDRINUSE)
- return LWS_ITOSA_BUSY;
- /* otherwise ask caller to retry later */
- return LWS_ITOSA_NOT_EXIST;
- }
- #if defined(LWS_WITH_UNIX_SOCK) && !defined(WIN32)
- if (!port && LWS_UNIX_SOCK_ENABLED(vhost)) {
- uid_t uid = vhost->context->uid;
- gid_t gid = vhost->context->gid;
- if (vhost->unix_socket_perms) {
- if (lws_plat_user_colon_group_to_ids(
- vhost->unix_socket_perms, &uid, &gid)) {
- lwsl_err("%s: Failed to translate %s\n",
- __func__, vhost->unix_socket_perms);
- return LWS_ITOSA_NOT_EXIST;
- }
- }
- if (iface && iface[0] != '@' && uid && gid) {
- if (chown(iface, uid, gid)) {
- lwsl_err("%s: failed to set %s perms %u:%u\n",
- __func__, iface,
- (unsigned int)uid, (unsigned int)gid);
- return LWS_ITOSA_NOT_EXIST;
- }
- lwsl_notice("%s: vh %s unix skt %s perms %u:%u\n",
- __func__, vhost->name, iface,
- (unsigned int)uid, (unsigned int)gid);
- if (chmod(iface, 0660)) {
- lwsl_err("%s: failed to set %s to 0600 mode\n",
- __func__, iface);
- return LWS_ITOSA_NOT_EXIST;
- }
- }
- }
- #endif
- #ifndef LWS_PLAT_OPTEE
- if (getsockname(sockfd, (struct sockaddr *)&sin, &len) == -1)
- lwsl_warn("getsockname: %s\n", strerror(LWS_ERRNO));
- else
- #endif
- #if defined(LWS_WITH_IPV6)
- port = (sin.ss_family == AF_INET6) ?
- ntohs(((struct sockaddr_in6 *) &sin)->sin6_port) :
- ntohs(((struct sockaddr_in *) &sin)->sin_port);
- #else
- {
- struct sockaddr_in sain;
- memcpy(&sain, &sin, sizeof(sain));
- port = ntohs(sain.sin_port);
- }
- #endif
- return port;
- }
- unsigned int
- lws_retry_get_delay_ms(struct lws_context *context,
- const lws_retry_bo_t *retry, uint16_t *ctry,
- char *conceal)
- {
- uint64_t ms = 3000, pc = 30; /* sane-ish defaults if no retry table */
- uint16_t ra;
- if (conceal)
- *conceal = 0;
- if (retry) {
- if (*ctry < retry->retry_ms_table_count)
- ms = retry->retry_ms_table[*ctry];
- else
- ms = retry->retry_ms_table[
- retry->retry_ms_table_count - 1];
- /* if no percent given, use the default 30% */
- if (retry->jitter_percent)
- pc = retry->jitter_percent;
- }
- if (lws_get_random(context, &ra, sizeof(ra)) == sizeof(ra))
- ms += ((ms * pc * ra) >> 16) / 100;
- else
- assert(0);
- if (*ctry < 0xffff)
- (*ctry)++;
- if (retry && conceal)
- *conceal = (int)*ctry <= retry->conceal_count;
- return (unsigned int)ms;
- }
- int
- lws_retry_sul_schedule(struct lws_context *context, int tid,
- lws_sorted_usec_list_t *sul,
- const lws_retry_bo_t *retry, sul_cb_t cb, uint16_t *ctry)
- {
- char conceal;
- uint64_t ms = lws_retry_get_delay_ms(context, retry, ctry, &conceal);
- if (!conceal)
- return 1;
- lwsl_info("%s: sul %p: scheduling retry in %dms\n", __func__, sul,
- (int)ms);
- lws_sul_schedule(context, tid, sul, cb, ms * 1000);
- return 0;
- }
- int
- lws_retry_sul_schedule_retry_wsi(struct lws *wsi, lws_sorted_usec_list_t *sul,
- sul_cb_t cb, uint16_t *ctry)
- {
- return lws_retry_sul_schedule(wsi->a.context, wsi->tsi, sul,
- wsi->retry_policy, cb, ctry);
- }
- #if defined(LWS_WITH_IPV6)
- unsigned long
- lws_get_addr_scope(const char *ifname_or_ipaddr)
- {
- unsigned long scope;
- char ip[NI_MAXHOST];
- unsigned int i;
- #if !defined(WIN32)
- struct ifaddrs *addrs, *addr;
- #else
- PIP_ADAPTER_ADDRESSES adapter, addrs = NULL;
- PIP_ADAPTER_UNICAST_ADDRESS addr;
- struct sockaddr_in6 *sockaddr;
- ULONG size = 0;
- int found = 0;
- DWORD ret;
- #endif
- /*
- * First see if we can look the string up as a network interface name...
- * windows vista+ also has this
- */
- scope = if_nametoindex(ifname_or_ipaddr);
- if (scope > 0)
- /* we found it from the interface name lookup */
- return scope;
- /*
- * if not, try to look it up as an IP -> interface -> interface index
- */
- scope = 0;
- #if !defined(WIN32)
- getifaddrs(&addrs);
- for (addr = addrs; addr; addr = addr->ifa_next) {
- if (!addr->ifa_addr ||
- addr->ifa_addr->sa_family != AF_INET6)
- continue;
- ip[0] = '\0';
- getnameinfo(addr->ifa_addr,
- sizeof(struct sockaddr_in6),
- ip, sizeof(ip),
- NULL, 0, NI_NUMERICHOST);
- i = 0;
- while (ip[i])
- if (ip[i++] == '%') {
- ip[i - 1] = '\0';
- break;
- }
- if (!strcmp(ip, ifname_or_ipaddr)) {
- scope = if_nametoindex(addr->ifa_name);
- break;
- }
- }
- freeifaddrs(addrs);
- #else
- for (i = 0; i < 5; i++)
- {
- ret = GetAdaptersAddresses(AF_INET6, GAA_FLAG_INCLUDE_PREFIX,
- NULL, addrs, &size);
- if ((ret == NO_ERROR) || (ret == ERROR_NO_DATA)) {
- break;
- } else if (ret == ERROR_BUFFER_OVERFLOW)
- {
- if (addrs)
- free(addrs);
- addrs = (IP_ADAPTER_ADDRESSES *)malloc(size);
- } else
- {
- if (addrs)
- {
- free(addrs);
- addrs = NULL;
- }
- lwsl_err("Failed to get IPv6 address table (%d)", ret);
- break;
- }
- }
- if ((ret == NO_ERROR) && (addrs)) {
- adapter = addrs;
- while (adapter && !found) {
- addr = adapter->FirstUnicastAddress;
- while (addr && !found) {
- if (addr->Address.lpSockaddr->sa_family ==
- AF_INET6) {
- sockaddr = (struct sockaddr_in6 *)
- (addr->Address.lpSockaddr);
- lws_plat_inet_ntop(sockaddr->sin6_family,
- &sockaddr->sin6_addr,
- ip, sizeof(ip));
- if (!strcmp(ip, ifname_or_ipaddr)) {
- scope = sockaddr->sin6_scope_id;
- found = 1;
- break;
- }
- }
- addr = addr->Next;
- }
- adapter = adapter->Next;
- }
- }
- if (addrs)
- free(addrs);
- #endif
- return scope;
- }
- #endif
- /*
- * https://en.wikipedia.org/wiki/IPv6_address
- *
- * An IPv6 address is represented as eight groups of four hexadecimal digits,
- * each group representing 16 bits (two octets, a group sometimes also called a
- * hextet[6][7]). The groups are separated by colons (:). An example of an IPv6
- * address is:
- *
- * 2001:0db8:85a3:0000:0000:8a2e:0370:7334
- *
- * The hexadecimal digits are case-insensitive, but IETF recommendations suggest
- * the use of lower case letters. The full representation of eight 4-digit
- * groups may be simplified by several techniques, eliminating parts of the
- * representation.
- *
- * Leading zeroes in a group may be omitted, but each group must retain at least
- * one hexadecimal digit.[1] Thus, the example address may be written as:
- *
- * 2001:db8:85a3:0:0:8a2e:370:7334
- *
- * One or more consecutive groups containing zeros only may be replaced with a
- * single empty group, using two consecutive colons (::).[1] The substitution
- * may only be applied once in the address, however, because multiple
- * occurrences would create an ambiguous representation. Thus, the example
- * address can be further simplified:
- *
- * 2001:db8:85a3::8a2e:370:7334
- *
- * The localhost (loopback) address, 0:0:0:0:0:0:0:1, and the IPv6 unspecified
- * address, 0:0:0:0:0:0:0:0, are reduced to ::1 and ::, respectively.
- *
- * During the transition of the Internet from IPv4 to IPv6, it is typical to
- * operate in a mixed addressing environment. For such use cases, a special
- * notation has been introduced, which expresses IPv4-mapped and IPv4-compatible
- * IPv6 addresses by writing the least-significant 32 bits of an address in the
- * familiar IPv4 dot-decimal notation, whereas the other 96 (most significant)
- * bits are written in IPv6 format. For example, the IPv4-mapped IPv6 address
- * ::ffff:c000:0280 is written as ::ffff:192.0.2.128, thus expressing clearly
- * the original IPv4 address that was mapped to IPv6.
- */
- int
- lws_parse_numeric_address(const char *ads, uint8_t *result, size_t max_len)
- {
- struct lws_tokenize ts;
- uint8_t *orig = result, temp[16];
- int sects = 0, ipv6 = !!strchr(ads, ':'), skip_point = -1, dm = 0;
- char t[5];
- size_t n;
- long u;
- lws_tokenize_init(&ts, ads, LWS_TOKENIZE_F_NO_INTEGERS |
- LWS_TOKENIZE_F_MINUS_NONTERM);
- ts.len = strlen(ads);
- if (!ipv6 && ts.len < 7)
- return -1;
- if (ipv6 && ts.len < 2)
- return -2;
- if (!ipv6 && max_len < 4)
- return -3;
- if (ipv6 && max_len < 16)
- return -4;
- if (ipv6)
- memset(result, 0, max_len);
- do {
- ts.e = lws_tokenize(&ts);
- switch (ts.e) {
- case LWS_TOKZE_TOKEN:
- dm = 0;
- if (ipv6) {
- if (ts.token_len > 4)
- return -1;
- memcpy(t, ts.token, ts.token_len);
- t[ts.token_len] = '\0';
- for (n = 0; n < ts.token_len; n++)
- if (t[n] < '0' || t[n] > 'f' ||
- (t[n] > '9' && t[n] < 'A') ||
- (t[n] > 'F' && t[n] < 'a'))
- return -1;
- u = strtol(t, NULL, 16);
- if (u > 0xffff)
- return -5;
- *result++ = (uint8_t)(u >> 8);
- } else {
- if (ts.token_len > 3)
- return -1;
- memcpy(t, ts.token, ts.token_len);
- t[ts.token_len] = '\0';
- for (n = 0; n < ts.token_len; n++)
- if (t[n] < '0' || t[n] > '9')
- return -1;
- u = strtol(t, NULL, 10);
- if (u > 0xff)
- return -6;
- }
- if (u < 0)
- return -7;
- *result++ = (uint8_t)u;
- sects++;
- break;
- case LWS_TOKZE_DELIMITER:
- if (dm++) {
- if (dm > 2)
- return -8;
- if (*ts.token != ':')
- return -9;
- /* back to back : */
- *result++ = 0;
- *result++ = 0;
- skip_point = lws_ptr_diff(result, orig);
- break;
- }
- if (ipv6 && orig[2] == 0xff && orig[3] == 0xff &&
- skip_point == 2) {
- /* ipv4 backwards compatible format */
- ipv6 = 0;
- memset(orig, 0, max_len);
- orig[10] = 0xff;
- orig[11] = 0xff;
- skip_point = -1;
- result = &orig[12];
- sects = 0;
- break;
- }
- if (ipv6 && *ts.token != ':')
- return -10;
- if (!ipv6 && *ts.token != '.')
- return -11;
- break;
- case LWS_TOKZE_ENDED:
- if (!ipv6 && sects == 4)
- return lws_ptr_diff(result, orig);
- if (ipv6 && sects == 8)
- return lws_ptr_diff(result, orig);
- if (skip_point != -1) {
- int ow = lws_ptr_diff(result, orig);
- /*
- * contains ...::...
- */
- if (ow == 16)
- return 16;
- memcpy(temp, &orig[skip_point], ow - skip_point);
- memset(&orig[skip_point], 0, 16 - skip_point);
- memcpy(&orig[16 - (ow - skip_point)], temp,
- ow - skip_point);
- return 16;
- }
- return -12;
- default: /* includes ENDED */
- lwsl_err("%s: malformed ip address\n",
- __func__);
- return -13;
- }
- } while (ts.e > 0 && result - orig <= (int)max_len);
- lwsl_err("%s: ended on e %d\n", __func__, ts.e);
- return -14;
- }
- int
- lws_sa46_parse_numeric_address(const char *ads, lws_sockaddr46 *sa46)
- {
- uint8_t a[16];
- int n;
- n = lws_parse_numeric_address(ads, a, sizeof(a));
- if (n < 0)
- return -1;
- #if defined(LWS_WITH_IPV6)
- if (n == 16) {
- sa46->sa6.sin6_family = AF_INET6;
- memcpy(sa46->sa6.sin6_addr.s6_addr, a,
- sizeof(sa46->sa6.sin6_addr.s6_addr));
- return 0;
- }
- #endif
- if (n != 4)
- return -1;
- sa46->sa4.sin_family = AF_INET;
- memcpy(&sa46->sa4.sin_addr.s_addr, a,
- sizeof(sa46->sa4.sin_addr.s_addr));
- return 0;
- }
- int
- lws_write_numeric_address(const uint8_t *ads, int size, char *buf, size_t len)
- {
- char c, elided = 0, soe = 0, zb = -1, n, ipv4 = 0;
- const char *e = buf + len;
- char *obuf = buf;
- int q = 0;
- if (size == 4)
- return lws_snprintf(buf, len, "%u.%u.%u.%u",
- ads[0], ads[1], ads[2], ads[3]);
- if (size != 16)
- return -1;
- for (c = 0; c < (char)size / 2; c++) {
- uint16_t v = (ads[q] << 8) | ads[q + 1];
- if (buf + 8 > e)
- return -1;
- q += 2;
- if (soe) {
- if (v)
- *buf++ = ':';
- /* fall thru to print hex value */
- } else
- if (!elided && !soe && !v) {
- elided = soe = 1;
- zb = c;
- continue;
- }
- if (ipv4) {
- n = lws_snprintf(buf, e - buf, "%u.%u",
- ads[q - 2], ads[q - 1]);
- buf += n;
- if (c == 6)
- *buf++ = '.';
- } else {
- if (soe && !v)
- continue;
- if (c)
- *buf++ = ':';
- buf += lws_snprintf(buf, e - buf, "%x", v);
- if (soe && v) {
- soe = 0;
- if (c == 5 && v == 0xffff && !zb) {
- ipv4 = 1;
- *buf++ = ':';
- }
- }
- }
- }
- if (buf + 3 > e)
- return -1;
- if (soe) { /* as is the case for all zeros */
- *buf++ = ':';
- *buf++ = ':';
- *buf = '\0';
- }
- return lws_ptr_diff(buf, obuf);
- }
- int
- lws_sa46_write_numeric_address(lws_sockaddr46 *sa46, char *buf, size_t len)
- {
- *buf = '\0';
- #if defined(LWS_WITH_IPV6)
- if (sa46->sa4.sin_family == AF_INET6)
- return lws_write_numeric_address(
- (uint8_t *)&sa46->sa6.sin6_addr, 16, buf, len);
- #endif
- if (sa46->sa4.sin_family == AF_INET)
- return lws_write_numeric_address(
- (uint8_t *)&sa46->sa4.sin_addr, 4, buf, len);
- return -1;
- }
- int
- lws_sa46_compare_ads(const lws_sockaddr46 *sa46a, const lws_sockaddr46 *sa46b)
- {
- if (sa46a->sa4.sin_family != sa46b->sa4.sin_family)
- return 1;
- #if defined(LWS_WITH_IPV6)
- if (sa46a->sa4.sin_family == AF_INET6)
- return memcmp(&sa46a->sa6.sin6_addr, &sa46b->sa6.sin6_addr, 16);
- #endif
- return sa46a->sa4.sin_addr.s_addr != sa46b->sa4.sin_addr.s_addr;
- }
- #if defined(LWS_WITH_SYS_STATE)
- lws_state_manager_t *
- lws_system_get_state_manager(struct lws_context *context)
- {
- return &context->mgr_system;
- }
- #endif
|