summaryrefslogtreecommitdiffstats
path: root/libc-top-half/musl/src/network
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-17 13:54:38 +0000
commit8c1ab65c0f548d20b7f177bdb736daaf603340e1 (patch)
treedf55b7e75bf43f2bf500845b105afe3ac3a5157e /libc-top-half/musl/src/network
parentInitial commit. (diff)
downloadwasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.tar.xz
wasi-libc-8c1ab65c0f548d20b7f177bdb736daaf603340e1.zip
Adding upstream version 0.0~git20221206.8b7148f.upstream/0.0_git20221206.8b7148f
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to '')
-rw-r--r--libc-top-half/musl/src/network/accept.c7
-rw-r--r--libc-top-half/musl/src/network/accept4.c19
-rw-r--r--libc-top-half/musl/src/network/bind.c7
-rw-r--r--libc-top-half/musl/src/network/connect.c7
-rw-r--r--libc-top-half/musl/src/network/dn_comp.c107
-rw-r--r--libc-top-half/musl/src/network/dn_expand.c33
-rw-r--r--libc-top-half/musl/src/network/dn_skipname.c15
-rw-r--r--libc-top-half/musl/src/network/dns_parse.c33
-rw-r--r--libc-top-half/musl/src/network/ent.c22
-rw-r--r--libc-top-half/musl/src/network/ether.c58
-rw-r--r--libc-top-half/musl/src/network/freeaddrinfo.c16
-rw-r--r--libc-top-half/musl/src/network/gai_strerror.c25
-rw-r--r--libc-top-half/musl/src/network/getaddrinfo.c135
-rw-r--r--libc-top-half/musl/src/network/gethostbyaddr.c24
-rw-r--r--libc-top-half/musl/src/network/gethostbyaddr_r.c71
-rw-r--r--libc-top-half/musl/src/network/gethostbyname.c11
-rw-r--r--libc-top-half/musl/src/network/gethostbyname2.c25
-rw-r--r--libc-top-half/musl/src/network/gethostbyname2_r.c80
-rw-r--r--libc-top-half/musl/src/network/gethostbyname_r.c11
-rw-r--r--libc-top-half/musl/src/network/getifaddrs.c216
-rw-r--r--libc-top-half/musl/src/network/getnameinfo.c200
-rw-r--r--libc-top-half/musl/src/network/getpeername.c7
-rw-r--r--libc-top-half/musl/src/network/getservbyname.c12
-rw-r--r--libc-top-half/musl/src/network/getservbyname_r.c55
-rw-r--r--libc-top-half/musl/src/network/getservbyport.c12
-rw-r--r--libc-top-half/musl/src/network/getservbyport_r.c60
-rw-r--r--libc-top-half/musl/src/network/getsockname.c7
-rw-r--r--libc-top-half/musl/src/network/getsockopt.c41
-rw-r--r--libc-top-half/musl/src/network/h_errno.c11
-rw-r--r--libc-top-half/musl/src/network/herror.c8
-rw-r--r--libc-top-half/musl/src/network/hstrerror.c18
-rw-r--r--libc-top-half/musl/src/network/htonl.c8
-rw-r--r--libc-top-half/musl/src/network/htons.c8
-rw-r--r--libc-top-half/musl/src/network/if_freenameindex.c7
-rw-r--r--libc-top-half/musl/src/network/if_indextoname.c23
-rw-r--r--libc-top-half/musl/src/network/if_nameindex.c114
-rw-r--r--libc-top-half/musl/src/network/if_nametoindex.c18
-rw-r--r--libc-top-half/musl/src/network/in6addr_any.c3
-rw-r--r--libc-top-half/musl/src/network/in6addr_loopback.c3
-rw-r--r--libc-top-half/musl/src/network/inet_addr.c10
-rw-r--r--libc-top-half/musl/src/network/inet_aton.c41
-rw-r--r--libc-top-half/musl/src/network/inet_legacy.c32
-rw-r--r--libc-top-half/musl/src/network/inet_ntoa.c10
-rw-r--r--libc-top-half/musl/src/network/inet_ntop.c54
-rw-r--r--libc-top-half/musl/src/network/inet_pton.c71
-rw-r--r--libc-top-half/musl/src/network/listen.c7
-rw-r--r--libc-top-half/musl/src/network/lookup.h55
-rw-r--r--libc-top-half/musl/src/network/lookup_ipliteral.c55
-rw-r--r--libc-top-half/musl/src/network/lookup_name.c425
-rw-r--r--libc-top-half/musl/src/network/lookup_serv.c114
-rw-r--r--libc-top-half/musl/src/network/netlink.c52
-rw-r--r--libc-top-half/musl/src/network/netlink.h94
-rw-r--r--libc-top-half/musl/src/network/netname.c12
-rw-r--r--libc-top-half/musl/src/network/ns_parse.c171
-rw-r--r--libc-top-half/musl/src/network/ntohl.c8
-rw-r--r--libc-top-half/musl/src/network/ntohs.c8
-rw-r--r--libc-top-half/musl/src/network/proto.c84
-rw-r--r--libc-top-half/musl/src/network/recv.c6
-rw-r--r--libc-top-half/musl/src/network/recvfrom.c7
-rw-r--r--libc-top-half/musl/src/network/recvmmsg.c39
-rw-r--r--libc-top-half/musl/src/network/recvmsg.c68
-rw-r--r--libc-top-half/musl/src/network/res_init.c6
-rw-r--r--libc-top-half/musl/src/network/res_mkquery.c44
-rw-r--r--libc-top-half/musl/src/network/res_msend.c188
-rw-r--r--libc-top-half/musl/src/network/res_query.c26
-rw-r--r--libc-top-half/musl/src/network/res_querydomain.c14
-rw-r--r--libc-top-half/musl/src/network/res_send.c9
-rw-r--r--libc-top-half/musl/src/network/res_state.c9
-rw-r--r--libc-top-half/musl/src/network/resolvconf.c94
-rw-r--r--libc-top-half/musl/src/network/send.c6
-rw-r--r--libc-top-half/musl/src/network/sendmmsg.c30
-rw-r--r--libc-top-half/musl/src/network/sendmsg.c29
-rw-r--r--libc-top-half/musl/src/network/sendto.c7
-rw-r--r--libc-top-half/musl/src/network/serv.c14
-rw-r--r--libc-top-half/musl/src/network/setsockopt.c46
-rw-r--r--libc-top-half/musl/src/network/shutdown.c7
-rw-r--r--libc-top-half/musl/src/network/sockatmark.c10
-rw-r--r--libc-top-half/musl/src/network/socket.c21
-rw-r--r--libc-top-half/musl/src/network/socketpair.c25
79 files changed, 3545 insertions, 0 deletions
diff --git a/libc-top-half/musl/src/network/accept.c b/libc-top-half/musl/src/network/accept.c
new file mode 100644
index 0000000..a92406f
--- /dev/null
+++ b/libc-top-half/musl/src/network/accept.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int accept(int fd, struct sockaddr *restrict addr, socklen_t *restrict len)
+{
+ return socketcall_cp(accept, fd, addr, len, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/accept4.c b/libc-top-half/musl/src/network/accept4.c
new file mode 100644
index 0000000..59ab172
--- /dev/null
+++ b/libc-top-half/musl/src/network/accept4.c
@@ -0,0 +1,19 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <errno.h>
+#include <fcntl.h>
+#include "syscall.h"
+
+int accept4(int fd, struct sockaddr *restrict addr, socklen_t *restrict len, int flg)
+{
+ if (!flg) return accept(fd, addr, len);
+ int ret = socketcall_cp(accept4, fd, addr, len, flg, 0, 0);
+ if (ret>=0 || (errno != ENOSYS && errno != EINVAL)) return ret;
+ ret = accept(fd, addr, len);
+ if (ret<0) return ret;
+ if (flg & SOCK_CLOEXEC)
+ __syscall(SYS_fcntl, ret, F_SETFD, FD_CLOEXEC);
+ if (flg & SOCK_NONBLOCK)
+ __syscall(SYS_fcntl, ret, F_SETFL, O_NONBLOCK);
+ return ret;
+}
diff --git a/libc-top-half/musl/src/network/bind.c b/libc-top-half/musl/src/network/bind.c
new file mode 100644
index 0000000..07bb669
--- /dev/null
+++ b/libc-top-half/musl/src/network/bind.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int bind(int fd, const struct sockaddr *addr, socklen_t len)
+{
+ return socketcall(bind, fd, addr, len, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/connect.c b/libc-top-half/musl/src/network/connect.c
new file mode 100644
index 0000000..289127b
--- /dev/null
+++ b/libc-top-half/musl/src/network/connect.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int connect(int fd, const struct sockaddr *addr, socklen_t len)
+{
+ return socketcall_cp(connect, fd, addr, len, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/dn_comp.c b/libc-top-half/musl/src/network/dn_comp.c
new file mode 100644
index 0000000..f0ccd16
--- /dev/null
+++ b/libc-top-half/musl/src/network/dn_comp.c
@@ -0,0 +1,107 @@
+#include <string.h>
+#include <resolv.h>
+
+/* RFC 1035 message compression */
+
+/* label start offsets of a compressed domain name s */
+static int getoffs(short *offs, const unsigned char *base, const unsigned char *s)
+{
+ int i=0;
+ for (;;) {
+ while (*s & 0xc0) {
+ if ((*s & 0xc0) != 0xc0) return 0;
+ s = base + ((s[0]&0x3f)<<8 | s[1]);
+ }
+ if (!*s) return i;
+ if (s-base >= 0x4000) return 0;
+ offs[i++] = s-base;
+ s += *s + 1;
+ }
+}
+
+/* label lengths of an ascii domain name s */
+static int getlens(unsigned char *lens, const char *s, int l)
+{
+ int i=0,j=0,k=0;
+ for (;;) {
+ for (; j<l && s[j]!='.'; j++);
+ if (j-k-1u > 62) return 0;
+ lens[i++] = j-k;
+ if (j==l) return i;
+ k = ++j;
+ }
+}
+
+/* longest suffix match of an ascii domain with a compressed domain name dn */
+static int match(int *offset, const unsigned char *base, const unsigned char *dn,
+ const char *end, const unsigned char *lens, int nlen)
+{
+ int l, o, m=0;
+ short offs[128];
+ int noff = getoffs(offs, base, dn);
+ if (!noff) return 0;
+ for (;;) {
+ l = lens[--nlen];
+ o = offs[--noff];
+ end -= l;
+ if (l != base[o] || memcmp(base+o+1, end, l))
+ return m;
+ *offset = o;
+ m += l;
+ if (nlen) m++;
+ if (!nlen || !noff) return m;
+ end--;
+ }
+}
+
+int dn_comp(const char *src, unsigned char *dst, int space, unsigned char **dnptrs, unsigned char **lastdnptr)
+{
+ int i, j, n, m=0, offset, bestlen=0, bestoff;
+ unsigned char lens[127];
+ unsigned char **p;
+ const char *end;
+ size_t l = strnlen(src, 255);
+ if (l && src[l-1] == '.') l--;
+ if (l>253 || space<=0) return -1;
+ if (!l) {
+ *dst = 0;
+ return 1;
+ }
+ end = src+l;
+ n = getlens(lens, src, l);
+ if (!n) return -1;
+
+ p = dnptrs;
+ if (p && *p) for (p++; *p; p++) {
+ m = match(&offset, *dnptrs, *p, end, lens, n);
+ if (m > bestlen) {
+ bestlen = m;
+ bestoff = offset;
+ if (m == l)
+ break;
+ }
+ }
+
+ /* encode unmatched part */
+ if (space < l-bestlen+2+(bestlen-1 < l-1)) return -1;
+ memcpy(dst+1, src, l-bestlen);
+ for (i=j=0; i<l-bestlen; i+=lens[j++]+1)
+ dst[i] = lens[j];
+
+ /* add tail */
+ if (bestlen) {
+ dst[i++] = 0xc0 | bestoff>>8;
+ dst[i++] = bestoff;
+ } else
+ dst[i++] = 0;
+
+ /* save dst pointer */
+ if (i>2 && lastdnptr && dnptrs && *dnptrs) {
+ while (*p) p++;
+ if (p+1 < lastdnptr) {
+ *p++ = dst;
+ *p=0;
+ }
+ }
+ return i;
+}
diff --git a/libc-top-half/musl/src/network/dn_expand.c b/libc-top-half/musl/src/network/dn_expand.c
new file mode 100644
index 0000000..eac343a
--- /dev/null
+++ b/libc-top-half/musl/src/network/dn_expand.c
@@ -0,0 +1,33 @@
+#include <resolv.h>
+
+int __dn_expand(const unsigned char *base, const unsigned char *end, const unsigned char *src, char *dest, int space)
+{
+ const unsigned char *p = src;
+ char *dend, *dbegin = dest;
+ int len = -1, i, j;
+ if (p==end || space <= 0) return -1;
+ dend = dest + (space > 254 ? 254 : space);
+ /* detect reference loop using an iteration counter */
+ for (i=0; i < end-base; i+=2) {
+ /* loop invariants: p<end, dest<dend */
+ if (*p & 0xc0) {
+ if (p+1==end) return -1;
+ j = ((p[0] & 0x3f) << 8) | p[1];
+ if (len < 0) len = p+2-src;
+ if (j >= end-base) return -1;
+ p = base+j;
+ } else if (*p) {
+ if (dest != dbegin) *dest++ = '.';
+ j = *p++;
+ if (j >= end-p || j >= dend-dest) return -1;
+ while (j--) *dest++ = *p++;
+ } else {
+ *dest = 0;
+ if (len < 0) len = p+1-src;
+ return len;
+ }
+ }
+ return -1;
+}
+
+weak_alias(__dn_expand, dn_expand);
diff --git a/libc-top-half/musl/src/network/dn_skipname.c b/libc-top-half/musl/src/network/dn_skipname.c
new file mode 100644
index 0000000..eba65bb
--- /dev/null
+++ b/libc-top-half/musl/src/network/dn_skipname.c
@@ -0,0 +1,15 @@
+#include <resolv.h>
+
+int dn_skipname(const unsigned char *s, const unsigned char *end)
+{
+ const unsigned char *p = s;
+ while (p < end)
+ if (!*p) return p-s+1;
+ else if (*p>=192)
+ if (p+1<end) return p-s+2;
+ else break;
+ else
+ if (end-p<*p+1) break;
+ else p += *p + 1;
+ return -1;
+}
diff --git a/libc-top-half/musl/src/network/dns_parse.c b/libc-top-half/musl/src/network/dns_parse.c
new file mode 100644
index 0000000..e6ee19d
--- /dev/null
+++ b/libc-top-half/musl/src/network/dns_parse.c
@@ -0,0 +1,33 @@
+#include <string.h>
+#include "lookup.h"
+
+int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
+{
+ int qdcount, ancount;
+ const unsigned char *p;
+ int len;
+
+ if (rlen<12) return -1;
+ if ((r[3]&15)) return 0;
+ p = r+12;
+ qdcount = r[4]*256 + r[5];
+ ancount = r[6]*256 + r[7];
+ if (qdcount+ancount > 64) return -1;
+ while (qdcount--) {
+ while (p-r < rlen && *p-1U < 127) p++;
+ if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ return -1;
+ p += 5 + !!*p;
+ }
+ while (ancount--) {
+ while (p-r < rlen && *p-1U < 127) p++;
+ if (*p>193 || (*p==193 && p[1]>254) || p>r+rlen-6)
+ return -1;
+ p += 1 + !!*p;
+ len = p[8]*256 + p[9];
+ if (p+len > r+rlen) return -1;
+ if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
+ p += 10 + len;
+ }
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/ent.c b/libc-top-half/musl/src/network/ent.c
new file mode 100644
index 0000000..c6e0123
--- /dev/null
+++ b/libc-top-half/musl/src/network/ent.c
@@ -0,0 +1,22 @@
+#include <netdb.h>
+
+void sethostent(int x)
+{
+}
+
+struct hostent *gethostent()
+{
+ return 0;
+}
+
+struct netent *getnetent()
+{
+ return 0;
+}
+
+void endhostent(void)
+{
+}
+
+weak_alias(sethostent, setnetent);
+weak_alias(endhostent, endnetent);
diff --git a/libc-top-half/musl/src/network/ether.c b/libc-top-half/musl/src/network/ether.c
new file mode 100644
index 0000000..4304a97
--- /dev/null
+++ b/libc-top-half/musl/src/network/ether.c
@@ -0,0 +1,58 @@
+#include <stdlib.h>
+#include <netinet/ether.h>
+#include <stdio.h>
+
+struct ether_addr *ether_aton_r (const char *x, struct ether_addr *p_a)
+{
+ struct ether_addr a;
+ char *y;
+ for (int ii = 0; ii < 6; ii++) {
+ unsigned long int n;
+ if (ii != 0) {
+ if (x[0] != ':') return 0; /* bad format */
+ else x++;
+ }
+ n = strtoul (x, &y, 16);
+ x = y;
+ if (n > 0xFF) return 0; /* bad byte */
+ a.ether_addr_octet[ii] = n;
+ }
+ if (x[0] != 0) return 0; /* bad format */
+ *p_a = a;
+ return p_a;
+}
+
+struct ether_addr *ether_aton (const char *x)
+{
+ static struct ether_addr a;
+ return ether_aton_r (x, &a);
+}
+
+char *ether_ntoa_r (const struct ether_addr *p_a, char *x) {
+ char *y;
+ y = x;
+ for (int ii = 0; ii < 6; ii++) {
+ x += sprintf (x, ii == 0 ? "%.2X" : ":%.2X", p_a->ether_addr_octet[ii]);
+ }
+ return y;
+}
+
+char *ether_ntoa (const struct ether_addr *p_a) {
+ static char x[18];
+ return ether_ntoa_r (p_a, x);
+}
+
+int ether_line(const char *l, struct ether_addr *e, char *hostname)
+{
+ return -1;
+}
+
+int ether_ntohost(char *hostname, const struct ether_addr *e)
+{
+ return -1;
+}
+
+int ether_hostton(const char *hostname, struct ether_addr *e)
+{
+ return -1;
+}
diff --git a/libc-top-half/musl/src/network/freeaddrinfo.c b/libc-top-half/musl/src/network/freeaddrinfo.c
new file mode 100644
index 0000000..62241c2
--- /dev/null
+++ b/libc-top-half/musl/src/network/freeaddrinfo.c
@@ -0,0 +1,16 @@
+#include <stdlib.h>
+#include <stddef.h>
+#include <netdb.h>
+#include "lookup.h"
+#include "lock.h"
+
+void freeaddrinfo(struct addrinfo *p)
+{
+ size_t cnt;
+ for (cnt=1; p->ai_next; cnt++, p=p->ai_next);
+ struct aibuf *b = (void *)((char *)p - offsetof(struct aibuf, ai));
+ b -= b->slot;
+ LOCK(b->lock);
+ if (!(b->ref -= cnt)) free(b);
+ else UNLOCK(b->lock);
+}
diff --git a/libc-top-half/musl/src/network/gai_strerror.c b/libc-top-half/musl/src/network/gai_strerror.c
new file mode 100644
index 0000000..9596580
--- /dev/null
+++ b/libc-top-half/musl/src/network/gai_strerror.c
@@ -0,0 +1,25 @@
+#include <netdb.h>
+#include "locale_impl.h"
+
+static const char msgs[] =
+ "Invalid flags\0"
+ "Name does not resolve\0"
+ "Try again\0"
+ "Non-recoverable error\0"
+ "Unknown error\0"
+ "Unrecognized address family or invalid length\0"
+ "Unrecognized socket type\0"
+ "Unrecognized service\0"
+ "Unknown error\0"
+ "Out of memory\0"
+ "System error\0"
+ "Overflow\0"
+ "\0Unknown error";
+
+const char *gai_strerror(int ecode)
+{
+ const char *s;
+ for (s=msgs, ecode++; ecode && *s; ecode++, s++) for (; *s; s++);
+ if (!*s) s++;
+ return LCTRANS_CUR(s);
+}
diff --git a/libc-top-half/musl/src/network/getaddrinfo.c b/libc-top-half/musl/src/network/getaddrinfo.c
new file mode 100644
index 0000000..efaab30
--- /dev/null
+++ b/libc-top-half/musl/src/network/getaddrinfo.c
@@ -0,0 +1,135 @@
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <string.h>
+#include <pthread.h>
+#include <unistd.h>
+#include <endian.h>
+#include <errno.h>
+#include "lookup.h"
+
+int getaddrinfo(const char *restrict host, const char *restrict serv, const struct addrinfo *restrict hint, struct addrinfo **restrict res)
+{
+ struct service ports[MAXSERVS];
+ struct address addrs[MAXADDRS];
+ char canon[256], *outcanon;
+ int nservs, naddrs, nais, canon_len, i, j, k;
+ int family = AF_UNSPEC, flags = 0, proto = 0, socktype = 0;
+ struct aibuf *out;
+
+ if (!host && !serv) return EAI_NONAME;
+
+ if (hint) {
+ family = hint->ai_family;
+ flags = hint->ai_flags;
+ proto = hint->ai_protocol;
+ socktype = hint->ai_socktype;
+
+ const int mask = AI_PASSIVE | AI_CANONNAME | AI_NUMERICHOST |
+ AI_V4MAPPED | AI_ALL | AI_ADDRCONFIG | AI_NUMERICSERV;
+ if ((flags & mask) != flags)
+ return EAI_BADFLAGS;
+
+ switch (family) {
+ case AF_INET:
+ case AF_INET6:
+ case AF_UNSPEC:
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+ }
+
+ if (flags & AI_ADDRCONFIG) {
+ /* Define the "an address is configured" condition for address
+ * families via ability to create a socket for the family plus
+ * routability of the loopback address for the family. */
+ static const struct sockaddr_in lo4 = {
+ .sin_family = AF_INET, .sin_port = 65535,
+ .sin_addr.s_addr = __BYTE_ORDER == __BIG_ENDIAN
+ ? 0x7f000001 : 0x0100007f
+ };
+ static const struct sockaddr_in6 lo6 = {
+ .sin6_family = AF_INET6, .sin6_port = 65535,
+ .sin6_addr = IN6ADDR_LOOPBACK_INIT
+ };
+ int tf[2] = { AF_INET, AF_INET6 };
+ const void *ta[2] = { &lo4, &lo6 };
+ socklen_t tl[2] = { sizeof lo4, sizeof lo6 };
+ for (i=0; i<2; i++) {
+ if (family==tf[1-i]) continue;
+ int s = socket(tf[i], SOCK_CLOEXEC|SOCK_DGRAM,
+ IPPROTO_UDP);
+ if (s>=0) {
+ int cs;
+ pthread_setcancelstate(
+ PTHREAD_CANCEL_DISABLE, &cs);
+ int r = connect(s, ta[i], tl[i]);
+ pthread_setcancelstate(cs, 0);
+ close(s);
+ if (!r) continue;
+ }
+ switch (errno) {
+ case EADDRNOTAVAIL:
+ case EAFNOSUPPORT:
+ case EHOSTUNREACH:
+ case ENETDOWN:
+ case ENETUNREACH:
+ break;
+ default:
+ return EAI_SYSTEM;
+ }
+ if (family == tf[i]) return EAI_NONAME;
+ family = tf[1-i];
+ }
+ }
+
+ nservs = __lookup_serv(ports, serv, proto, socktype, flags);
+ if (nservs < 0) return nservs;
+
+ naddrs = __lookup_name(addrs, canon, host, family, flags);
+ if (naddrs < 0) return naddrs;
+
+ nais = nservs * naddrs;
+ canon_len = strlen(canon);
+ out = calloc(1, nais * sizeof(*out) + canon_len + 1);
+ if (!out) return EAI_MEMORY;
+
+ if (canon_len) {
+ outcanon = (void *)&out[nais];
+ memcpy(outcanon, canon, canon_len+1);
+ } else {
+ outcanon = 0;
+ }
+
+ for (k=i=0; i<naddrs; i++) for (j=0; j<nservs; j++, k++) {
+ out[k].slot = k;
+ out[k].ai = (struct addrinfo){
+ .ai_family = addrs[i].family,
+ .ai_socktype = ports[j].socktype,
+ .ai_protocol = ports[j].proto,
+ .ai_addrlen = addrs[i].family == AF_INET
+ ? sizeof(struct sockaddr_in)
+ : sizeof(struct sockaddr_in6),
+ .ai_addr = (void *)&out[k].sa,
+ .ai_canonname = outcanon };
+ if (k) out[k-1].ai.ai_next = &out[k].ai;
+ switch (addrs[i].family) {
+ case AF_INET:
+ out[k].sa.sin.sin_family = AF_INET;
+ out[k].sa.sin.sin_port = htons(ports[j].port);
+ memcpy(&out[k].sa.sin.sin_addr, &addrs[i].addr, 4);
+ break;
+ case AF_INET6:
+ out[k].sa.sin6.sin6_family = AF_INET6;
+ out[k].sa.sin6.sin6_port = htons(ports[j].port);
+ out[k].sa.sin6.sin6_scope_id = addrs[i].scopeid;
+ memcpy(&out[k].sa.sin6.sin6_addr, &addrs[i].addr, 16);
+ break;
+ }
+ }
+ out[0].ref = nais;
+ *res = &out->ai;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/gethostbyaddr.c b/libc-top-half/musl/src/network/gethostbyaddr.c
new file mode 100644
index 0000000..598e224
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyaddr.c
@@ -0,0 +1,24 @@
+#define _GNU_SOURCE
+
+#include <netdb.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)
+{
+ static struct hostent *h;
+ size_t size = 63;
+ struct hostent *res;
+ int err;
+ do {
+ free(h);
+ h = malloc(size+=size+1);
+ if (!h) {
+ h_errno = NO_RECOVERY;
+ return 0;
+ }
+ err = gethostbyaddr_r(a, l, af, h,
+ (void *)(h+1), size-sizeof *h, &res, &h_errno);
+ } while (err == ERANGE);
+ return err ? 0 : h;
+}
diff --git a/libc-top-half/musl/src/network/gethostbyaddr_r.c b/libc-top-half/musl/src/network/gethostbyaddr_r.c
new file mode 100644
index 0000000..0f1e61a
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyaddr_r.c
@@ -0,0 +1,71 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <inttypes.h>
+
+int gethostbyaddr_r(const void *a, socklen_t l, int af,
+ struct hostent *h, char *buf, size_t buflen,
+ struct hostent **res, int *err)
+{
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sa = { .sin.sin_family = af };
+ socklen_t sl = af==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+ int i;
+
+ *res = 0;
+
+ /* Load address argument into sockaddr structure */
+ if (af==AF_INET6 && l==16) memcpy(&sa.sin6.sin6_addr, a, 16);
+ else if (af==AF_INET && l==4) memcpy(&sa.sin.sin_addr, a, 4);
+ else {
+ *err = NO_RECOVERY;
+ return EINVAL;
+ }
+
+ /* Align buffer and check for space for pointers and ip address */
+ i = (uintptr_t)buf & sizeof(char *)-1;
+ if (!i) i = sizeof(char *);
+ if (buflen <= 5*sizeof(char *)-i + l) return ERANGE;
+ buf += sizeof(char *)-i;
+ buflen -= 5*sizeof(char *)-i + l;
+
+ h->h_addr_list = (void *)buf;
+ buf += 2*sizeof(char *);
+ h->h_aliases = (void *)buf;
+ buf += 2*sizeof(char *);
+
+ h->h_addr_list[0] = buf;
+ memcpy(h->h_addr_list[0], a, l);
+ buf += l;
+ h->h_addr_list[1] = 0;
+ h->h_aliases[0] = buf;
+ h->h_aliases[1] = 0;
+
+ switch (getnameinfo((void *)&sa, sl, buf, buflen, 0, 0, 0)) {
+ case EAI_AGAIN:
+ *err = TRY_AGAIN;
+ return EAGAIN;
+ case EAI_OVERFLOW:
+ return ERANGE;
+ default:
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ case EAI_FAIL:
+ *err = NO_RECOVERY;
+ return errno;
+ case 0:
+ break;
+ }
+
+ h->h_addrtype = af;
+ h->h_length = l;
+ h->h_name = h->h_aliases[0];
+ *res = h;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/gethostbyname.c b/libc-top-half/musl/src/network/gethostbyname.c
new file mode 100644
index 0000000..bfedf52
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyname.c
@@ -0,0 +1,11 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyname(const char *name)
+{
+ return gethostbyname2(name, AF_INET);
+}
diff --git a/libc-top-half/musl/src/network/gethostbyname2.c b/libc-top-half/musl/src/network/gethostbyname2.c
new file mode 100644
index 0000000..dc9d662
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyname2.c
@@ -0,0 +1,25 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdlib.h>
+
+struct hostent *gethostbyname2(const char *name, int af)
+{
+ static struct hostent *h;
+ size_t size = 63;
+ struct hostent *res;
+ int err;
+ do {
+ free(h);
+ h = malloc(size+=size+1);
+ if (!h) {
+ h_errno = NO_RECOVERY;
+ return 0;
+ }
+ err = gethostbyname2_r(name, af, h,
+ (void *)(h+1), size-sizeof *h, &res, &h_errno);
+ } while (err == ERANGE);
+ return err ? 0 : h;
+}
diff --git a/libc-top-half/musl/src/network/gethostbyname2_r.c b/libc-top-half/musl/src/network/gethostbyname2_r.c
new file mode 100644
index 0000000..fc89487
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyname2_r.c
@@ -0,0 +1,80 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <stdint.h>
+#include "lookup.h"
+
+int gethostbyname2_r(const char *name, int af,
+ struct hostent *h, char *buf, size_t buflen,
+ struct hostent **res, int *err)
+{
+ struct address addrs[MAXADDRS];
+ char canon[256];
+ int i, cnt;
+ size_t align, need;
+
+ *res = 0;
+ cnt = __lookup_name(addrs, canon, name, af, AI_CANONNAME);
+ if (cnt<0) switch (cnt) {
+ case EAI_NONAME:
+ *err = HOST_NOT_FOUND;
+ return ENOENT;
+ case EAI_AGAIN:
+ *err = TRY_AGAIN;
+ return EAGAIN;
+ default:
+ case EAI_FAIL:
+ *err = NO_RECOVERY;
+ return EBADMSG;
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ *err = NO_RECOVERY;
+ return errno;
+ }
+
+ h->h_addrtype = af;
+ h->h_length = af==AF_INET6 ? 16 : 4;
+
+ /* Align buffer */
+ align = -(uintptr_t)buf & sizeof(char *)-1;
+
+ need = 4*sizeof(char *);
+ need += (cnt + 1) * (sizeof(char *) + h->h_length);
+ need += strlen(name)+1;
+ need += strlen(canon)+1;
+ need += align;
+
+ if (need > buflen) return ERANGE;
+
+ buf += align;
+ h->h_aliases = (void *)buf;
+ buf += 3*sizeof(char *);
+ h->h_addr_list = (void *)buf;
+ buf += (cnt+1)*sizeof(char *);
+
+ for (i=0; i<cnt; i++) {
+ h->h_addr_list[i] = (void *)buf;
+ buf += h->h_length;
+ memcpy(h->h_addr_list[i], addrs[i].addr, h->h_length);
+ }
+ h->h_addr_list[i] = 0;
+
+ h->h_name = h->h_aliases[0] = buf;
+ strcpy(h->h_name, canon);
+ buf += strlen(h->h_name)+1;
+
+ if (strcmp(h->h_name, name)) {
+ h->h_aliases[1] = buf;
+ strcpy(h->h_aliases[1], name);
+ buf += strlen(h->h_aliases[1])+1;
+ } else h->h_aliases[1] = 0;
+
+ h->h_aliases[2] = 0;
+
+ *res = h;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/gethostbyname_r.c b/libc-top-half/musl/src/network/gethostbyname_r.c
new file mode 100644
index 0000000..cd87254
--- /dev/null
+++ b/libc-top-half/musl/src/network/gethostbyname_r.c
@@ -0,0 +1,11 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+
+int gethostbyname_r(const char *name,
+ struct hostent *h, char *buf, size_t buflen,
+ struct hostent **res, int *err)
+{
+ return gethostbyname2_r(name, AF_INET, h, buf, buflen, res, err);
+}
diff --git a/libc-top-half/musl/src/network/getifaddrs.c b/libc-top-half/musl/src/network/getifaddrs.c
new file mode 100644
index 0000000..fed75bd
--- /dev/null
+++ b/libc-top-half/musl/src/network/getifaddrs.c
@@ -0,0 +1,216 @@
+#define _GNU_SOURCE
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <ifaddrs.h>
+#include <syscall.h>
+#include <net/if.h>
+#include <netinet/in.h>
+#include "netlink.h"
+
+#define IFADDRS_HASH_SIZE 64
+
+/* getifaddrs() reports hardware addresses with PF_PACKET that implies
+ * struct sockaddr_ll. But e.g. Infiniband socket address length is
+ * longer than sockaddr_ll.ssl_addr[8] can hold. Use this hack struct
+ * to extend ssl_addr - callers should be able to still use it. */
+struct sockaddr_ll_hack {
+ unsigned short sll_family, sll_protocol;
+ int sll_ifindex;
+ unsigned short sll_hatype;
+ unsigned char sll_pkttype, sll_halen;
+ unsigned char sll_addr[24];
+};
+
+union sockany {
+ struct sockaddr sa;
+ struct sockaddr_ll_hack ll;
+ struct sockaddr_in v4;
+ struct sockaddr_in6 v6;
+};
+
+struct ifaddrs_storage {
+ struct ifaddrs ifa;
+ struct ifaddrs_storage *hash_next;
+ union sockany addr, netmask, ifu;
+ unsigned int index;
+ char name[IFNAMSIZ+1];
+};
+
+struct ifaddrs_ctx {
+ struct ifaddrs_storage *first;
+ struct ifaddrs_storage *last;
+ struct ifaddrs_storage *hash[IFADDRS_HASH_SIZE];
+};
+
+void freeifaddrs(struct ifaddrs *ifp)
+{
+ struct ifaddrs *n;
+ while (ifp) {
+ n = ifp->ifa_next;
+ free(ifp);
+ ifp = n;
+ }
+}
+
+static void copy_addr(struct sockaddr **r, int af, union sockany *sa, void *addr, size_t addrlen, int ifindex)
+{
+ uint8_t *dst;
+ int len;
+
+ switch (af) {
+ case AF_INET:
+ dst = (uint8_t*) &sa->v4.sin_addr;
+ len = 4;
+ break;
+ case AF_INET6:
+ dst = (uint8_t*) &sa->v6.sin6_addr;
+ len = 16;
+ if (IN6_IS_ADDR_LINKLOCAL(addr) || IN6_IS_ADDR_MC_LINKLOCAL(addr))
+ sa->v6.sin6_scope_id = ifindex;
+ break;
+ default:
+ return;
+ }
+ if (addrlen < len) return;
+ sa->sa.sa_family = af;
+ memcpy(dst, addr, len);
+ *r = &sa->sa;
+}
+
+static void gen_netmask(struct sockaddr **r, int af, union sockany *sa, int prefixlen)
+{
+ uint8_t addr[16] = {0};
+ int i;
+
+ if (prefixlen > 8*sizeof(addr)) prefixlen = 8*sizeof(addr);
+ i = prefixlen / 8;
+ memset(addr, 0xff, i);
+ if (i < sizeof(addr)) addr[i++] = 0xff << (8 - (prefixlen % 8));
+ copy_addr(r, af, sa, addr, sizeof(addr), 0);
+}
+
+static void copy_lladdr(struct sockaddr **r, union sockany *sa, void *addr, size_t addrlen, int ifindex, unsigned short hatype)
+{
+ if (addrlen > sizeof(sa->ll.sll_addr)) return;
+ sa->ll.sll_family = AF_PACKET;
+ sa->ll.sll_ifindex = ifindex;
+ sa->ll.sll_hatype = hatype;
+ sa->ll.sll_halen = addrlen;
+ memcpy(sa->ll.sll_addr, addr, addrlen);
+ *r = &sa->sa;
+}
+
+static int netlink_msg_to_ifaddr(void *pctx, struct nlmsghdr *h)
+{
+ struct ifaddrs_ctx *ctx = pctx;
+ struct ifaddrs_storage *ifs, *ifs0;
+ struct ifinfomsg *ifi = NLMSG_DATA(h);
+ struct ifaddrmsg *ifa = NLMSG_DATA(h);
+ struct rtattr *rta;
+ int stats_len = 0;
+
+ if (h->nlmsg_type == RTM_NEWLINK) {
+ for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
+ if (rta->rta_type != IFLA_STATS) continue;
+ stats_len = RTA_DATALEN(rta);
+ break;
+ }
+ } else {
+ for (ifs0 = ctx->hash[ifa->ifa_index % IFADDRS_HASH_SIZE]; ifs0; ifs0 = ifs0->hash_next)
+ if (ifs0->index == ifa->ifa_index)
+ break;
+ if (!ifs0) return 0;
+ }
+
+ ifs = calloc(1, sizeof(struct ifaddrs_storage) + stats_len);
+ if (ifs == 0) return -1;
+
+ if (h->nlmsg_type == RTM_NEWLINK) {
+ ifs->index = ifi->ifi_index;
+ ifs->ifa.ifa_flags = ifi->ifi_flags;
+
+ for (rta = NLMSG_RTA(h, sizeof(*ifi)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
+ switch (rta->rta_type) {
+ case IFLA_IFNAME:
+ if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
+ memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
+ ifs->ifa.ifa_name = ifs->name;
+ }
+ break;
+ case IFLA_ADDRESS:
+ copy_lladdr(&ifs->ifa.ifa_addr, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
+ break;
+ case IFLA_BROADCAST:
+ copy_lladdr(&ifs->ifa.ifa_broadaddr, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifi->ifi_index, ifi->ifi_type);
+ break;
+ case IFLA_STATS:
+ ifs->ifa.ifa_data = (void*)(ifs+1);
+ memcpy(ifs->ifa.ifa_data, RTA_DATA(rta), RTA_DATALEN(rta));
+ break;
+ }
+ }
+ if (ifs->ifa.ifa_name) {
+ unsigned int bucket = ifs->index % IFADDRS_HASH_SIZE;
+ ifs->hash_next = ctx->hash[bucket];
+ ctx->hash[bucket] = ifs;
+ }
+ } else {
+ ifs->ifa.ifa_name = ifs0->ifa.ifa_name;
+ ifs->ifa.ifa_flags = ifs0->ifa.ifa_flags;
+ for (rta = NLMSG_RTA(h, sizeof(*ifa)); NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
+ switch (rta->rta_type) {
+ case IFA_ADDRESS:
+ /* If ifa_addr is already set we, received an IFA_LOCAL before
+ * so treat this as destination address */
+ if (ifs->ifa.ifa_addr)
+ copy_addr(&ifs->ifa.ifa_dstaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
+ else
+ copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
+ break;
+ case IFA_BROADCAST:
+ copy_addr(&ifs->ifa.ifa_broadaddr, ifa->ifa_family, &ifs->ifu, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
+ break;
+ case IFA_LOCAL:
+ /* If ifa_addr is set and we get IFA_LOCAL, assume we have
+ * a point-to-point network. Move address to correct field. */
+ if (ifs->ifa.ifa_addr) {
+ ifs->ifu = ifs->addr;
+ ifs->ifa.ifa_dstaddr = &ifs->ifu.sa;
+ memset(&ifs->addr, 0, sizeof(ifs->addr));
+ }
+ copy_addr(&ifs->ifa.ifa_addr, ifa->ifa_family, &ifs->addr, RTA_DATA(rta), RTA_DATALEN(rta), ifa->ifa_index);
+ break;
+ case IFA_LABEL:
+ if (RTA_DATALEN(rta) < sizeof(ifs->name)) {
+ memcpy(ifs->name, RTA_DATA(rta), RTA_DATALEN(rta));
+ ifs->ifa.ifa_name = ifs->name;
+ }
+ break;
+ }
+ }
+ if (ifs->ifa.ifa_addr)
+ gen_netmask(&ifs->ifa.ifa_netmask, ifa->ifa_family, &ifs->netmask, ifa->ifa_prefixlen);
+ }
+
+ if (ifs->ifa.ifa_name) {
+ if (!ctx->first) ctx->first = ifs;
+ if (ctx->last) ctx->last->ifa.ifa_next = &ifs->ifa;
+ ctx->last = ifs;
+ } else {
+ free(ifs);
+ }
+ return 0;
+}
+
+int getifaddrs(struct ifaddrs **ifap)
+{
+ struct ifaddrs_ctx _ctx, *ctx = &_ctx;
+ int r;
+ memset(ctx, 0, sizeof *ctx);
+ r = __rtnetlink_enumerate(AF_UNSPEC, AF_UNSPEC, netlink_msg_to_ifaddr, ctx);
+ if (r == 0) *ifap = &ctx->first->ifa;
+ else freeifaddrs(&ctx->first->ifa);
+ return r;
+}
diff --git a/libc-top-half/musl/src/network/getnameinfo.c b/libc-top-half/musl/src/network/getnameinfo.c
new file mode 100644
index 0000000..949e181
--- /dev/null
+++ b/libc-top-half/musl/src/network/getnameinfo.c
@@ -0,0 +1,200 @@
+#include <netdb.h>
+#include <limits.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <net/if.h>
+#include <ctype.h>
+#include <resolv.h>
+#include "lookup.h"
+#include "stdio_impl.h"
+
+#define PTR_MAX (64 + sizeof ".in-addr.arpa")
+#define RR_PTR 12
+
+static char *itoa(char *p, unsigned x) {
+ p += 3*sizeof(int);
+ *--p = 0;
+ do {
+ *--p = '0' + x % 10;
+ x /= 10;
+ } while (x);
+ return p;
+}
+
+static void mkptr4(char *s, const unsigned char *ip)
+{
+ sprintf(s, "%d.%d.%d.%d.in-addr.arpa",
+ ip[3], ip[2], ip[1], ip[0]);
+}
+
+static void mkptr6(char *s, const unsigned char *ip)
+{
+ static const char xdigits[] = "0123456789abcdef";
+ int i;
+ for (i=15; i>=0; i--) {
+ *s++ = xdigits[ip[i]&15]; *s++ = '.';
+ *s++ = xdigits[ip[i]>>4]; *s++ = '.';
+ }
+ strcpy(s, "ip6.arpa");
+}
+
+static void reverse_hosts(char *buf, const unsigned char *a, unsigned scopeid, int family)
+{
+ char line[512], *p, *z;
+ unsigned char _buf[1032], atmp[16];
+ struct address iplit;
+ FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+ if (!f) return;
+ if (family == AF_INET) {
+ memcpy(atmp+12, a, 4);
+ memcpy(atmp, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ a = atmp;
+ }
+ while (fgets(line, sizeof line, f)) {
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+
+ for (p=line; *p && !isspace(*p); p++);
+ *p++ = 0;
+ if (__lookup_ipliteral(&iplit, line, AF_UNSPEC)<=0)
+ continue;
+
+ if (iplit.family == AF_INET) {
+ memcpy(iplit.addr+12, iplit.addr, 4);
+ memcpy(iplit.addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ iplit.scopeid = 0;
+ }
+
+ if (memcmp(a, iplit.addr, 16) || iplit.scopeid != scopeid)
+ continue;
+
+ for (; *p && isspace(*p); p++);
+ for (z=p; *z && !isspace(*z); z++);
+ *z = 0;
+ if (z-p < 256) {
+ memcpy(buf, p, z-p+1);
+ break;
+ }
+ }
+ __fclose_ca(f);
+}
+
+static void reverse_services(char *buf, int port, int dgram)
+{
+ unsigned long svport;
+ char line[128], *p, *z;
+ unsigned char _buf[1032];
+ FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
+ if (!f) return;
+ while (fgets(line, sizeof line, f)) {
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+
+ for (p=line; *p && !isspace(*p); p++);
+ if (!*p) continue;
+ *p++ = 0;
+ svport = strtoul(p, &z, 10);
+
+ if (svport != port || z==p) continue;
+ if (dgram && strncmp(z, "/udp", 4)) continue;
+ if (!dgram && strncmp(z, "/tcp", 4)) continue;
+ if (p-line > 32) continue;
+
+ memcpy(buf, line, p-line);
+ break;
+ }
+ __fclose_ca(f);
+}
+
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+{
+ if (rr != RR_PTR) return 0;
+ if (__dn_expand(packet, (const unsigned char *)packet + 512,
+ data, c, 256) <= 0)
+ *(char *)c = 0;
+ return 0;
+
+}
+
+int getnameinfo(const struct sockaddr *restrict sa, socklen_t sl,
+ char *restrict node, socklen_t nodelen,
+ char *restrict serv, socklen_t servlen,
+ int flags)
+{
+ char ptr[PTR_MAX];
+ char buf[256], num[3*sizeof(int)+1];
+ int af = sa->sa_family;
+ unsigned char *a;
+ unsigned scopeid;
+
+ switch (af) {
+ case AF_INET:
+ a = (void *)&((struct sockaddr_in *)sa)->sin_addr;
+ if (sl < sizeof(struct sockaddr_in)) return EAI_FAMILY;
+ mkptr4(ptr, a);
+ scopeid = 0;
+ break;
+ case AF_INET6:
+ a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+ if (sl < sizeof(struct sockaddr_in6)) return EAI_FAMILY;
+ if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12))
+ mkptr6(ptr, a);
+ else
+ mkptr4(ptr, a+12);
+ scopeid = ((struct sockaddr_in6 *)sa)->sin6_scope_id;
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ if (node && nodelen) {
+ buf[0] = 0;
+ if (!(flags & NI_NUMERICHOST)) {
+ reverse_hosts(buf, a, scopeid, af);
+ }
+ if (!*buf && !(flags & NI_NUMERICHOST)) {
+ unsigned char query[18+PTR_MAX], reply[512];
+ int qlen = __res_mkquery(0, ptr, 1, RR_PTR,
+ 0, 0, 0, query, sizeof query);
+ query[3] = 0; /* don't need AD flag */
+ int rlen = __res_send(query, qlen, reply, sizeof reply);
+ buf[0] = 0;
+ if (rlen > 0)
+ __dns_parse(reply, rlen, dns_parse_callback, buf);
+ }
+ if (!*buf) {
+ if (flags & NI_NAMEREQD) return EAI_NONAME;
+ inet_ntop(af, a, buf, sizeof buf);
+ if (scopeid) {
+ char *p = 0, tmp[IF_NAMESIZE+1];
+ if (!(flags & NI_NUMERICSCOPE) &&
+ (IN6_IS_ADDR_LINKLOCAL(a) ||
+ IN6_IS_ADDR_MC_LINKLOCAL(a)))
+ p = if_indextoname(scopeid, tmp+1);
+ if (!p)
+ p = itoa(num, scopeid);
+ *--p = '%';
+ strcat(buf, p);
+ }
+ }
+ if (strlen(buf) >= nodelen) return EAI_OVERFLOW;
+ strcpy(node, buf);
+ }
+
+ if (serv && servlen) {
+ char *p = buf;
+ int port = ntohs(((struct sockaddr_in *)sa)->sin_port);
+ buf[0] = 0;
+ if (!(flags & NI_NUMERICSERV))
+ reverse_services(buf, port, flags & NI_DGRAM);
+ if (!*p)
+ p = itoa(num, port);
+ if (strlen(p) >= servlen)
+ return EAI_OVERFLOW;
+ strcpy(serv, p);
+ }
+
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/getpeername.c b/libc-top-half/musl/src/network/getpeername.c
new file mode 100644
index 0000000..6567b45
--- /dev/null
+++ b/libc-top-half/musl/src/network/getpeername.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int getpeername(int fd, struct sockaddr *restrict addr, socklen_t *restrict len)
+{
+ return socketcall(getpeername, fd, addr, len, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/getservbyname.c b/libc-top-half/musl/src/network/getservbyname.c
new file mode 100644
index 0000000..dd30376
--- /dev/null
+++ b/libc-top-half/musl/src/network/getservbyname.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+
+struct servent *getservbyname(const char *name, const char *prots)
+{
+ static struct servent se;
+ static char *buf[2];
+ struct servent *res;
+ if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res))
+ return 0;
+ return &se;
+}
diff --git a/libc-top-half/musl/src/network/getservbyname_r.c b/libc-top-half/musl/src/network/getservbyname_r.c
new file mode 100644
index 0000000..cad6317
--- /dev/null
+++ b/libc-top-half/musl/src/network/getservbyname_r.c
@@ -0,0 +1,55 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include "lookup.h"
+
+#define ALIGN (sizeof(struct { char a; char *b; }) - sizeof(char *))
+
+int getservbyname_r(const char *name, const char *prots,
+ struct servent *se, char *buf, size_t buflen, struct servent **res)
+{
+ struct service servs[MAXSERVS];
+ int cnt, proto, align;
+
+ *res = 0;
+
+ /* Don't treat numeric port number strings as service records. */
+ char *end = "";
+ strtoul(name, &end, 10);
+ if (!*end) return ENOENT;
+
+ /* Align buffer */
+ align = -(uintptr_t)buf & ALIGN-1;
+ if (buflen < 2*sizeof(char *)+align)
+ return ERANGE;
+ buf += align;
+
+ if (!prots) proto = 0;
+ else if (!strcmp(prots, "tcp")) proto = IPPROTO_TCP;
+ else if (!strcmp(prots, "udp")) proto = IPPROTO_UDP;
+ else return EINVAL;
+
+ cnt = __lookup_serv(servs, name, proto, 0, 0);
+ if (cnt<0) switch (cnt) {
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ return ENOMEM;
+ default:
+ return ENOENT;
+ }
+
+ se->s_name = (char *)name;
+ se->s_aliases = (void *)buf;
+ se->s_aliases[0] = se->s_name;
+ se->s_aliases[1] = 0;
+ se->s_port = htons(servs[0].port);
+ se->s_proto = servs[0].proto == IPPROTO_TCP ? "tcp" : "udp";
+
+ *res = se;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/getservbyport.c b/libc-top-half/musl/src/network/getservbyport.c
new file mode 100644
index 0000000..c9ecbb1
--- /dev/null
+++ b/libc-top-half/musl/src/network/getservbyport.c
@@ -0,0 +1,12 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+
+struct servent *getservbyport(int port, const char *prots)
+{
+ static struct servent se;
+ static long buf[32/sizeof(long)];
+ struct servent *res;
+ if (getservbyport_r(port, prots, &se, (void *)buf, sizeof buf, &res))
+ return 0;
+ return &se;
+}
diff --git a/libc-top-half/musl/src/network/getservbyport_r.c b/libc-top-half/musl/src/network/getservbyport_r.c
new file mode 100644
index 0000000..b7f21c6
--- /dev/null
+++ b/libc-top-half/musl/src/network/getservbyport_r.c
@@ -0,0 +1,60 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+int getservbyport_r(int port, const char *prots,
+ struct servent *se, char *buf, size_t buflen, struct servent **res)
+{
+ int i;
+ struct sockaddr_in sin = {
+ .sin_family = AF_INET,
+ .sin_port = port,
+ };
+
+ if (!prots) {
+ int r = getservbyport_r(port, "tcp", se, buf, buflen, res);
+ if (r) r = getservbyport_r(port, "udp", se, buf, buflen, res);
+ return r;
+ }
+ *res = 0;
+
+ /* Align buffer */
+ i = (uintptr_t)buf & sizeof(char *)-1;
+ if (!i) i = sizeof(char *);
+ if (buflen < 3*sizeof(char *)-i)
+ return ERANGE;
+ buf += sizeof(char *)-i;
+ buflen -= sizeof(char *)-i;
+
+ if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return EINVAL;
+
+ se->s_port = port;
+ se->s_proto = (char *)prots;
+ se->s_aliases = (void *)buf;
+ buf += 2*sizeof(char *);
+ buflen -= 2*sizeof(char *);
+ se->s_aliases[1] = 0;
+ se->s_aliases[0] = se->s_name = buf;
+
+ switch (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen,
+ strcmp(prots, "udp") ? 0 : NI_DGRAM)) {
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ return ENOMEM;
+ default:
+ return ENOENT;
+ case 0:
+ break;
+ }
+
+ /* A numeric port string is not a service record. */
+ if (strtol(buf, 0, 10)==ntohs(port)) return ENOENT;
+
+ *res = se;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/getsockname.c b/libc-top-half/musl/src/network/getsockname.c
new file mode 100644
index 0000000..7885fc1
--- /dev/null
+++ b/libc-top-half/musl/src/network/getsockname.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int getsockname(int fd, struct sockaddr *restrict addr, socklen_t *restrict len)
+{
+ return socketcall(getsockname, fd, addr, len, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/getsockopt.c b/libc-top-half/musl/src/network/getsockopt.c
new file mode 100644
index 0000000..d3640d9
--- /dev/null
+++ b/libc-top-half/musl/src/network/getsockopt.c
@@ -0,0 +1,41 @@
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include "syscall.h"
+
+int getsockopt(int fd, int level, int optname, void *restrict optval, socklen_t *restrict optlen)
+{
+ long tv32[2];
+ struct timeval *tv;
+
+ int r = __socketcall(getsockopt, fd, level, optname, optval, optlen, 0);
+
+ if (r==-ENOPROTOOPT) switch (level) {
+ case SOL_SOCKET:
+ switch (optname) {
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break;
+ if (*optlen < sizeof *tv) return __syscall_ret(-EINVAL);
+ if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD;
+ if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD;
+ r = __socketcall(getsockopt, fd, level, optname,
+ tv32, (socklen_t[]){sizeof tv32}, 0);
+ if (r<0) break;
+ tv = optval;
+ tv->tv_sec = tv32[0];
+ tv->tv_usec = tv32[1];
+ *optlen = sizeof *tv;
+ break;
+ case SO_TIMESTAMP:
+ case SO_TIMESTAMPNS:
+ if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break;
+ if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD;
+ if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD;
+ r = __socketcall(getsockopt, fd, level,
+ optname, optval, optlen, 0);
+ break;
+ }
+ }
+ return __syscall_ret(r);
+}
diff --git a/libc-top-half/musl/src/network/h_errno.c b/libc-top-half/musl/src/network/h_errno.c
new file mode 100644
index 0000000..638f771
--- /dev/null
+++ b/libc-top-half/musl/src/network/h_errno.c
@@ -0,0 +1,11 @@
+#include <netdb.h>
+#include "pthread_impl.h"
+
+#undef h_errno
+int h_errno;
+
+int *__h_errno_location(void)
+{
+ if (!__pthread_self()->stack) return &h_errno;
+ return &__pthread_self()->h_errno_val;
+}
diff --git a/libc-top-half/musl/src/network/herror.c b/libc-top-half/musl/src/network/herror.c
new file mode 100644
index 0000000..87f8cff
--- /dev/null
+++ b/libc-top-half/musl/src/network/herror.c
@@ -0,0 +1,8 @@
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <netdb.h>
+
+void herror(const char *msg)
+{
+ fprintf(stderr, "%s%s%s\n", msg?msg:"", msg?": ":"", hstrerror(h_errno));
+}
diff --git a/libc-top-half/musl/src/network/hstrerror.c b/libc-top-half/musl/src/network/hstrerror.c
new file mode 100644
index 0000000..a4d001c
--- /dev/null
+++ b/libc-top-half/musl/src/network/hstrerror.c
@@ -0,0 +1,18 @@
+#define _GNU_SOURCE
+#include <netdb.h>
+#include "locale_impl.h"
+
+static const char msgs[] =
+ "Host not found\0"
+ "Try again\0"
+ "Non-recoverable error\0"
+ "Address not available\0"
+ "\0Unknown error";
+
+const char *hstrerror(int ecode)
+{
+ const char *s;
+ for (s=msgs, ecode--; ecode && *s; ecode--, s++) for (; *s; s++);
+ if (!*s) s++;
+ return LCTRANS_CUR(s);
+}
diff --git a/libc-top-half/musl/src/network/htonl.c b/libc-top-half/musl/src/network/htonl.c
new file mode 100644
index 0000000..6622d16
--- /dev/null
+++ b/libc-top-half/musl/src/network/htonl.c
@@ -0,0 +1,8 @@
+#include <netinet/in.h>
+#include <byteswap.h>
+
+uint32_t htonl(uint32_t n)
+{
+ union { int i; char c; } u = { 1 };
+ return u.c ? bswap_32(n) : n;
+}
diff --git a/libc-top-half/musl/src/network/htons.c b/libc-top-half/musl/src/network/htons.c
new file mode 100644
index 0000000..03a3a1d
--- /dev/null
+++ b/libc-top-half/musl/src/network/htons.c
@@ -0,0 +1,8 @@
+#include <netinet/in.h>
+#include <byteswap.h>
+
+uint16_t htons(uint16_t n)
+{
+ union { int i; char c; } u = { 1 };
+ return u.c ? bswap_16(n) : n;
+}
diff --git a/libc-top-half/musl/src/network/if_freenameindex.c b/libc-top-half/musl/src/network/if_freenameindex.c
new file mode 100644
index 0000000..89bafcc
--- /dev/null
+++ b/libc-top-half/musl/src/network/if_freenameindex.c
@@ -0,0 +1,7 @@
+#include <net/if.h>
+#include <stdlib.h>
+
+void if_freenameindex(struct if_nameindex *idx)
+{
+ free(idx);
+}
diff --git a/libc-top-half/musl/src/network/if_indextoname.c b/libc-top-half/musl/src/network/if_indextoname.c
new file mode 100644
index 0000000..3b368bf
--- /dev/null
+++ b/libc-top-half/musl/src/network/if_indextoname.c
@@ -0,0 +1,23 @@
+#define _GNU_SOURCE
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include <errno.h>
+#include "syscall.h"
+
+char *if_indextoname(unsigned index, char *name)
+{
+ struct ifreq ifr;
+ int fd, r;
+
+ if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return 0;
+ ifr.ifr_ifindex = index;
+ r = ioctl(fd, SIOCGIFNAME, &ifr);
+ __syscall(SYS_close, fd);
+ if (r < 0) {
+ if (errno == ENODEV) errno = ENXIO;
+ return 0;
+ }
+ return strncpy(name, ifr.ifr_name, IF_NAMESIZE);
+}
diff --git a/libc-top-half/musl/src/network/if_nameindex.c b/libc-top-half/musl/src/network/if_nameindex.c
new file mode 100644
index 0000000..2deaef7
--- /dev/null
+++ b/libc-top-half/musl/src/network/if_nameindex.c
@@ -0,0 +1,114 @@
+#define _GNU_SOURCE
+#include <net/if.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <pthread.h>
+#include "netlink.h"
+
+#define IFADDRS_HASH_SIZE 64
+
+struct ifnamemap {
+ unsigned int hash_next;
+ unsigned int index;
+ unsigned char namelen;
+ char name[IFNAMSIZ];
+};
+
+struct ifnameindexctx {
+ unsigned int num, allocated, str_bytes;
+ struct ifnamemap *list;
+ unsigned int hash[IFADDRS_HASH_SIZE];
+};
+
+static int netlink_msg_to_nameindex(void *pctx, struct nlmsghdr *h)
+{
+ struct ifnameindexctx *ctx = pctx;
+ struct ifnamemap *map;
+ struct rtattr *rta;
+ unsigned int i;
+ int index, type, namelen, bucket;
+
+ if (h->nlmsg_type == RTM_NEWLINK) {
+ struct ifinfomsg *ifi = NLMSG_DATA(h);
+ index = ifi->ifi_index;
+ type = IFLA_IFNAME;
+ rta = NLMSG_RTA(h, sizeof(*ifi));
+ } else {
+ struct ifaddrmsg *ifa = NLMSG_DATA(h);
+ index = ifa->ifa_index;
+ type = IFA_LABEL;
+ rta = NLMSG_RTA(h, sizeof(*ifa));
+ }
+ for (; NLMSG_RTAOK(rta, h); rta = RTA_NEXT(rta)) {
+ if (rta->rta_type != type) continue;
+
+ namelen = RTA_DATALEN(rta) - 1;
+ if (namelen > IFNAMSIZ) return 0;
+
+ /* suppress duplicates */
+ bucket = index % IFADDRS_HASH_SIZE;
+ i = ctx->hash[bucket];
+ while (i) {
+ map = &ctx->list[i-1];
+ if (map->index == index &&
+ map->namelen == namelen &&
+ memcmp(map->name, RTA_DATA(rta), namelen) == 0)
+ return 0;
+ i = map->hash_next;
+ }
+
+ if (ctx->num >= ctx->allocated) {
+ size_t a = ctx->allocated ? ctx->allocated * 2 + 1 : 8;
+ if (a > SIZE_MAX/sizeof *map) return -1;
+ map = realloc(ctx->list, a * sizeof *map);
+ if (!map) return -1;
+ ctx->list = map;
+ ctx->allocated = a;
+ }
+ map = &ctx->list[ctx->num];
+ map->index = index;
+ map->namelen = namelen;
+ memcpy(map->name, RTA_DATA(rta), namelen);
+ ctx->str_bytes += namelen + 1;
+ ctx->num++;
+ map->hash_next = ctx->hash[bucket];
+ ctx->hash[bucket] = ctx->num;
+ return 0;
+ }
+ return 0;
+}
+
+struct if_nameindex *if_nameindex()
+{
+ struct ifnameindexctx _ctx, *ctx = &_ctx;
+ struct if_nameindex *ifs = 0, *d;
+ struct ifnamemap *s;
+ char *p;
+ int i;
+ int cs;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+ memset(ctx, 0, sizeof(*ctx));
+ if (__rtnetlink_enumerate(AF_UNSPEC, AF_INET, netlink_msg_to_nameindex, ctx) < 0) goto err;
+
+ ifs = malloc(sizeof(struct if_nameindex[ctx->num+1]) + ctx->str_bytes);
+ if (!ifs) goto err;
+
+ p = (char*)(ifs + ctx->num + 1);
+ for (i = ctx->num, d = ifs, s = ctx->list; i; i--, s++, d++) {
+ d->if_index = s->index;
+ d->if_name = p;
+ memcpy(p, s->name, s->namelen);
+ p += s->namelen;
+ *p++ = 0;
+ }
+ d->if_index = 0;
+ d->if_name = 0;
+err:
+ pthread_setcancelstate(cs, 0);
+ free(ctx->list);
+ errno = ENOBUFS;
+ return ifs;
+}
diff --git a/libc-top-half/musl/src/network/if_nametoindex.c b/libc-top-half/musl/src/network/if_nametoindex.c
new file mode 100644
index 0000000..331413c
--- /dev/null
+++ b/libc-top-half/musl/src/network/if_nametoindex.c
@@ -0,0 +1,18 @@
+#define _GNU_SOURCE
+#include <net/if.h>
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include <string.h>
+#include "syscall.h"
+
+unsigned if_nametoindex(const char *name)
+{
+ struct ifreq ifr;
+ int fd, r;
+
+ if ((fd = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0)) < 0) return 0;
+ strncpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
+ r = ioctl(fd, SIOCGIFINDEX, &ifr);
+ __syscall(SYS_close, fd);
+ return r < 0 ? 0 : ifr.ifr_ifindex;
+}
diff --git a/libc-top-half/musl/src/network/in6addr_any.c b/libc-top-half/musl/src/network/in6addr_any.c
new file mode 100644
index 0000000..995387f
--- /dev/null
+++ b/libc-top-half/musl/src/network/in6addr_any.c
@@ -0,0 +1,3 @@
+#include <netinet/in.h>
+
+const struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
diff --git a/libc-top-half/musl/src/network/in6addr_loopback.c b/libc-top-half/musl/src/network/in6addr_loopback.c
new file mode 100644
index 0000000..b96005b
--- /dev/null
+++ b/libc-top-half/musl/src/network/in6addr_loopback.c
@@ -0,0 +1,3 @@
+#include <netinet/in.h>
+
+const struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/libc-top-half/musl/src/network/inet_addr.c b/libc-top-half/musl/src/network/inet_addr.c
new file mode 100644
index 0000000..11ece3d
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_addr.c
@@ -0,0 +1,10 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+in_addr_t inet_addr(const char *p)
+{
+ struct in_addr a;
+ if (!__inet_aton(p, &a)) return -1;
+ return a.s_addr;
+}
diff --git a/libc-top-half/musl/src/network/inet_aton.c b/libc-top-half/musl/src/network/inet_aton.c
new file mode 100644
index 0000000..c65f7c2
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_aton.c
@@ -0,0 +1,41 @@
+#include <ctype.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+
+int __inet_aton(const char *s0, struct in_addr *dest)
+{
+ const char *s = s0;
+ unsigned char *d = (void *)dest;
+ unsigned long a[4] = { 0 };
+ char *z;
+ int i;
+
+ for (i=0; i<4; i++) {
+ a[i] = strtoul(s, &z, 0);
+ if (z==s || (*z && *z != '.') || !isdigit(*s))
+ return 0;
+ if (!*z) break;
+ s=z+1;
+ }
+ if (i==4) return 0;
+ switch (i) {
+ case 0:
+ a[1] = a[0] & 0xffffff;
+ a[0] >>= 24;
+ case 1:
+ a[2] = a[1] & 0xffff;
+ a[1] >>= 16;
+ case 2:
+ a[3] = a[2] & 0xff;
+ a[2] >>= 8;
+ }
+ for (i=0; i<4; i++) {
+ if (a[i] > 255) return 0;
+ d[i] = a[i];
+ }
+ return 1;
+}
+
+weak_alias(__inet_aton, inet_aton);
diff --git a/libc-top-half/musl/src/network/inet_legacy.c b/libc-top-half/musl/src/network/inet_legacy.c
new file mode 100644
index 0000000..621b47b
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_legacy.c
@@ -0,0 +1,32 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+
+in_addr_t inet_network(const char *p)
+{
+ return ntohl(inet_addr(p));
+}
+
+struct in_addr inet_makeaddr(in_addr_t n, in_addr_t h)
+{
+ if (n < 256) h |= n<<24;
+ else if (n < 65536) h |= n<<16;
+ else h |= n<<8;
+ return (struct in_addr){ h };
+}
+
+in_addr_t inet_lnaof(struct in_addr in)
+{
+ uint32_t h = in.s_addr;
+ if (h>>24 < 128) return h & 0xffffff;
+ if (h>>24 < 192) return h & 0xffff;
+ return h & 0xff;
+}
+
+in_addr_t inet_netof(struct in_addr in)
+{
+ uint32_t h = in.s_addr;
+ if (h>>24 < 128) return h >> 24;
+ if (h>>24 < 192) return h >> 16;
+ return h >> 8;
+}
diff --git a/libc-top-half/musl/src/network/inet_ntoa.c b/libc-top-half/musl/src/network/inet_ntoa.c
new file mode 100644
index 0000000..71411e0
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_ntoa.c
@@ -0,0 +1,10 @@
+#include <arpa/inet.h>
+#include <stdio.h>
+
+char *inet_ntoa(struct in_addr in)
+{
+ static char buf[16];
+ unsigned char *a = (void *)&in;
+ snprintf(buf, sizeof buf, "%d.%d.%d.%d", a[0], a[1], a[2], a[3]);
+ return buf;
+}
diff --git a/libc-top-half/musl/src/network/inet_ntop.c b/libc-top-half/musl/src/network/inet_ntop.c
new file mode 100644
index 0000000..4bfef2c
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_ntop.c
@@ -0,0 +1,54 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *inet_ntop(int af, const void *restrict a0, char *restrict s, socklen_t l)
+{
+ const unsigned char *a = a0;
+ int i, j, max, best;
+ char buf[100];
+
+ switch (af) {
+ case AF_INET:
+ if (snprintf(s, l, "%d.%d.%d.%d", a[0],a[1],a[2],a[3]) < l)
+ return s;
+ break;
+ case AF_INET6:
+ if (memcmp(a, "\0\0\0\0\0\0\0\0\0\0\377\377", 12))
+ snprintf(buf, sizeof buf,
+ "%x:%x:%x:%x:%x:%x:%x:%x",
+ 256*a[0]+a[1],256*a[2]+a[3],
+ 256*a[4]+a[5],256*a[6]+a[7],
+ 256*a[8]+a[9],256*a[10]+a[11],
+ 256*a[12]+a[13],256*a[14]+a[15]);
+ else
+ snprintf(buf, sizeof buf,
+ "%x:%x:%x:%x:%x:%x:%d.%d.%d.%d",
+ 256*a[0]+a[1],256*a[2]+a[3],
+ 256*a[4]+a[5],256*a[6]+a[7],
+ 256*a[8]+a[9],256*a[10]+a[11],
+ a[12],a[13],a[14],a[15]);
+ /* Replace longest /(^0|:)[:0]{2,}/ with "::" */
+ for (i=best=0, max=2; buf[i]; i++) {
+ if (i && buf[i] != ':') continue;
+ j = strspn(buf+i, ":0");
+ if (j>max) best=i, max=j;
+ }
+ if (max>3) {
+ buf[best] = buf[best+1] = ':';
+ memmove(buf+best+2, buf+best+max, i-best-max+1);
+ }
+ if (strlen(buf) < l) {
+ strcpy(s, buf);
+ return s;
+ }
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return 0;
+ }
+ errno = ENOSPC;
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/inet_pton.c b/libc-top-half/musl/src/network/inet_pton.c
new file mode 100644
index 0000000..d36c368
--- /dev/null
+++ b/libc-top-half/musl/src/network/inet_pton.c
@@ -0,0 +1,71 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+
+static int hexval(unsigned c)
+{
+ if (c-'0'<10) return c-'0';
+ c |= 32;
+ if (c-'a'<6) return c-'a'+10;
+ return -1;
+}
+
+int inet_pton(int af, const char *restrict s, void *restrict a0)
+{
+ uint16_t ip[8];
+ unsigned char *a = a0;
+ int i, j, v, d, brk=-1, need_v4=0;
+
+ if (af==AF_INET) {
+ for (i=0; i<4; i++) {
+ for (v=j=0; j<3 && isdigit(s[j]); j++)
+ v = 10*v + s[j]-'0';
+ if (j==0 || (j>1 && s[0]=='0') || v>255) return 0;
+ a[i] = v;
+ if (s[j]==0 && i==3) return 1;
+ if (s[j]!='.') return 0;
+ s += j+1;
+ }
+ return 0;
+ } else if (af!=AF_INET6) {
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ if (*s==':' && *++s!=':') return 0;
+
+ for (i=0; ; i++) {
+ if (s[0]==':' && brk<0) {
+ brk=i;
+ ip[i&7]=0;
+ if (!*++s) break;
+ if (i==7) return 0;
+ continue;
+ }
+ for (v=j=0; j<4 && (d=hexval(s[j]))>=0; j++)
+ v=16*v+d;
+ if (j==0) return 0;
+ ip[i&7] = v;
+ if (!s[j] && (brk>=0 || i==7)) break;
+ if (i==7) return 0;
+ if (s[j]!=':') {
+ if (s[j]!='.' || (i<6 && brk<0)) return 0;
+ need_v4=1;
+ i++;
+ break;
+ }
+ s += j+1;
+ }
+ if (brk>=0) {
+ memmove(ip+brk+7-i, ip+brk, 2*(i+1-brk));
+ for (j=0; j<7-i; j++) ip[brk+j] = 0;
+ }
+ for (j=0; j<8; j++) {
+ *a++ = ip[j]>>8;
+ *a++ = ip[j];
+ }
+ if (need_v4 && inet_pton(AF_INET, (void *)s, a-4) <= 0) return 0;
+ return 1;
+}
diff --git a/libc-top-half/musl/src/network/listen.c b/libc-top-half/musl/src/network/listen.c
new file mode 100644
index 0000000..f84ad03
--- /dev/null
+++ b/libc-top-half/musl/src/network/listen.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int listen(int fd, int backlog)
+{
+ return socketcall(listen, fd, backlog, 0, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/lookup.h b/libc-top-half/musl/src/network/lookup.h
new file mode 100644
index 0000000..ef66272
--- /dev/null
+++ b/libc-top-half/musl/src/network/lookup.h
@@ -0,0 +1,55 @@
+#ifndef LOOKUP_H
+#define LOOKUP_H
+
+#include <stdint.h>
+#include <stddef.h>
+#include <features.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+struct aibuf {
+ struct addrinfo ai;
+ union sa {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sa;
+ volatile int lock[1];
+ short slot, ref;
+};
+
+struct address {
+ int family;
+ unsigned scopeid;
+ uint8_t addr[16];
+ int sortkey;
+};
+
+struct service {
+ uint16_t port;
+ unsigned char proto, socktype;
+};
+
+#define MAXNS 3
+
+struct resolvconf {
+ struct address ns[MAXNS];
+ unsigned nns, attempts, ndots;
+ unsigned timeout;
+};
+
+/* The limit of 48 results is a non-sharp bound on the number of addresses
+ * that can fit in one 512-byte DNS packet full of v4 results and a second
+ * packet full of v6 results. Due to headers, the actual limit is lower. */
+#define MAXADDRS 48
+#define MAXSERVS 2
+
+hidden int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags);
+hidden int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags);
+hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, int family);
+
+hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);
+hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
+
+hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+
+#endif
diff --git a/libc-top-half/musl/src/network/lookup_ipliteral.c b/libc-top-half/musl/src/network/lookup_ipliteral.c
new file mode 100644
index 0000000..2fddab7
--- /dev/null
+++ b/libc-top-half/musl/src/network/lookup_ipliteral.c
@@ -0,0 +1,55 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include "lookup.h"
+
+int __lookup_ipliteral(struct address buf[static 1], const char *name, int family)
+{
+ struct in_addr a4;
+ struct in6_addr a6;
+ if (__inet_aton(name, &a4) > 0) {
+ if (family == AF_INET6) /* wrong family */
+ return EAI_NONAME;
+ memcpy(&buf[0].addr, &a4, sizeof a4);
+ buf[0].family = AF_INET;
+ buf[0].scopeid = 0;
+ return 1;
+ }
+
+ char tmp[64];
+ char *p = strchr(name, '%'), *z;
+ unsigned long long scopeid = 0;
+ if (p && p-name < 64) {
+ memcpy(tmp, name, p-name);
+ tmp[p-name] = 0;
+ name = tmp;
+ }
+
+ if (inet_pton(AF_INET6, name, &a6) <= 0)
+ return 0;
+ if (family == AF_INET) /* wrong family */
+ return EAI_NONAME;
+
+ memcpy(&buf[0].addr, &a6, sizeof a6);
+ buf[0].family = AF_INET6;
+ if (p) {
+ if (isdigit(*++p)) scopeid = strtoull(p, &z, 10);
+ else z = p-1;
+ if (*z) {
+ if (!IN6_IS_ADDR_LINKLOCAL(&a6) &&
+ !IN6_IS_ADDR_MC_LINKLOCAL(&a6))
+ return EAI_NONAME;
+ scopeid = if_nametoindex(p);
+ if (!scopeid) return EAI_NONAME;
+ }
+ if (scopeid > UINT_MAX) return EAI_NONAME;
+ }
+ buf[0].scopeid = scopeid;
+ return 1;
+}
diff --git a/libc-top-half/musl/src/network/lookup_name.c b/libc-top-half/musl/src/network/lookup_name.c
new file mode 100644
index 0000000..aa558c1
--- /dev/null
+++ b/libc-top-half/musl/src/network/lookup_name.c
@@ -0,0 +1,425 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <net/if.h>
+#include <arpa/inet.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <pthread.h>
+#include <errno.h>
+#include <resolv.h>
+#include "lookup.h"
+#include "stdio_impl.h"
+#include "syscall.h"
+
+static int is_valid_hostname(const char *host)
+{
+ const unsigned char *s;
+ if (strnlen(host, 255)-1 >= 254 || mbstowcs(0, host, 0) == -1) return 0;
+ for (s=(void *)host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
+ return !*s;
+}
+
+static int name_from_null(struct address buf[static 2], const char *name, int family, int flags)
+{
+ int cnt = 0;
+ if (name) return 0;
+ if (flags & AI_PASSIVE) {
+ if (family != AF_INET6)
+ buf[cnt++] = (struct address){ .family = AF_INET };
+ if (family != AF_INET)
+ buf[cnt++] = (struct address){ .family = AF_INET6 };
+ } else {
+ if (family != AF_INET6)
+ buf[cnt++] = (struct address){ .family = AF_INET, .addr = { 127,0,0,1 } };
+ if (family != AF_INET)
+ buf[cnt++] = (struct address){ .family = AF_INET6, .addr = { [15] = 1 } };
+ }
+ return cnt;
+}
+
+static int name_from_numeric(struct address buf[static 1], const char *name, int family)
+{
+ return __lookup_ipliteral(buf, name, family);
+}
+
+static int name_from_hosts(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
+{
+ char line[512];
+ size_t l = strlen(name);
+ int cnt = 0, badfam = 0, have_canon = 0;
+ unsigned char _buf[1032];
+ FILE _f, *f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+ if (!f) switch (errno) {
+ case ENOENT:
+ case ENOTDIR:
+ case EACCES:
+ return 0;
+ default:
+ return EAI_SYSTEM;
+ }
+ while (fgets(line, sizeof line, f) && cnt < MAXADDRS) {
+ char *p, *z;
+
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+ for(p=line+1; (p=strstr(p, name)) &&
+ (!isspace(p[-1]) || !isspace(p[l])); p++);
+ if (!p) continue;
+
+ /* Isolate IP address to parse */
+ for (p=line; *p && !isspace(*p); p++);
+ *p++ = 0;
+ switch (name_from_numeric(buf+cnt, line, family)) {
+ case 1:
+ cnt++;
+ break;
+ case 0:
+ continue;
+ default:
+ badfam = EAI_NONAME;
+ break;
+ }
+
+ if (have_canon) continue;
+
+ /* Extract first name as canonical name */
+ for (; *p && isspace(*p); p++);
+ for (z=p; *z && !isspace(*z); z++);
+ *z = 0;
+ if (is_valid_hostname(p)) {
+ have_canon = 1;
+ memcpy(canon, p, z-p+1);
+ }
+ }
+ __fclose_ca(f);
+ return cnt ? cnt : badfam;
+}
+
+struct dpc_ctx {
+ struct address *addrs;
+ char *canon;
+ int cnt;
+};
+
+#define RR_A 1
+#define RR_CNAME 5
+#define RR_AAAA 28
+
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+{
+ char tmp[256];
+ struct dpc_ctx *ctx = c;
+ if (ctx->cnt >= MAXADDRS) return -1;
+ switch (rr) {
+ case RR_A:
+ if (len != 4) return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 4);
+ break;
+ case RR_AAAA:
+ if (len != 16) return -1;
+ ctx->addrs[ctx->cnt].family = AF_INET6;
+ ctx->addrs[ctx->cnt].scopeid = 0;
+ memcpy(ctx->addrs[ctx->cnt++].addr, data, 16);
+ break;
+ case RR_CNAME:
+ if (__dn_expand(packet, (const unsigned char *)packet + 512,
+ data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
+ strcpy(ctx->canon, tmp);
+ break;
+ }
+ return 0;
+}
+
+static int name_from_dns(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, const struct resolvconf *conf)
+{
+ unsigned char qbuf[2][280], abuf[2][512];
+ const unsigned char *qp[2] = { qbuf[0], qbuf[1] };
+ unsigned char *ap[2] = { abuf[0], abuf[1] };
+ int qlens[2], alens[2];
+ int i, nq = 0;
+ struct dpc_ctx ctx = { .addrs = buf, .canon = canon };
+ static const struct { int af; int rr; } afrr[2] = {
+ { .af = AF_INET6, .rr = RR_A },
+ { .af = AF_INET, .rr = RR_AAAA },
+ };
+
+ for (i=0; i<2; i++) {
+ if (family != afrr[i].af) {
+ qlens[nq] = __res_mkquery(0, name, 1, afrr[i].rr,
+ 0, 0, 0, qbuf[nq], sizeof *qbuf);
+ if (qlens[nq] == -1)
+ return EAI_NONAME;
+ qbuf[nq][3] = 0; /* don't need AD flag */
+ nq++;
+ }
+ }
+
+ if (__res_msend_rc(nq, qp, qlens, ap, alens, sizeof *abuf, conf) < 0)
+ return EAI_SYSTEM;
+
+ for (i=0; i<nq; i++) {
+ if (alens[i] < 4 || (abuf[i][3] & 15) == 2) return EAI_AGAIN;
+ if ((abuf[i][3] & 15) == 3) return 0;
+ if ((abuf[i][3] & 15) != 0) return EAI_FAIL;
+ }
+
+ for (i=0; i<nq; i++)
+ __dns_parse(abuf[i], alens[i], dns_parse_callback, &ctx);
+
+ if (ctx.cnt) return ctx.cnt;
+ return EAI_NONAME;
+}
+
+static int name_from_dns_search(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family)
+{
+ char search[256];
+ struct resolvconf conf;
+ size_t l, dots;
+ char *p, *z;
+
+ if (__get_resolv_conf(&conf, search, sizeof search) < 0) return -1;
+
+ /* Count dots, suppress search when >=ndots or name ends in
+ * a dot, which is an explicit request for global scope. */
+ for (dots=l=0; name[l]; l++) if (name[l]=='.') dots++;
+ if (dots >= conf.ndots || name[l-1]=='.') *search = 0;
+
+ /* Strip final dot for canon, fail if multiple trailing dots. */
+ if (name[l-1]=='.') l--;
+ if (!l || name[l-1]=='.') return EAI_NONAME;
+
+ /* This can never happen; the caller already checked length. */
+ if (l >= 256) return EAI_NONAME;
+
+ /* Name with search domain appended is setup in canon[]. This both
+ * provides the desired default canonical name (if the requested
+ * name is not a CNAME record) and serves as a buffer for passing
+ * the full requested name to name_from_dns. */
+ memcpy(canon, name, l);
+ canon[l] = '.';
+
+ for (p=search; *p; p=z) {
+ for (; isspace(*p); p++);
+ for (z=p; *z && !isspace(*z); z++);
+ if (z==p) break;
+ if (z-p < 256 - l - 1) {
+ memcpy(canon+l+1, p, z-p);
+ canon[z-p+1+l] = 0;
+ int cnt = name_from_dns(buf, canon, canon, family, &conf);
+ if (cnt) return cnt;
+ }
+ }
+
+ canon[l] = 0;
+ return name_from_dns(buf, canon, name, family, &conf);
+}
+
+static const struct policy {
+ unsigned char addr[16];
+ unsigned char len, mask;
+ unsigned char prec, label;
+} defpolicy[] = {
+ { "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1", 15, 0xff, 50, 0 },
+ { "\0\0\0\0\0\0\0\0\0\0\xff\xff", 11, 0xff, 35, 4 },
+ { "\x20\2", 1, 0xff, 30, 2 },
+ { "\x20\1", 3, 0xff, 5, 5 },
+ { "\xfc", 0, 0xfe, 3, 13 },
+#if 0
+ /* These are deprecated and/or returned to the address
+ * pool, so despite the RFC, treating them as special
+ * is probably wrong. */
+ { "", 11, 0xff, 1, 3 },
+ { "\xfe\xc0", 1, 0xc0, 1, 11 },
+ { "\x3f\xfe", 1, 0xff, 1, 12 },
+#endif
+ /* Last rule must match all addresses to stop loop. */
+ { "", 0, 0, 40, 1 },
+};
+
+static const struct policy *policyof(const struct in6_addr *a)
+{
+ int i;
+ for (i=0; ; i++) {
+ if (memcmp(a->s6_addr, defpolicy[i].addr, defpolicy[i].len))
+ continue;
+ if ((a->s6_addr[defpolicy[i].len] & defpolicy[i].mask)
+ != defpolicy[i].addr[defpolicy[i].len])
+ continue;
+ return defpolicy+i;
+ }
+}
+
+static int labelof(const struct in6_addr *a)
+{
+ return policyof(a)->label;
+}
+
+static int scopeof(const struct in6_addr *a)
+{
+ if (IN6_IS_ADDR_MULTICAST(a)) return a->s6_addr[1] & 15;
+ if (IN6_IS_ADDR_LINKLOCAL(a)) return 2;
+ if (IN6_IS_ADDR_LOOPBACK(a)) return 2;
+ if (IN6_IS_ADDR_SITELOCAL(a)) return 5;
+ return 14;
+}
+
+static int prefixmatch(const struct in6_addr *s, const struct in6_addr *d)
+{
+ /* FIXME: The common prefix length should be limited to no greater
+ * than the nominal length of the prefix portion of the source
+ * address. However the definition of the source prefix length is
+ * not clear and thus this limiting is not yet implemented. */
+ unsigned i;
+ for (i=0; i<128 && !((s->s6_addr[i/8]^d->s6_addr[i/8])&(128>>(i%8))); i++);
+ return i;
+}
+
+#define DAS_USABLE 0x40000000
+#define DAS_MATCHINGSCOPE 0x20000000
+#define DAS_MATCHINGLABEL 0x10000000
+#define DAS_PREC_SHIFT 20
+#define DAS_SCOPE_SHIFT 16
+#define DAS_PREFIX_SHIFT 8
+#define DAS_ORDER_SHIFT 0
+
+static int addrcmp(const void *_a, const void *_b)
+{
+ const struct address *a = _a, *b = _b;
+ return b->sortkey - a->sortkey;
+}
+
+int __lookup_name(struct address buf[static MAXADDRS], char canon[static 256], const char *name, int family, int flags)
+{
+ int cnt = 0, i, j;
+
+ *canon = 0;
+ if (name) {
+ /* reject empty name and check len so it fits into temp bufs */
+ size_t l = strnlen(name, 255);
+ if (l-1 >= 254)
+ return EAI_NONAME;
+ memcpy(canon, name, l+1);
+ }
+
+ /* Procedurally, a request for v6 addresses with the v4-mapped
+ * flag set is like a request for unspecified family, followed
+ * by filtering of the results. */
+ if (flags & AI_V4MAPPED) {
+ if (family == AF_INET6) family = AF_UNSPEC;
+ else flags -= AI_V4MAPPED;
+ }
+
+ /* Try each backend until there's at least one result. */
+ cnt = name_from_null(buf, name, family, flags);
+ if (!cnt) cnt = name_from_numeric(buf, name, family);
+ if (!cnt && !(flags & AI_NUMERICHOST)) {
+ cnt = name_from_hosts(buf, canon, name, family);
+ if (!cnt) cnt = name_from_dns_search(buf, canon, name, family);
+ }
+ if (cnt<=0) return cnt ? cnt : EAI_NONAME;
+
+ /* Filter/transform results for v4-mapped lookup, if requested. */
+ if (flags & AI_V4MAPPED) {
+ if (!(flags & AI_ALL)) {
+ /* If any v6 results exist, remove v4 results. */
+ for (i=0; i<cnt && buf[i].family != AF_INET6; i++);
+ if (i<cnt) {
+ for (j=0; i<cnt; i++) {
+ if (buf[i].family == AF_INET6)
+ buf[j++] = buf[i];
+ }
+ cnt = i = j;
+ }
+ }
+ /* Translate any remaining v4 results to v6 */
+ for (i=0; i<cnt; i++) {
+ if (buf[i].family != AF_INET) continue;
+ memcpy(buf[i].addr+12, buf[i].addr, 4);
+ memcpy(buf[i].addr, "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ buf[i].family = AF_INET6;
+ }
+ }
+
+ /* No further processing is needed if there are fewer than 2
+ * results or if there are only IPv4 results. */
+ if (cnt<2 || family==AF_INET) return cnt;
+ for (i=0; i<cnt; i++) if (buf[i].family != AF_INET) break;
+ if (i==cnt) return cnt;
+
+ int cs;
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
+ /* The following implements a subset of RFC 3484/6724 destination
+ * address selection by generating a single 31-bit sort key for
+ * each address. Rules 3, 4, and 7 are omitted for having
+ * excessive runtime and code size cost and dubious benefit.
+ * So far the label/precedence table cannot be customized. */
+ for (i=0; i<cnt; i++) {
+ int family = buf[i].family;
+ int key = 0;
+ struct sockaddr_in6 sa6 = { 0 }, da6 = {
+ .sin6_family = AF_INET6,
+ .sin6_scope_id = buf[i].scopeid,
+ .sin6_port = 65535
+ };
+ struct sockaddr_in sa4 = { 0 }, da4 = {
+ .sin_family = AF_INET,
+ .sin_port = 65535
+ };
+ void *sa, *da;
+ socklen_t salen, dalen;
+ if (family == AF_INET6) {
+ memcpy(da6.sin6_addr.s6_addr, buf[i].addr, 16);
+ da = &da6; dalen = sizeof da6;
+ sa = &sa6; salen = sizeof sa6;
+ } else {
+ memcpy(sa6.sin6_addr.s6_addr,
+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
+ memcpy(da6.sin6_addr.s6_addr,
+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ memcpy(da6.sin6_addr.s6_addr+12, buf[i].addr, 4);
+ memcpy(&da4.sin_addr, buf[i].addr, 4);
+ da = &da4; dalen = sizeof da4;
+ sa = &sa4; salen = sizeof sa4;
+ }
+ const struct policy *dpolicy = policyof(&da6.sin6_addr);
+ int dscope = scopeof(&da6.sin6_addr);
+ int dlabel = dpolicy->label;
+ int dprec = dpolicy->prec;
+ int prefixlen = 0;
+ int fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC, IPPROTO_UDP);
+ if (fd >= 0) {
+ if (!connect(fd, da, dalen)) {
+ key |= DAS_USABLE;
+ if (!getsockname(fd, sa, &salen)) {
+ if (family == AF_INET) memcpy(
+ sa6.sin6_addr.s6_addr+12,
+ &sa4.sin_addr, 4);
+ if (dscope == scopeof(&sa6.sin6_addr))
+ key |= DAS_MATCHINGSCOPE;
+ if (dlabel == labelof(&sa6.sin6_addr))
+ key |= DAS_MATCHINGLABEL;
+ prefixlen = prefixmatch(&sa6.sin6_addr,
+ &da6.sin6_addr);
+ }
+ }
+ close(fd);
+ }
+ key |= dprec << DAS_PREC_SHIFT;
+ key |= (15-dscope) << DAS_SCOPE_SHIFT;
+ key |= prefixlen << DAS_PREFIX_SHIFT;
+ key |= (MAXADDRS-i) << DAS_ORDER_SHIFT;
+ buf[i].sortkey = key;
+ }
+ qsort(buf, cnt, sizeof *buf, addrcmp);
+
+ pthread_setcancelstate(cs, 0);
+
+ return cnt;
+}
diff --git a/libc-top-half/musl/src/network/lookup_serv.c b/libc-top-half/musl/src/network/lookup_serv.c
new file mode 100644
index 0000000..ae38277
--- /dev/null
+++ b/libc-top-half/musl/src/network/lookup_serv.c
@@ -0,0 +1,114 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <ctype.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "lookup.h"
+#include "stdio_impl.h"
+
+int __lookup_serv(struct service buf[static MAXSERVS], const char *name, int proto, int socktype, int flags)
+{
+ char line[128];
+ int cnt = 0;
+ char *p, *z = "";
+ unsigned long port = 0;
+
+ switch (socktype) {
+ case SOCK_STREAM:
+ switch (proto) {
+ case 0:
+ proto = IPPROTO_TCP;
+ case IPPROTO_TCP:
+ break;
+ default:
+ return EAI_SERVICE;
+ }
+ break;
+ case SOCK_DGRAM:
+ switch (proto) {
+ case 0:
+ proto = IPPROTO_UDP;
+ case IPPROTO_UDP:
+ break;
+ default:
+ return EAI_SERVICE;
+ }
+ case 0:
+ break;
+ default:
+ if (name) return EAI_SERVICE;
+ buf[0].port = 0;
+ buf[0].proto = proto;
+ buf[0].socktype = socktype;
+ return 1;
+ }
+
+ if (name) {
+ if (!*name) return EAI_SERVICE;
+ port = strtoul(name, &z, 10);
+ }
+ if (!*z) {
+ if (port > 65535) return EAI_SERVICE;
+ if (proto != IPPROTO_UDP) {
+ buf[cnt].port = port;
+ buf[cnt].socktype = SOCK_STREAM;
+ buf[cnt++].proto = IPPROTO_TCP;
+ }
+ if (proto != IPPROTO_TCP) {
+ buf[cnt].port = port;
+ buf[cnt].socktype = SOCK_DGRAM;
+ buf[cnt++].proto = IPPROTO_UDP;
+ }
+ return cnt;
+ }
+
+ if (flags & AI_NUMERICSERV) return EAI_NONAME;
+
+ size_t l = strlen(name);
+
+ unsigned char _buf[1032];
+ FILE _f, *f = __fopen_rb_ca("/etc/services", &_f, _buf, sizeof _buf);
+ if (!f) switch (errno) {
+ case ENOENT:
+ case ENOTDIR:
+ case EACCES:
+ return EAI_SERVICE;
+ default:
+ return EAI_SYSTEM;
+ }
+
+ while (fgets(line, sizeof line, f) && cnt < MAXSERVS) {
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+
+ /* Find service name */
+ for(p=line; (p=strstr(p, name)); p++) {
+ if (p>line && !isspace(p[-1])) continue;
+ if (p[l] && !isspace(p[l])) continue;
+ break;
+ }
+ if (!p) continue;
+
+ /* Skip past canonical name at beginning of line */
+ for (p=line; *p && !isspace(*p); p++);
+
+ port = strtoul(p, &z, 10);
+ if (port > 65535 || z==p) continue;
+ if (!strncmp(z, "/udp", 4)) {
+ if (proto == IPPROTO_TCP) continue;
+ buf[cnt].port = port;
+ buf[cnt].socktype = SOCK_DGRAM;
+ buf[cnt++].proto = IPPROTO_UDP;
+ }
+ if (!strncmp(z, "/tcp", 4)) {
+ if (proto == IPPROTO_UDP) continue;
+ buf[cnt].port = port;
+ buf[cnt].socktype = SOCK_STREAM;
+ buf[cnt++].proto = IPPROTO_TCP;
+ }
+ }
+ __fclose_ca(f);
+ return cnt > 0 ? cnt : EAI_SERVICE;
+}
diff --git a/libc-top-half/musl/src/network/netlink.c b/libc-top-half/musl/src/network/netlink.c
new file mode 100644
index 0000000..94dba7f
--- /dev/null
+++ b/libc-top-half/musl/src/network/netlink.c
@@ -0,0 +1,52 @@
+#include <errno.h>
+#include <string.h>
+#include <syscall.h>
+#include <sys/socket.h>
+#include "netlink.h"
+
+static int __netlink_enumerate(int fd, unsigned int seq, int type, int af,
+ int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
+{
+ struct nlmsghdr *h;
+ union {
+ uint8_t buf[8192];
+ struct {
+ struct nlmsghdr nlh;
+ struct rtgenmsg g;
+ } req;
+ struct nlmsghdr reply;
+ } u;
+ int r, ret;
+
+ memset(&u.req, 0, sizeof(u.req));
+ u.req.nlh.nlmsg_len = sizeof(u.req);
+ u.req.nlh.nlmsg_type = type;
+ u.req.nlh.nlmsg_flags = NLM_F_DUMP | NLM_F_REQUEST;
+ u.req.nlh.nlmsg_seq = seq;
+ u.req.g.rtgen_family = af;
+ r = send(fd, &u.req, sizeof(u.req), 0);
+ if (r < 0) return r;
+
+ while (1) {
+ r = recv(fd, u.buf, sizeof(u.buf), MSG_DONTWAIT);
+ if (r <= 0) return -1;
+ for (h = &u.reply; NLMSG_OK(h, (void*)&u.buf[r]); h = NLMSG_NEXT(h)) {
+ if (h->nlmsg_type == NLMSG_DONE) return 0;
+ if (h->nlmsg_type == NLMSG_ERROR) return -1;
+ ret = cb(ctx, h);
+ if (ret) return ret;
+ }
+ }
+}
+
+int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx)
+{
+ int fd, r;
+
+ fd = socket(PF_NETLINK, SOCK_RAW|SOCK_CLOEXEC, NETLINK_ROUTE);
+ if (fd < 0) return -1;
+ r = __netlink_enumerate(fd, 1, RTM_GETLINK, link_af, cb, ctx);
+ if (!r) r = __netlink_enumerate(fd, 2, RTM_GETADDR, addr_af, cb, ctx);
+ __syscall(SYS_close,fd);
+ return r;
+}
diff --git a/libc-top-half/musl/src/network/netlink.h b/libc-top-half/musl/src/network/netlink.h
new file mode 100644
index 0000000..38acb17
--- /dev/null
+++ b/libc-top-half/musl/src/network/netlink.h
@@ -0,0 +1,94 @@
+#include <stdint.h>
+
+/* linux/netlink.h */
+
+#define NETLINK_ROUTE 0
+
+struct nlmsghdr {
+ uint32_t nlmsg_len;
+ uint16_t nlmsg_type;
+ uint16_t nlmsg_flags;
+ uint32_t nlmsg_seq;
+ uint32_t nlmsg_pid;
+};
+
+#define NLM_F_REQUEST 1
+#define NLM_F_MULTI 2
+#define NLM_F_ACK 4
+
+#define NLM_F_ROOT 0x100
+#define NLM_F_MATCH 0x200
+#define NLM_F_ATOMIC 0x400
+#define NLM_F_DUMP (NLM_F_ROOT|NLM_F_MATCH)
+
+#define NLMSG_NOOP 0x1
+#define NLMSG_ERROR 0x2
+#define NLMSG_DONE 0x3
+#define NLMSG_OVERRUN 0x4
+
+/* linux/rtnetlink.h */
+
+#define RTM_NEWLINK 16
+#define RTM_GETLINK 18
+#define RTM_NEWADDR 20
+#define RTM_GETADDR 22
+
+struct rtattr {
+ unsigned short rta_len;
+ unsigned short rta_type;
+};
+
+struct rtgenmsg {
+ unsigned char rtgen_family;
+};
+
+struct ifinfomsg {
+ unsigned char ifi_family;
+ unsigned char __ifi_pad;
+ unsigned short ifi_type;
+ int ifi_index;
+ unsigned ifi_flags;
+ unsigned ifi_change;
+};
+
+/* linux/if_link.h */
+
+#define IFLA_ADDRESS 1
+#define IFLA_BROADCAST 2
+#define IFLA_IFNAME 3
+#define IFLA_STATS 7
+
+/* linux/if_addr.h */
+
+struct ifaddrmsg {
+ uint8_t ifa_family;
+ uint8_t ifa_prefixlen;
+ uint8_t ifa_flags;
+ uint8_t ifa_scope;
+ uint32_t ifa_index;
+};
+
+#define IFA_ADDRESS 1
+#define IFA_LOCAL 2
+#define IFA_LABEL 3
+#define IFA_BROADCAST 4
+
+/* musl */
+
+#define NETLINK_ALIGN(len) (((len)+3) & ~3)
+#define NLMSG_DATA(nlh) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)))
+#define NLMSG_DATALEN(nlh) ((nlh)->nlmsg_len-sizeof(struct nlmsghdr))
+#define NLMSG_DATAEND(nlh) ((char*)(nlh)+(nlh)->nlmsg_len)
+#define NLMSG_NEXT(nlh) (struct nlmsghdr*)((char*)(nlh)+NETLINK_ALIGN((nlh)->nlmsg_len))
+#define NLMSG_OK(nlh,end) ((char*)(end)-(char*)(nlh) >= sizeof(struct nlmsghdr))
+
+#define RTA_DATA(rta) ((void*)((char*)(rta)+sizeof(struct rtattr)))
+#define RTA_DATALEN(rta) ((rta)->rta_len-sizeof(struct rtattr))
+#define RTA_DATAEND(rta) ((char*)(rta)+(rta)->rta_len)
+#define RTA_NEXT(rta) (struct rtattr*)((char*)(rta)+NETLINK_ALIGN((rta)->rta_len))
+#define RTA_OK(nlh,end) ((char*)(end)-(char*)(rta) >= sizeof(struct rtattr))
+
+#define NLMSG_RTA(nlh,len) ((void*)((char*)(nlh)+sizeof(struct nlmsghdr)+NETLINK_ALIGN(len)))
+#define NLMSG_RTAOK(rta,nlh) RTA_OK(rta,NLMSG_DATAEND(nlh))
+
+hidden int __rtnetlink_enumerate(int link_af, int addr_af, int (*cb)(void *ctx, struct nlmsghdr *h), void *ctx);
diff --git a/libc-top-half/musl/src/network/netname.c b/libc-top-half/musl/src/network/netname.c
new file mode 100644
index 0000000..ba6e665
--- /dev/null
+++ b/libc-top-half/musl/src/network/netname.c
@@ -0,0 +1,12 @@
+#include <netdb.h>
+
+struct netent *getnetbyaddr(uint32_t net, int type)
+{
+ return 0;
+}
+
+struct netent *getnetbyname(const char *name)
+{
+ return 0;
+}
+
diff --git a/libc-top-half/musl/src/network/ns_parse.c b/libc-top-half/musl/src/network/ns_parse.c
new file mode 100644
index 0000000..d01da47
--- /dev/null
+++ b/libc-top-half/musl/src/network/ns_parse.c
@@ -0,0 +1,171 @@
+#define _BSD_SOURCE
+#include <errno.h>
+#include <stddef.h>
+#include <resolv.h>
+#include <arpa/nameser.h>
+
+const struct _ns_flagdata _ns_flagdata[16] = {
+ { 0x8000, 15 },
+ { 0x7800, 11 },
+ { 0x0400, 10 },
+ { 0x0200, 9 },
+ { 0x0100, 8 },
+ { 0x0080, 7 },
+ { 0x0040, 6 },
+ { 0x0020, 5 },
+ { 0x0010, 4 },
+ { 0x000f, 0 },
+ { 0x0000, 0 },
+ { 0x0000, 0 },
+ { 0x0000, 0 },
+ { 0x0000, 0 },
+ { 0x0000, 0 },
+ { 0x0000, 0 },
+};
+
+unsigned ns_get16(const unsigned char *cp)
+{
+ return cp[0]<<8 | cp[1];
+}
+
+unsigned long ns_get32(const unsigned char *cp)
+{
+ return (unsigned)cp[0]<<24 | cp[1]<<16 | cp[2]<<8 | cp[3];
+}
+
+void ns_put16(unsigned s, unsigned char *cp)
+{
+ *cp++ = s>>8;
+ *cp++ = s;
+}
+
+void ns_put32(unsigned long l, unsigned char *cp)
+{
+ *cp++ = l>>24;
+ *cp++ = l>>16;
+ *cp++ = l>>8;
+ *cp++ = l;
+}
+
+int ns_initparse(const unsigned char *msg, int msglen, ns_msg *handle)
+{
+ int i, r;
+
+ handle->_msg = msg;
+ handle->_eom = msg + msglen;
+ if (msglen < (2 + ns_s_max) * NS_INT16SZ) goto bad;
+ NS_GET16(handle->_id, msg);
+ NS_GET16(handle->_flags, msg);
+ for (i = 0; i < ns_s_max; i++) NS_GET16(handle->_counts[i], msg);
+ for (i = 0; i < ns_s_max; i++) {
+ if (handle->_counts[i]) {
+ handle->_sections[i] = msg;
+ r = ns_skiprr(msg, handle->_eom, i, handle->_counts[i]);
+ if (r < 0) return -1;
+ msg += r;
+ } else {
+ handle->_sections[i] = NULL;
+ }
+ }
+ if (msg != handle->_eom) goto bad;
+ handle->_sect = ns_s_max;
+ handle->_rrnum = -1;
+ handle->_msg_ptr = NULL;
+ return 0;
+bad:
+ errno = EMSGSIZE;
+ return -1;
+}
+
+int ns_skiprr(const unsigned char *ptr, const unsigned char *eom, ns_sect section, int count)
+{
+ const unsigned char *p = ptr;
+ int r;
+
+ while (count--) {
+ r = dn_skipname(p, eom);
+ if (r < 0) goto bad;
+ if (r + 2 * NS_INT16SZ > eom - p) goto bad;
+ p += r + 2 * NS_INT16SZ;
+ if (section != ns_s_qd) {
+ if (NS_INT32SZ + NS_INT16SZ > eom - p) goto bad;
+ p += NS_INT32SZ;
+ NS_GET16(r, p);
+ if (r > eom - p) goto bad;
+ p += r;
+ }
+ }
+ return p - ptr;
+bad:
+ errno = EMSGSIZE;
+ return -1;
+}
+
+int ns_parserr(ns_msg *handle, ns_sect section, int rrnum, ns_rr *rr)
+{
+ int r;
+
+ if (section < 0 || section >= ns_s_max) goto bad;
+ if (section != handle->_sect) {
+ handle->_sect = section;
+ handle->_rrnum = 0;
+ handle->_msg_ptr = handle->_sections[section];
+ }
+ if (rrnum == -1) rrnum = handle->_rrnum;
+ if (rrnum < 0 || rrnum >= handle->_counts[section]) goto bad;
+ if (rrnum < handle->_rrnum) {
+ handle->_rrnum = 0;
+ handle->_msg_ptr = handle->_sections[section];
+ }
+ if (rrnum > handle->_rrnum) {
+ r = ns_skiprr(handle->_msg_ptr, handle->_eom, section, rrnum - handle->_rrnum);
+ if (r < 0) return -1;
+ handle->_msg_ptr += r;
+ handle->_rrnum = rrnum;
+ }
+ r = ns_name_uncompress(handle->_msg, handle->_eom, handle->_msg_ptr, rr->name, NS_MAXDNAME);
+ if (r < 0) return -1;
+ handle->_msg_ptr += r;
+ if (2 * NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
+ NS_GET16(rr->type, handle->_msg_ptr);
+ NS_GET16(rr->rr_class, handle->_msg_ptr);
+ if (section != ns_s_qd) {
+ if (NS_INT32SZ + NS_INT16SZ > handle->_eom - handle->_msg_ptr) goto size;
+ NS_GET32(rr->ttl, handle->_msg_ptr);
+ NS_GET16(rr->rdlength, handle->_msg_ptr);
+ if (rr->rdlength > handle->_eom - handle->_msg_ptr) goto size;
+ rr->rdata = handle->_msg_ptr;
+ handle->_msg_ptr += rr->rdlength;
+ } else {
+ rr->ttl = 0;
+ rr->rdlength = 0;
+ rr->rdata = NULL;
+ }
+ handle->_rrnum++;
+ if (handle->_rrnum > handle->_counts[section]) {
+ handle->_sect = section + 1;
+ if (handle->_sect == ns_s_max) {
+ handle->_rrnum = -1;
+ handle->_msg_ptr = NULL;
+ } else {
+ handle->_rrnum = 0;
+ }
+ }
+ return 0;
+bad:
+ errno = ENODEV;
+ return -1;
+size:
+ errno = EMSGSIZE;
+ return -1;
+}
+
+int ns_name_uncompress(const unsigned char *msg, const unsigned char *eom,
+ const unsigned char *src, char *dst, size_t dstsiz)
+{
+ int r;
+ r = dn_expand(msg, eom, src, dst, dstsiz);
+ if (r < 0) errno = EMSGSIZE;
+ return r;
+}
+
diff --git a/libc-top-half/musl/src/network/ntohl.c b/libc-top-half/musl/src/network/ntohl.c
new file mode 100644
index 0000000..d6fce45
--- /dev/null
+++ b/libc-top-half/musl/src/network/ntohl.c
@@ -0,0 +1,8 @@
+#include <netinet/in.h>
+#include <byteswap.h>
+
+uint32_t ntohl(uint32_t n)
+{
+ union { int i; char c; } u = { 1 };
+ return u.c ? bswap_32(n) : n;
+}
diff --git a/libc-top-half/musl/src/network/ntohs.c b/libc-top-half/musl/src/network/ntohs.c
new file mode 100644
index 0000000..745cef4
--- /dev/null
+++ b/libc-top-half/musl/src/network/ntohs.c
@@ -0,0 +1,8 @@
+#include <netinet/in.h>
+#include <byteswap.h>
+
+uint16_t ntohs(uint16_t n)
+{
+ union { int i; char c; } u = { 1 };
+ return u.c ? bswap_16(n) : n;
+}
diff --git a/libc-top-half/musl/src/network/proto.c b/libc-top-half/musl/src/network/proto.c
new file mode 100644
index 0000000..c4fd34e
--- /dev/null
+++ b/libc-top-half/musl/src/network/proto.c
@@ -0,0 +1,84 @@
+#include <netdb.h>
+#include <string.h>
+
+/* do we really need all these?? */
+
+static int idx;
+static const unsigned char protos[] = {
+ "\000ip\0"
+ "\001icmp\0"
+ "\002igmp\0"
+ "\003ggp\0"
+ "\004ipencap\0"
+ "\005st\0"
+ "\006tcp\0"
+ "\010egp\0"
+ "\014pup\0"
+ "\021udp\0"
+ "\024hmp\0"
+ "\026xns-idp\0"
+ "\033rdp\0"
+ "\035iso-tp4\0"
+ "\044xtp\0"
+ "\045ddp\0"
+ "\046idpr-cmtp\0"
+ "\051ipv6\0"
+ "\053ipv6-route\0"
+ "\054ipv6-frag\0"
+ "\055idrp\0"
+ "\056rsvp\0"
+ "\057gre\0"
+ "\062esp\0"
+ "\063ah\0"
+ "\071skip\0"
+ "\072ipv6-icmp\0"
+ "\073ipv6-nonxt\0"
+ "\074ipv6-opts\0"
+ "\111rspf\0"
+ "\121vmtp\0"
+ "\131ospf\0"
+ "\136ipip\0"
+ "\142encap\0"
+ "\147pim\0"
+ "\377raw"
+};
+
+void endprotoent(void)
+{
+ idx = 0;
+}
+
+void setprotoent(int stayopen)
+{
+ idx = 0;
+}
+
+struct protoent *getprotoent(void)
+{
+ static struct protoent p;
+ static const char *aliases;
+ if (idx >= sizeof protos) return NULL;
+ p.p_proto = protos[idx];
+ p.p_name = (char *)&protos[idx+1];
+ p.p_aliases = (char **)&aliases;
+ idx += strlen(p.p_name) + 2;
+ return &p;
+}
+
+struct protoent *getprotobyname(const char *name)
+{
+ struct protoent *p;
+ endprotoent();
+ do p = getprotoent();
+ while (p && strcmp(name, p->p_name));
+ return p;
+}
+
+struct protoent *getprotobynumber(int num)
+{
+ struct protoent *p;
+ endprotoent();
+ do p = getprotoent();
+ while (p && p->p_proto != num);
+ return p;
+}
diff --git a/libc-top-half/musl/src/network/recv.c b/libc-top-half/musl/src/network/recv.c
new file mode 100644
index 0000000..5970048
--- /dev/null
+++ b/libc-top-half/musl/src/network/recv.c
@@ -0,0 +1,6 @@
+#include <sys/socket.h>
+
+ssize_t recv(int fd, void *buf, size_t len, int flags)
+{
+ return recvfrom(fd, buf, len, flags, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/recvfrom.c b/libc-top-half/musl/src/network/recvfrom.c
new file mode 100644
index 0000000..6191166
--- /dev/null
+++ b/libc-top-half/musl/src/network/recvfrom.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+ssize_t recvfrom(int fd, void *restrict buf, size_t len, int flags, struct sockaddr *restrict addr, socklen_t *restrict alen)
+{
+ return socketcall_cp(recvfrom, fd, buf, len, flags, addr, alen);
+}
diff --git a/libc-top-half/musl/src/network/recvmmsg.c b/libc-top-half/musl/src/network/recvmmsg.c
new file mode 100644
index 0000000..2978e2f
--- /dev/null
+++ b/libc-top-half/musl/src/network/recvmmsg.c
@@ -0,0 +1,39 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <limits.h>
+#include <errno.h>
+#include <time.h>
+#include "syscall.h"
+
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
+
+hidden void __convert_scm_timestamps(struct msghdr *, socklen_t);
+
+int recvmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags, struct timespec *timeout)
+{
+#if LONG_MAX > INT_MAX
+ struct mmsghdr *mh = msgvec;
+ unsigned int i;
+ for (i = vlen; i; i--, mh++)
+ mh->msg_hdr.__pad1 = mh->msg_hdr.__pad2 = 0;
+#endif
+#ifdef SYS_recvmmsg_time64
+ time_t s = timeout ? timeout->tv_sec : 0;
+ long ns = timeout ? timeout->tv_nsec : 0;
+ int r = __syscall_cp(SYS_recvmmsg_time64, fd, msgvec, vlen, flags,
+ timeout ? ((long long[]){s, ns}) : 0);
+ if (SYS_recvmmsg == SYS_recvmmsg_time64 || r!=-ENOSYS)
+ return __syscall_ret(r);
+ if (vlen > IOV_MAX) vlen = IOV_MAX;
+ socklen_t csize[vlen];
+ for (int i=0; i<vlen; i++) csize[i] = msgvec[i].msg_hdr.msg_controllen;
+ r = __syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags,
+ timeout ? ((long[]){CLAMP(s), ns}) : 0);
+ for (int i=0; i<r; i++)
+ __convert_scm_timestamps(&msgvec[i].msg_hdr, csize[i]);
+ return __syscall_ret(r);
+#else
+ return syscall_cp(SYS_recvmmsg, fd, msgvec, vlen, flags, timeout);
+#endif
+}
diff --git a/libc-top-half/musl/src/network/recvmsg.c b/libc-top-half/musl/src/network/recvmsg.c
new file mode 100644
index 0000000..0364162
--- /dev/null
+++ b/libc-top-half/musl/src/network/recvmsg.c
@@ -0,0 +1,68 @@
+#include <sys/socket.h>
+#include <limits.h>
+#include <time.h>
+#include <sys/time.h>
+#include <string.h>
+#include "syscall.h"
+
+hidden void __convert_scm_timestamps(struct msghdr *, socklen_t);
+
+void __convert_scm_timestamps(struct msghdr *msg, socklen_t csize)
+{
+ if (SCM_TIMESTAMP == SCM_TIMESTAMP_OLD) return;
+ if (!msg->msg_control || !msg->msg_controllen) return;
+
+ struct cmsghdr *cmsg, *last=0;
+ long tmp;
+ long long tvts[2];
+ int type = 0;
+
+ for (cmsg=CMSG_FIRSTHDR(msg); cmsg; cmsg=CMSG_NXTHDR(msg, cmsg)) {
+ if (cmsg->cmsg_level==SOL_SOCKET) switch (cmsg->cmsg_type) {
+ case SCM_TIMESTAMP_OLD:
+ if (type) break;
+ type = SCM_TIMESTAMP;
+ goto common;
+ case SCM_TIMESTAMPNS_OLD:
+ type = SCM_TIMESTAMPNS;
+ common:
+ memcpy(&tmp, CMSG_DATA(cmsg), sizeof tmp);
+ tvts[0] = tmp;
+ memcpy(&tmp, CMSG_DATA(cmsg) + sizeof tmp, sizeof tmp);
+ tvts[1] = tmp;
+ break;
+ }
+ last = cmsg;
+ }
+ if (!last || !type) return;
+ if (CMSG_SPACE(sizeof tvts) > csize-msg->msg_controllen) {
+ msg->msg_flags |= MSG_CTRUNC;
+ return;
+ }
+ msg->msg_controllen += CMSG_SPACE(sizeof tvts);
+ cmsg = CMSG_NXTHDR(msg, last);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = type;
+ cmsg->cmsg_len = CMSG_LEN(sizeof tvts);
+ memcpy(CMSG_DATA(cmsg), &tvts, sizeof tvts);
+}
+
+ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ ssize_t r;
+ socklen_t orig_controllen = msg->msg_controllen;
+#if LONG_MAX > INT_MAX
+ struct msghdr h, *orig = msg;
+ if (msg) {
+ h = *msg;
+ h.__pad1 = h.__pad2 = 0;
+ msg = &h;
+ }
+#endif
+ r = socketcall_cp(recvmsg, fd, msg, flags, 0, 0, 0);
+ if (r >= 0) __convert_scm_timestamps(msg, orig_controllen);
+#if LONG_MAX > INT_MAX
+ if (orig) *orig = h;
+#endif
+ return r;
+}
diff --git a/libc-top-half/musl/src/network/res_init.c b/libc-top-half/musl/src/network/res_init.c
new file mode 100644
index 0000000..5dba9df
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_init.c
@@ -0,0 +1,6 @@
+#include <resolv.h>
+
+int res_init()
+{
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/res_mkquery.c b/libc-top-half/musl/src/network/res_mkquery.c
new file mode 100644
index 0000000..33f50cb
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_mkquery.c
@@ -0,0 +1,44 @@
+#include <resolv.h>
+#include <string.h>
+#include <time.h>
+
+int __res_mkquery(int op, const char *dname, int class, int type,
+ const unsigned char *data, int datalen,
+ const unsigned char *newrr, unsigned char *buf, int buflen)
+{
+ int id, i, j;
+ unsigned char q[280];
+ struct timespec ts;
+ size_t l = strnlen(dname, 255);
+ int n;
+
+ if (l && dname[l-1]=='.') l--;
+ n = 17+l+!!l;
+ if (l>253 || buflen<n || op>15u || class>255u || type>255u)
+ return -1;
+
+ /* Construct query template - ID will be filled later */
+ memset(q, 0, n);
+ q[2] = op*8 + 1;
+ q[3] = 32; /* AD */
+ q[5] = 1;
+ memcpy((char *)q+13, dname, l);
+ for (i=13; q[i]; i=j+1) {
+ for (j=i; q[j] && q[j] != '.'; j++);
+ if (j-i-1u > 62u) return -1;
+ q[i-1] = j-i;
+ }
+ q[i+1] = type;
+ q[i+3] = class;
+
+ /* Make a reasonably unpredictable id */
+ clock_gettime(CLOCK_REALTIME, &ts);
+ id = ts.tv_nsec + ts.tv_nsec/65536UL & 0xffff;
+ q[0] = id/256;
+ q[1] = id;
+
+ memcpy(buf, q, n);
+ return n;
+}
+
+weak_alias(__res_mkquery, res_mkquery);
diff --git a/libc-top-half/musl/src/network/res_msend.c b/libc-top-half/musl/src/network/res_msend.c
new file mode 100644
index 0000000..3e01800
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_msend.c
@@ -0,0 +1,188 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdint.h>
+#include <string.h>
+#include <poll.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <errno.h>
+#include <pthread.h>
+#include "stdio_impl.h"
+#include "syscall.h"
+#include "lookup.h"
+
+static void cleanup(void *p)
+{
+ __syscall(SYS_close, (intptr_t)p);
+}
+
+static unsigned long mtime()
+{
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ return (unsigned long)ts.tv_sec * 1000
+ + ts.tv_nsec / 1000000;
+}
+
+int __res_msend_rc(int nqueries, const unsigned char *const *queries,
+ const int *qlens, unsigned char *const *answers, int *alens, int asize,
+ const struct resolvconf *conf)
+{
+ int fd;
+ int timeout, attempts, retry_interval, servfail_retry;
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sa = {0}, ns[MAXNS] = {{0}};
+ socklen_t sl = sizeof sa.sin;
+ int nns = 0;
+ int family = AF_INET;
+ int rlen;
+ int next;
+ int i, j;
+ int cs;
+ struct pollfd pfd;
+ unsigned long t0, t1, t2;
+
+ pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cs);
+
+ timeout = 1000*conf->timeout;
+ attempts = conf->attempts;
+
+ for (nns=0; nns<conf->nns; nns++) {
+ const struct address *iplit = &conf->ns[nns];
+ if (iplit->family == AF_INET) {
+ memcpy(&ns[nns].sin.sin_addr, iplit->addr, 4);
+ ns[nns].sin.sin_port = htons(53);
+ ns[nns].sin.sin_family = AF_INET;
+ } else {
+ sl = sizeof sa.sin6;
+ memcpy(&ns[nns].sin6.sin6_addr, iplit->addr, 16);
+ ns[nns].sin6.sin6_port = htons(53);
+ ns[nns].sin6.sin6_scope_id = iplit->scopeid;
+ ns[nns].sin6.sin6_family = family = AF_INET6;
+ }
+ }
+
+ /* Get local address and open/bind a socket */
+ sa.sin.sin_family = family;
+ fd = socket(family, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+
+ /* Handle case where system lacks IPv6 support */
+ if (fd < 0 && family == AF_INET6 && errno == EAFNOSUPPORT) {
+ fd = socket(AF_INET, SOCK_DGRAM|SOCK_CLOEXEC|SOCK_NONBLOCK, 0);
+ family = AF_INET;
+ }
+ if (fd < 0 || bind(fd, (void *)&sa, sl) < 0) {
+ if (fd >= 0) close(fd);
+ pthread_setcancelstate(cs, 0);
+ return -1;
+ }
+
+ /* Past this point, there are no errors. Each individual query will
+ * yield either no reply (indicated by zero length) or an answer
+ * packet which is up to the caller to interpret. */
+
+ pthread_cleanup_push(cleanup, (void *)(intptr_t)fd);
+ pthread_setcancelstate(cs, 0);
+
+ /* Convert any IPv4 addresses in a mixed environment to v4-mapped */
+ if (family == AF_INET6) {
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY, &(int){0}, sizeof 0);
+ for (i=0; i<nns; i++) {
+ if (ns[i].sin.sin_family != AF_INET) continue;
+ memcpy(ns[i].sin6.sin6_addr.s6_addr+12,
+ &ns[i].sin.sin_addr, 4);
+ memcpy(ns[i].sin6.sin6_addr.s6_addr,
+ "\0\0\0\0\0\0\0\0\0\0\xff\xff", 12);
+ ns[i].sin6.sin6_family = AF_INET6;
+ ns[i].sin6.sin6_flowinfo = 0;
+ ns[i].sin6.sin6_scope_id = 0;
+ }
+ }
+
+ memset(alens, 0, sizeof *alens * nqueries);
+
+ pfd.fd = fd;
+ pfd.events = POLLIN;
+ retry_interval = timeout / attempts;
+ next = 0;
+ t0 = t2 = mtime();
+ t1 = t2 - retry_interval;
+
+ for (; t2-t0 < timeout; t2=mtime()) {
+ if (t2-t1 >= retry_interval) {
+ /* Query all configured namservers in parallel */
+ for (i=0; i<nqueries; i++)
+ if (!alens[i])
+ for (j=0; j<nns; j++)
+ sendto(fd, queries[i],
+ qlens[i], MSG_NOSIGNAL,
+ (void *)&ns[j], sl);
+ t1 = t2;
+ servfail_retry = 2 * nqueries;
+ }
+
+ /* Wait for a response, or until time to retry */
+ if (poll(&pfd, 1, t1+retry_interval-t2) <= 0) continue;
+
+ while ((rlen = recvfrom(fd, answers[next], asize, 0,
+ (void *)&sa, (socklen_t[1]){sl})) >= 0) {
+
+ /* Ignore non-identifiable packets */
+ if (rlen < 4) continue;
+
+ /* Ignore replies from addresses we didn't send to */
+ for (j=0; j<nns && memcmp(ns+j, &sa, sl); j++);
+ if (j==nns) continue;
+
+ /* Find which query this answer goes with, if any */
+ for (i=next; i<nqueries && (
+ answers[next][0] != queries[i][0] ||
+ answers[next][1] != queries[i][1] ); i++);
+ if (i==nqueries) continue;
+ if (alens[i]) continue;
+
+ /* Only accept positive or negative responses;
+ * retry immediately on server failure, and ignore
+ * all other codes such as refusal. */
+ switch (answers[next][3] & 15) {
+ case 0:
+ case 3:
+ break;
+ case 2:
+ if (servfail_retry && servfail_retry--)
+ sendto(fd, queries[i],
+ qlens[i], MSG_NOSIGNAL,
+ (void *)&ns[j], sl);
+ default:
+ continue;
+ }
+
+ /* Store answer in the right slot, or update next
+ * available temp slot if it's already in place. */
+ alens[i] = rlen;
+ if (i == next)
+ for (; next<nqueries && alens[next]; next++);
+ else
+ memcpy(answers[i], answers[next], rlen);
+
+ if (next == nqueries) goto out;
+ }
+ }
+out:
+ pthread_cleanup_pop(1);
+
+ return 0;
+}
+
+int __res_msend(int nqueries, const unsigned char *const *queries,
+ const int *qlens, unsigned char *const *answers, int *alens, int asize)
+{
+ struct resolvconf conf;
+ if (__get_resolv_conf(&conf, 0, 0) < 0) return -1;
+ return __res_msend_rc(nqueries, queries, qlens, answers, alens, asize, &conf);
+}
diff --git a/libc-top-half/musl/src/network/res_query.c b/libc-top-half/musl/src/network/res_query.c
new file mode 100644
index 0000000..506dc23
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_query.c
@@ -0,0 +1,26 @@
+#define _BSD_SOURCE
+#include <resolv.h>
+#include <netdb.h>
+
+int res_query(const char *name, int class, int type, unsigned char *dest, int len)
+{
+ unsigned char q[280];
+ int ql = __res_mkquery(0, name, class, type, 0, 0, 0, q, sizeof q);
+ if (ql < 0) return ql;
+ int r = __res_send(q, ql, dest, len);
+ if (r<12) {
+ h_errno = TRY_AGAIN;
+ return -1;
+ }
+ if ((dest[3] & 15) == 3) {
+ h_errno = HOST_NOT_FOUND;
+ return -1;
+ }
+ if ((dest[3] & 15) == 0 && !dest[6] && !dest[7]) {
+ h_errno = NO_DATA;
+ return -1;
+ }
+ return r;
+}
+
+weak_alias(res_query, res_search);
diff --git a/libc-top-half/musl/src/network/res_querydomain.c b/libc-top-half/musl/src/network/res_querydomain.c
new file mode 100644
index 0000000..727e6f6
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_querydomain.c
@@ -0,0 +1,14 @@
+#include <resolv.h>
+#include <string.h>
+
+int res_querydomain(const char *name, const char *domain, int class, int type, unsigned char *dest, int len)
+{
+ char tmp[255];
+ size_t nl = strnlen(name, 255);
+ size_t dl = strnlen(domain, 255);
+ if (nl+dl+1 > 254) return -1;
+ memcpy(tmp, name, nl);
+ tmp[nl] = '.';
+ memcpy(tmp+nl+1, domain, dl+1);
+ return res_query(tmp, class, type, dest, len);
+}
diff --git a/libc-top-half/musl/src/network/res_send.c b/libc-top-half/musl/src/network/res_send.c
new file mode 100644
index 0000000..ee4abf1
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_send.c
@@ -0,0 +1,9 @@
+#include <resolv.h>
+
+int __res_send(const unsigned char *msg, int msglen, unsigned char *answer, int anslen)
+{
+ int r = __res_msend(1, &msg, &msglen, &answer, &anslen, anslen);
+ return r<0 || !anslen ? -1 : anslen;
+}
+
+weak_alias(__res_send, res_send);
diff --git a/libc-top-half/musl/src/network/res_state.c b/libc-top-half/musl/src/network/res_state.c
new file mode 100644
index 0000000..5c42cda
--- /dev/null
+++ b/libc-top-half/musl/src/network/res_state.c
@@ -0,0 +1,9 @@
+#include <resolv.h>
+
+/* This is completely unused, and exists purely to satisfy broken apps. */
+
+struct __res_state *__res_state()
+{
+ static struct __res_state res;
+ return &res;
+}
diff --git a/libc-top-half/musl/src/network/resolvconf.c b/libc-top-half/musl/src/network/resolvconf.c
new file mode 100644
index 0000000..ceabf08
--- /dev/null
+++ b/libc-top-half/musl/src/network/resolvconf.c
@@ -0,0 +1,94 @@
+#include "lookup.h"
+#include "stdio_impl.h"
+#include <ctype.h>
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+#include <netinet/in.h>
+
+int __get_resolv_conf(struct resolvconf *conf, char *search, size_t search_sz)
+{
+ char line[256];
+ unsigned char _buf[256];
+ FILE *f, _f;
+ int nns = 0;
+
+ conf->ndots = 1;
+ conf->timeout = 5;
+ conf->attempts = 2;
+ if (search) *search = 0;
+
+ f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+ if (!f) switch (errno) {
+ case ENOENT:
+ case ENOTDIR:
+ case EACCES:
+ goto no_resolv_conf;
+ default:
+ return -1;
+ }
+
+ while (fgets(line, sizeof line, f)) {
+ char *p, *z;
+ if (!strchr(line, '\n') && !feof(f)) {
+ /* Ignore lines that get truncated rather than
+ * potentially misinterpreting them. */
+ int c;
+ do c = getc(f);
+ while (c != '\n' && c != EOF);
+ continue;
+ }
+ if (!strncmp(line, "options", 7) && isspace(line[7])) {
+ p = strstr(line, "ndots:");
+ if (p && isdigit(p[6])) {
+ p += 6;
+ unsigned long x = strtoul(p, &z, 10);
+ if (z != p) conf->ndots = x > 15 ? 15 : x;
+ }
+ p = strstr(line, "attempts:");
+ if (p && isdigit(p[9])) {
+ p += 9;
+ unsigned long x = strtoul(p, &z, 10);
+ if (z != p) conf->attempts = x > 10 ? 10 : x;
+ }
+ p = strstr(line, "timeout:");
+ if (p && (isdigit(p[8]) || p[8]=='.')) {
+ p += 8;
+ unsigned long x = strtoul(p, &z, 10);
+ if (z != p) conf->timeout = x > 60 ? 60 : x;
+ }
+ continue;
+ }
+ if (!strncmp(line, "nameserver", 10) && isspace(line[10])) {
+ if (nns >= MAXNS) continue;
+ for (p=line+11; isspace(*p); p++);
+ for (z=p; *z && !isspace(*z); z++);
+ *z=0;
+ if (__lookup_ipliteral(conf->ns+nns, p, AF_UNSPEC) > 0)
+ nns++;
+ continue;
+ }
+
+ if (!search) continue;
+ if ((strncmp(line, "domain", 6) && strncmp(line, "search", 6))
+ || !isspace(line[6]))
+ continue;
+ for (p=line+7; isspace(*p); p++);
+ size_t l = strlen(p);
+ /* This can never happen anyway with chosen buffer sizes. */
+ if (l >= search_sz) continue;
+ memcpy(search, p, l+1);
+ }
+
+ __fclose_ca(f);
+
+no_resolv_conf:
+ if (!nns) {
+ __lookup_ipliteral(conf->ns, "127.0.0.1", AF_UNSPEC);
+ nns = 1;
+ }
+
+ conf->nns = nns;
+
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/send.c b/libc-top-half/musl/src/network/send.c
new file mode 100644
index 0000000..9f10497
--- /dev/null
+++ b/libc-top-half/musl/src/network/send.c
@@ -0,0 +1,6 @@
+#include <sys/socket.h>
+
+ssize_t send(int fd, const void *buf, size_t len, int flags)
+{
+ return sendto(fd, buf, len, flags, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/sendmmsg.c b/libc-top-half/musl/src/network/sendmmsg.c
new file mode 100644
index 0000000..eeae1d0
--- /dev/null
+++ b/libc-top-half/musl/src/network/sendmmsg.c
@@ -0,0 +1,30 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <limits.h>
+#include <errno.h>
+#include "syscall.h"
+
+int sendmmsg(int fd, struct mmsghdr *msgvec, unsigned int vlen, unsigned int flags)
+{
+#if LONG_MAX > INT_MAX
+ /* Can't use the syscall directly because the kernel has the wrong
+ * idea for the types of msg_iovlen, msg_controllen, and cmsg_len,
+ * and the cmsg blocks cannot be modified in-place. */
+ int i;
+ if (vlen > IOV_MAX) vlen = IOV_MAX; /* This matches the kernel. */
+ if (!vlen) return 0;
+ for (i=0; i<vlen; i++) {
+ /* As an unfortunate inconsistency, the sendmmsg API uses
+ * unsigned int for the resulting msg_len, despite sendmsg
+ * returning ssize_t. However Linux limits the total bytes
+ * sent by sendmsg to INT_MAX, so the assignment is safe. */
+ ssize_t r = sendmsg(fd, &msgvec[i].msg_hdr, flags);
+ if (r < 0) goto error;
+ msgvec[i].msg_len = r;
+ }
+error:
+ return i ? i : -1;
+#else
+ return syscall_cp(SYS_sendmmsg, fd, msgvec, vlen, flags);
+#endif
+}
diff --git a/libc-top-half/musl/src/network/sendmsg.c b/libc-top-half/musl/src/network/sendmsg.c
new file mode 100644
index 0000000..80cc5f4
--- /dev/null
+++ b/libc-top-half/musl/src/network/sendmsg.c
@@ -0,0 +1,29 @@
+#include <sys/socket.h>
+#include <limits.h>
+#include <string.h>
+#include <errno.h>
+#include "syscall.h"
+
+ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+#if LONG_MAX > INT_MAX
+ struct msghdr h;
+ struct cmsghdr chbuf[1024/sizeof(struct cmsghdr)+1], *c;
+ if (msg) {
+ h = *msg;
+ h.__pad1 = h.__pad2 = 0;
+ msg = &h;
+ if (h.msg_controllen) {
+ if (h.msg_controllen > 1024) {
+ errno = ENOMEM;
+ return -1;
+ }
+ memcpy(chbuf, h.msg_control, h.msg_controllen);
+ h.msg_control = chbuf;
+ for (c=CMSG_FIRSTHDR(&h); c; c=CMSG_NXTHDR(&h,c))
+ c->__pad1 = 0;
+ }
+ }
+#endif
+ return socketcall_cp(sendmsg, fd, msg, flags, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/sendto.c b/libc-top-half/musl/src/network/sendto.c
new file mode 100644
index 0000000..c598797
--- /dev/null
+++ b/libc-top-half/musl/src/network/sendto.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen)
+{
+ return socketcall_cp(sendto, fd, buf, len, flags, addr, alen);
+}
diff --git a/libc-top-half/musl/src/network/serv.c b/libc-top-half/musl/src/network/serv.c
new file mode 100644
index 0000000..41424e8
--- /dev/null
+++ b/libc-top-half/musl/src/network/serv.c
@@ -0,0 +1,14 @@
+#include <netdb.h>
+
+void endservent(void)
+{
+}
+
+void setservent(int stayopen)
+{
+}
+
+struct servent *getservent(void)
+{
+ return 0;
+}
diff --git a/libc-top-half/musl/src/network/setsockopt.c b/libc-top-half/musl/src/network/setsockopt.c
new file mode 100644
index 0000000..612a194
--- /dev/null
+++ b/libc-top-half/musl/src/network/setsockopt.c
@@ -0,0 +1,46 @@
+#include <sys/socket.h>
+#include <sys/time.h>
+#include <errno.h>
+#include "syscall.h"
+
+#define IS32BIT(x) !((x)+0x80000000ULL>>32)
+#define CLAMP(x) (int)(IS32BIT(x) ? (x) : 0x7fffffffU+((0ULL+(x))>>63))
+
+int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
+{
+ const struct timeval *tv;
+ time_t s;
+ suseconds_t us;
+
+ int r = __socketcall(setsockopt, fd, level, optname, optval, optlen, 0);
+
+ if (r==-ENOPROTOOPT) switch (level) {
+ case SOL_SOCKET:
+ switch (optname) {
+ case SO_RCVTIMEO:
+ case SO_SNDTIMEO:
+ if (SO_RCVTIMEO == SO_RCVTIMEO_OLD) break;
+ if (optlen < sizeof *tv) return __syscall_ret(-EINVAL);
+ tv = optval;
+ s = tv->tv_sec;
+ us = tv->tv_usec;
+ if (!IS32BIT(s)) return __syscall_ret(-ENOTSUP);
+
+ if (optname==SO_RCVTIMEO) optname=SO_RCVTIMEO_OLD;
+ if (optname==SO_SNDTIMEO) optname=SO_SNDTIMEO_OLD;
+
+ r = __socketcall(setsockopt, fd, level, optname,
+ ((long[]){s, CLAMP(us)}), 2*sizeof(long), 0);
+ break;
+ case SO_TIMESTAMP:
+ case SO_TIMESTAMPNS:
+ if (SO_TIMESTAMP == SO_TIMESTAMP_OLD) break;
+ if (optname==SO_TIMESTAMP) optname=SO_TIMESTAMP_OLD;
+ if (optname==SO_TIMESTAMPNS) optname=SO_TIMESTAMPNS_OLD;
+ r = __socketcall(setsockopt, fd, level,
+ optname, optval, optlen, 0);
+ break;
+ }
+ }
+ return __syscall_ret(r);
+}
diff --git a/libc-top-half/musl/src/network/shutdown.c b/libc-top-half/musl/src/network/shutdown.c
new file mode 100644
index 0000000..10ca21a
--- /dev/null
+++ b/libc-top-half/musl/src/network/shutdown.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include "syscall.h"
+
+int shutdown(int fd, int how)
+{
+ return socketcall(shutdown, fd, how, 0, 0, 0, 0);
+}
diff --git a/libc-top-half/musl/src/network/sockatmark.c b/libc-top-half/musl/src/network/sockatmark.c
new file mode 100644
index 0000000..f474551
--- /dev/null
+++ b/libc-top-half/musl/src/network/sockatmark.c
@@ -0,0 +1,10 @@
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+
+int sockatmark(int s)
+{
+ int ret;
+ if (ioctl(s, SIOCATMARK, &ret) < 0)
+ return -1;
+ return ret;
+}
diff --git a/libc-top-half/musl/src/network/socket.c b/libc-top-half/musl/src/network/socket.c
new file mode 100644
index 0000000..afa1a7f
--- /dev/null
+++ b/libc-top-half/musl/src/network/socket.c
@@ -0,0 +1,21 @@
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "syscall.h"
+
+int socket(int domain, int type, int protocol)
+{
+ int s = __socketcall(socket, domain, type, protocol, 0, 0, 0);
+ if ((s==-EINVAL || s==-EPROTONOSUPPORT)
+ && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) {
+ s = __socketcall(socket, domain,
+ type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK),
+ protocol, 0, 0, 0);
+ if (s < 0) return __syscall_ret(s);
+ if (type & SOCK_CLOEXEC)
+ __syscall(SYS_fcntl, s, F_SETFD, FD_CLOEXEC);
+ if (type & SOCK_NONBLOCK)
+ __syscall(SYS_fcntl, s, F_SETFL, O_NONBLOCK);
+ }
+ return __syscall_ret(s);
+}
diff --git a/libc-top-half/musl/src/network/socketpair.c b/libc-top-half/musl/src/network/socketpair.c
new file mode 100644
index 0000000..f348962
--- /dev/null
+++ b/libc-top-half/musl/src/network/socketpair.c
@@ -0,0 +1,25 @@
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <errno.h>
+#include "syscall.h"
+
+int socketpair(int domain, int type, int protocol, int fd[2])
+{
+ int r = socketcall(socketpair, domain, type, protocol, fd, 0, 0);
+ if (r<0 && (errno==EINVAL || errno==EPROTONOSUPPORT)
+ && (type&(SOCK_CLOEXEC|SOCK_NONBLOCK))) {
+ r = socketcall(socketpair, domain,
+ type & ~(SOCK_CLOEXEC|SOCK_NONBLOCK),
+ protocol, fd, 0, 0);
+ if (r < 0) return r;
+ if (type & SOCK_CLOEXEC) {
+ __syscall(SYS_fcntl, fd[0], F_SETFD, FD_CLOEXEC);
+ __syscall(SYS_fcntl, fd[1], F_SETFD, FD_CLOEXEC);
+ }
+ if (type & SOCK_NONBLOCK) {
+ __syscall(SYS_fcntl, fd[0], F_SETFL, O_NONBLOCK);
+ __syscall(SYS_fcntl, fd[1], F_SETFL, O_NONBLOCK);
+ }
+ }
+ return r;
+}