summaryrefslogtreecommitdiff
path: root/src/network
diff options
context:
space:
mode:
authorRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
committerRich Felker <dalias@aerifal.cx>2011-02-12 00:22:29 -0500
commit0b44a0315b47dd8eced9f3b7f31580cf14bbfc01 (patch)
tree6eaef0d8a720fa3da580de87b647fff796fe80b3 /src/network
downloadmusl-0b44a0315b47dd8eced9f3b7f31580cf14bbfc01.tar.gz
initial check-in, version 0.5.0v0.5.0
Diffstat (limited to 'src/network')
-rw-r--r--src/network/__dns.c267
-rw-r--r--src/network/__dns.h14
-rw-r--r--src/network/__ipparse.c40
-rw-r--r--src/network/accept.c14
-rw-r--r--src/network/bind.c9
-rw-r--r--src/network/connect.c14
-rw-r--r--src/network/dn_expand.c28
-rw-r--r--src/network/ent.c26
-rw-r--r--src/network/freeaddrinfo.c7
-rw-r--r--src/network/gai_strerror.c21
-rw-r--r--src/network/getaddrinfo.c224
-rw-r--r--src/network/gethostbyaddr.c15
-rw-r--r--src/network/gethostbyaddr_r.c71
-rw-r--r--src/network/gethostbyname.c63
-rw-r--r--src/network/gethostbyname2.c16
-rw-r--r--src/network/gethostbyname2_r.c99
-rw-r--r--src/network/gethostbyname_r.c11
-rw-r--r--src/network/getnameinfo.c54
-rw-r--r--src/network/getpeername.c9
-rw-r--r--src/network/getservbyname.c12
-rw-r--r--src/network/getservbyname_r.c41
-rw-r--r--src/network/getservbyport.c12
-rw-r--r--src/network/getservbyport_r.c43
-rw-r--r--src/network/getsockname.c9
-rw-r--r--src/network/getsockopt.c13
-rw-r--r--src/network/h_errno.c1
-rw-r--r--src/network/hstrerror.c16
-rw-r--r--src/network/htonl.c10
-rw-r--r--src/network/htons.c10
-rw-r--r--src/network/in6addr_any.c3
-rw-r--r--src/network/in6addr_loopback.c3
-rw-r--r--src/network/inet_addr.c11
-rw-r--r--src/network/inet_aton.c7
-rw-r--r--src/network/inet_ntoa.c10
-rw-r--r--src/network/inet_ntop.c48
-rw-r--r--src/network/inet_pton.c31
-rw-r--r--src/network/listen.c9
-rw-r--r--src/network/ntohl.c10
-rw-r--r--src/network/ntohs.c10
-rw-r--r--src/network/proto.c58
-rw-r--r--src/network/recv.c14
-rw-r--r--src/network/recvfrom.c17
-rw-r--r--src/network/recvmsg.c14
-rw-r--r--src/network/res_init.c4
-rw-r--r--src/network/res_query.c20
-rw-r--r--src/network/send.c14
-rw-r--r--src/network/sendmsg.c14
-rw-r--r--src/network/sendto.c17
-rw-r--r--src/network/serv.c16
-rw-r--r--src/network/setsockopt.c9
-rw-r--r--src/network/shutdown.c9
-rw-r--r--src/network/sockatmark.c11
-rw-r--r--src/network/socket.c9
-rw-r--r--src/network/socketcall.h24
-rw-r--r--src/network/socketpair.c9
55 files changed, 1570 insertions, 0 deletions
diff --git a/src/network/__dns.c b/src/network/__dns.c
new file mode 100644
index 00000000..73ec422d
--- /dev/null
+++ b/src/network/__dns.c
@@ -0,0 +1,267 @@
+#include <stdint.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+#include <time.h>
+#include <ctype.h>
+#include <unistd.h>
+#include "__dns.h"
+#include "stdio_impl.h"
+
+#define TIMEOUT 5
+#define RETRY 1
+#define PACKET_MAX 512
+#define PTR_MAX (64 + sizeof ".in-addr.arpa")
+
+int __dns_doqueries(unsigned char *dest, const char *name, int *rr, int rrcnt)
+{
+ time_t t0 = time(0);
+ int fd;
+ FILE *f, _f;
+ unsigned char _buf[64];
+ char line[64], *s, *z;
+ union {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+ } sa = {0}, ns[3] = {{0}};
+ socklen_t sl;
+ int nns;
+ int family;
+ unsigned char q[280] = "", *r = dest;
+ int ql;
+ int rlen;
+ int got = 0, failed = 0;
+ int errcode = EAI_AGAIN;
+ int i, j;
+ struct timeval tv;
+ fd_set fds;
+ int id;
+
+ /* Construct query template - RR and ID will be filled later */
+ if (strlen(name)-1 >= 254U) return -1;
+ q[2] = q[5] = 1;
+ strcpy(q+13, name);
+ 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+3] = 1;
+ ql = i+4;
+
+ /* Make a reasonably unpredictable id */
+ gettimeofday(&tv, 0);
+ id = tv.tv_usec + tv.tv_usec/256 & 0xffff;
+
+ /* Get nameservers from resolv.conf, fallback to localhost */
+ f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+ if (f) for (nns=0; nns<3 && fgets(line, sizeof line, f); ) {
+ if (strncmp(line, "nameserver", 10) || !isspace(line[10]))
+ continue;
+ for (s=line+11; isspace(*s); s++);
+ for (z=s; *z && !isspace(*z); z++);
+ *z=0;
+ if (__ipparse(ns+nns, family, s) < 0) continue;
+ ns[nns].sin.sin_port = htons(53);
+ family = ns[nns++].sin.sin_family;
+ sl = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+ }
+ if (f) __fclose_ca(f);
+ if (!nns) {
+ ns[0].sin.sin_family = AF_INET;
+ ns[0].sin.sin_port = htons(53);
+ nns=1;
+ sl = sizeof sa.sin;
+ }
+
+ /* Get local address and open/bind a socket */
+ sa.sin.sin_family = family;
+ fd = socket(family, SOCK_DGRAM, 0);
+ if (bind(fd, (void *)&sa, sl) < 0) {
+ close(fd);
+ return -1;
+ }
+ /* Nonblocking to work around Linux UDP select bug */
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) | O_NONBLOCK);
+
+ /* Loop until we timeout; break early on success */
+ for (; time(0)-t0 < TIMEOUT; ) {
+
+ /* Query all configured namservers in parallel */
+ for (i=0; i<rrcnt; i++) if (rr[i]) for (j=0; j<nns; j++) {
+ q[0] = id+i >> 8;
+ q[1] = id+i;
+ q[ql-3] = rr[i];
+ sendto(fd, q, ql, MSG_NOSIGNAL, (void *)&ns[j], sl);
+ }
+
+ /* Wait for a response, or until time to retry */
+ FD_ZERO(&fds);
+ FD_SET(fd, &fds);
+ tv.tv_sec = RETRY;
+ tv.tv_usec = 0;
+ if (select(fd+1, &fds, 0, 0, &tv) <= 0) continue;
+
+ /* Process any and all replies */
+ while (got+failed < rrcnt && (rlen = recvfrom(fd, r, 512, 0,
+ (void *)&sa, (socklen_t[1]){sl})) >= 2)
+ {
+ /* Ignore replies from addresses we didn't send to */
+ for (i=0; i<nns; i++) if (!memcmp(ns+i, &sa, sl)) break;
+ if (i==nns) continue;
+
+ /* Compute index of the query from id */
+ i = r[0]*256+r[1] - id & 0xffff;
+ if ((unsigned)i >= rrcnt || !rr[i]) continue;
+
+ /* Interpret the result code */
+ switch (r[3] & 15) {
+ case 0:
+ got++;
+ break;
+ case 3:
+ if (1) errcode = EAI_NONAME; else
+ default:
+ errcode = EAI_FAIL;
+ failed++;
+ }
+
+ /* Mark this record as answered */
+ rr[i] = 0;
+ r += 512;
+ }
+
+ /* Check to see if we have answers to all queries */
+ if (got+failed == rrcnt) break;
+ }
+ close(fd);
+
+ /* Return the number of results, or an error code if none */
+ if (got) return got;
+ return errcode;
+}
+
+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");
+}
+
+int __dns_query(unsigned char *r, const void *a, int family, int ptr)
+{
+ char buf[PTR_MAX];
+ int rr[2], rrcnt = 1;
+
+ if (ptr) {
+ if (family == AF_INET6) mkptr6(buf, a);
+ else mkptr4(buf, a);
+ rr[0] = RR_PTR;
+ a = buf;
+ } else if (family == AF_INET6) {
+ rr[0] = RR_AAAA;
+ } else {
+ rr[0] = RR_A;
+ if (family != AF_INET) rr[rrcnt++] = RR_AAAA;
+ }
+
+ return __dns_doqueries(r, a, rr, rrcnt);
+}
+
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+static int decname(char *s, const unsigned char *b, const unsigned char *p)
+{
+ /* Remember jump destinations to detect loops and abort */
+ size_t seen[PACKET_MAX/8/sizeof(size_t)] = { 0 };
+ char *sz = s + HOST_NAME_MAX;
+ const unsigned char *pz = b+512;
+ for (;;) {
+ if (p>=pz) return -1;
+ else if (*p&0xc0) {
+ int j = (p[0]&1) | p[1];
+ if (BITOP(seen, j, &)) return -1;
+ BITOP(seen, j, |=);
+ p = b + j;
+ } else if (*p) {
+ if (p+*p+1>=pz || s+*p>=sz) return -1;
+ memcpy(s, p+1, *p);
+ s += *p+1;
+ p += *p+1;
+ s[-1] = *p ? '.' : 0;
+ } else return 0;
+ }
+}
+
+int __dns_get_rr(void *dest, size_t stride, size_t maxlen, size_t limit, const unsigned char *r, int rr, int dec)
+{
+ int qdcount, ancount;
+ const unsigned char *p;
+ char tmp[256];
+ int found = 0;
+ int len;
+
+ 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 < 512 && *p-1U < 127) p++;
+ if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+ return -1;
+ p += 5 + !!*p;
+ }
+ while (ancount--) {
+ while (p-r < 512 && *p-1U < 127) p++;
+ if (*p>193 || (*p==193 && p[1]>254) || p>r+506)
+ return -1;
+ p += 1 + !!*p;
+ len = p[8]*256 + p[9];
+ if (p+len > r+512) return -1;
+ if (p[1]==rr && len <= maxlen) {
+ if (dec && decname(tmp, r, p+10)<0) return -1;
+ if (dest && limit) {
+ if (dec) strcpy(dest, tmp);
+ else memcpy(dest, p+10, len);
+ dest = (char *)dest + stride;
+ limit--;
+ }
+ found++;
+ }
+ p += 10 + len;
+ }
+ return found;
+}
+
+int __dns_count_addrs(const unsigned char *r, int cnt)
+{
+ int found=0, res, i;
+ static const int p[2][2] = { { 4, RR_A }, { 16, RR_AAAA } };
+
+ while (cnt--) for (i=0; i<2; i++) {
+ res = __dns_get_rr(0, 0, p[i][0], -1, r, p[i][1], 0);
+ if (res < 0) return res;
+ found += res;
+ r += 512;
+ }
+ return found;
+}
diff --git a/src/network/__dns.h b/src/network/__dns.h
new file mode 100644
index 00000000..9a3f7402
--- /dev/null
+++ b/src/network/__dns.h
@@ -0,0 +1,14 @@
+#include <stddef.h>
+
+#define RR_A 1
+#define RR_CNAME 5
+#define RR_PTR 12
+#define RR_AAAA 28
+
+int __dns_count_addrs(const unsigned char *, int);
+int __dns_get_rr(void *, size_t, size_t, size_t, const unsigned char *, int, int);
+
+int __dns_query(unsigned char *, const void *, int, int);
+int __ipparse(void *, int, const char *);
+
+int __dns_doqueries(unsigned char *, const char *, int *, int);
diff --git a/src/network/__ipparse.c b/src/network/__ipparse.c
new file mode 100644
index 00000000..ca9e5890
--- /dev/null
+++ b/src/network/__ipparse.c
@@ -0,0 +1,40 @@
+#include <string.h>
+#include <stdlib.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include "__dns.h"
+#include <stdio.h>
+
+int __ipparse(void *dest, int family, const char *s)
+{
+ unsigned char *d = dest;
+ unsigned long a[16] = { 0 };
+ const char *z;
+ int i;
+
+ if (family == AF_INET6) goto not_v4;
+
+ for (i=0; i<4 && *s; i++) {
+ a[i] = strtoul(s, (char **)&z, 0);
+ if (z==s || (*z && *z != '.')) goto not_v4;
+ s=z+1;
+ }
+ 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;
+ }
+ ((struct sockaddr_in *)d)->sin_family = AF_INET;
+ d = (void *)&((struct sockaddr_in *)d)->sin_addr;
+ for (i=0; i<4; i++) d[i] = a[i];
+ return 0;
+
+not_v4:
+ return -1;
+}
diff --git a/src/network/accept.c b/src/network/accept.c
new file mode 100644
index 00000000..83704096
--- /dev/null
+++ b/src/network/accept.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+int accept(int fd, struct sockaddr *addr, socklen_t *len)
+{
+ unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+ int ret;
+ CANCELPT_BEGIN;
+ ret = syscall2(__NR_socketcall, SYS_ACCEPT, (long)args);
+ CANCELPT_END;
+ return ret;
+}
diff --git a/src/network/bind.c b/src/network/bind.c
new file mode 100644
index 00000000..3bef382c
--- /dev/null
+++ b/src/network/bind.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int bind(int fd, const struct sockaddr *addr, socklen_t len)
+{
+ unsigned long args[] = { fd, (unsigned long)addr, len };
+ return syscall2(__NR_socketcall, SYS_BIND, (long)args);
+}
diff --git a/src/network/connect.c b/src/network/connect.c
new file mode 100644
index 00000000..6074122e
--- /dev/null
+++ b/src/network/connect.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+int connect(int fd, const struct sockaddr *addr, socklen_t len)
+{
+ unsigned long args[] = { fd, (unsigned long)addr, len };
+ int ret;
+ CANCELPT_BEGIN;
+ ret = syscall2(__NR_socketcall, SYS_CONNECT, (long)args);
+ CANCELPT_END;
+ return ret;
+}
diff --git a/src/network/dn_expand.c b/src/network/dn_expand.c
new file mode 100644
index 00000000..01b449bb
--- /dev/null
+++ b/src/network/dn_expand.c
@@ -0,0 +1,28 @@
+#include <resolv.h>
+#include <string.h>
+
+#define BITOP(a,b,op) \
+ ((a)[(size_t)(b)/(8*sizeof *(a))] op (size_t)1<<((size_t)(b)%(8*sizeof *(a))))
+
+int dn_expand(unsigned char *b, unsigned char *pz, unsigned char *p, unsigned char *s, int outlen)
+{
+ /* Remember jump destinations to detect loops and abort */
+ size_t seen[512/8/sizeof(size_t)] = { 0 };
+ unsigned char *sz = s + outlen;
+ if (pz-b > 512) return -1;
+ for (;;) {
+ if (p>=pz) return -1;
+ else if (*p&0xc0) {
+ int j = (p[0]&1) | p[1];
+ if (BITOP(seen, j, &)) return -1;
+ BITOP(seen, j, |=);
+ p = b + j;
+ } else if (*p) {
+ if (p+*p+1>=pz || s+*p>=sz) return -1;
+ memcpy(s, p+1, *p);
+ s += *p+1;
+ p += *p+1;
+ s[-1] = *p ? '.' : 0;
+ } else return 0;
+ }
+}
diff --git a/src/network/ent.c b/src/network/ent.c
new file mode 100644
index 00000000..4c2f24b5
--- /dev/null
+++ b/src/network/ent.c
@@ -0,0 +1,26 @@
+#include "libc.h"
+
+void sethostent(int x)
+{
+}
+
+void *gethostent()
+{
+ return 0;
+}
+
+void endhostent(void)
+{
+}
+
+weak_alias(sethostent, setnetent);
+weak_alias(gethostent, getnetent);
+weak_alias(endhostent, endnetent);
+
+weak_alias(sethostent, setservent);
+weak_alias(gethostent, getservent);
+weak_alias(endhostent, endservent);
+
+weak_alias(sethostent, setprotoent);
+weak_alias(gethostent, getprotoent);
+weak_alias(endhostent, endprotoent);
diff --git a/src/network/freeaddrinfo.c b/src/network/freeaddrinfo.c
new file mode 100644
index 00000000..df3798ae
--- /dev/null
+++ b/src/network/freeaddrinfo.c
@@ -0,0 +1,7 @@
+#include <stdlib.h>
+#include <netdb.h>
+
+void freeaddrinfo(struct addrinfo *p)
+{
+ free(p);
+}
diff --git a/src/network/gai_strerror.c b/src/network/gai_strerror.c
new file mode 100644
index 00000000..ea00bed7
--- /dev/null
+++ b/src/network/gai_strerror.c
@@ -0,0 +1,21 @@
+#include <netdb.h>
+
+static const char msgs[] =
+ "Invalid flags\0"
+ "Name does not resolve\0"
+ "Try again\0"
+ "Non-recoverable error\0"
+ "Unrecognized address family or invalid length\0"
+ "Unrecognized socket type\0"
+ "Unrecognized service\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++);
+ return *s ? s : s+1;
+}
diff --git a/src/network/getaddrinfo.c b/src/network/getaddrinfo.c
new file mode 100644
index 00000000..90e85f6a
--- /dev/null
+++ b/src/network/getaddrinfo.c
@@ -0,0 +1,224 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <string.h>
+#include <ctype.h>
+#include "__dns.h"
+#include "stdio_impl.h"
+
+static int is_valid(const char *host)
+{
+ const unsigned char *s;
+ if (strlen(host)-1 > 254 || mbstowcs(0, host, 0) > 255) return 0;
+ for (s=host; *s>=0x80 || *s=='.' || *s=='-' || isalnum(*s); s++);
+ return !*s;
+}
+
+#if 0
+static int have_af(int family)
+{
+ struct sockaddr_in6 sin6 = { .sin6_family = family };
+ socklen_t sl = family == AF_INET
+ ? sizeof(struct sockaddr_in)
+ : sizeof(struct sockaddr_in6);
+ int sock = socket(family, SOCK_STREAM, 0);
+ int have = !bind(sock, (void *)&sin6, sl);
+ close(sock);
+ return have;
+}
+#endif
+
+#include <stdlib.h>
+#include <netdb.h>
+
+union sa {
+ struct sockaddr_in sin;
+ struct sockaddr_in6 sin6;
+};
+
+struct aibuf {
+ struct addrinfo ai;
+ union sa sa;
+};
+
+/* Extra slots needed for storing canonical name */
+#define EXTRA ((256+sizeof(struct aibuf)-1)/sizeof(struct aibuf))
+
+int getaddrinfo(const char *host, const char *serv, const struct addrinfo *hint, struct addrinfo **res)
+{
+ int flags = hint ? hint->ai_flags : 0;
+ int family = hint ? hint->ai_family : AF_UNSPEC;
+ int type = hint ? hint->ai_socktype : 0;
+ int proto = hint ? hint->ai_protocol : 0;
+ unsigned long port = 0;
+ struct aibuf *buf;
+ union sa sa = {{0}};
+ unsigned char reply[1024];
+ int i, j;
+ //char hostbuf[256];
+ char line[512];
+ FILE *f, _f;
+ unsigned char _buf[64];
+ char *z;
+ int result;
+ int cnt;
+
+ if (host && strlen(host)>255) return EAI_NONAME;
+ if (serv && strlen(serv)>32) return EAI_SERVICE;
+
+ if (type && !proto)
+ proto = type==SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
+ if (!type && proto)
+ type = proto==IPPROTO_UDP ? SOCK_DGRAM : SOCK_STREAM;
+
+ if (serv) {
+ port = strtoul(serv, &z, 0);
+ if (!*z && port > 65535) return EAI_SERVICE;
+ if (!port) {
+ if (flags & AI_NUMERICSERV) return EAI_SERVICE;
+
+ //f = fopen("/etc/services", "rb");
+ return EAI_SERVICE;
+ }
+ port = htons(port);
+ }
+
+ if (!host) {
+ if (family == AF_UNSPEC) family = AF_INET;
+ buf = calloc(sizeof *buf, 1+EXTRA);
+ if (!buf) return EAI_MEMORY;
+ buf->ai.ai_protocol = proto;
+ buf->ai.ai_socktype = type;
+ buf->ai.ai_addr = (void *)&buf->sa;
+ buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+ buf->ai.ai_family = family;
+ buf->sa.sin.sin_family = family;
+ buf->sa.sin.sin_port = port;
+ if (!(flags & AI_PASSIVE)) {
+ if (family == AF_INET) {
+ 0[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=127;
+ 3[(uint8_t*)&buf->sa.sin.sin_addr.s_addr]=1;
+ } else buf[0].sa.sin6.sin6_addr.s6_addr[15] = 1;
+ }
+ *res = &buf->ai;
+ return 0;
+ }
+
+ /* Try as a numeric address */
+ if (__ipparse(&sa, family, host) >= 0) {
+ buf = calloc(sizeof *buf, 1+EXTRA);
+ if (!buf) return EAI_MEMORY;
+ family = sa.sin.sin_family;
+ buf->ai.ai_protocol = proto;
+ buf->ai.ai_socktype = type;
+ buf->ai.ai_addr = (void *)&buf->sa;
+ buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+ buf->ai.ai_family = family;
+ buf->sa = sa;
+ buf->sa.sin.sin_port = port;
+ *res = &buf->ai;
+ return 0;
+ }
+
+ if (flags & AI_NUMERICHOST) return EAI_NONAME;
+
+ f = __fopen_rb_ca("/etc/hosts", &_f, _buf, sizeof _buf);
+ if (f) while (fgets(line, sizeof line, f)) {
+ char *p;
+ size_t l = strlen(host);
+
+ if ((p=strchr(line, '#'))) *p++='\n', *p=0;
+ for(p=line+1; (p=strstr(p, host)) &&
+ (!isspace(p[-1]) || !isspace(p[l])); p++);
+ if (!p) continue;
+ __fclose_ca(f);
+
+ /* Isolate IP address to parse */
+ for (p=line; *p && !isspace(*p); p++);
+ *p++ = 0;
+ if (__ipparse(&sa, family, line) < 0) return EAI_NONAME;
+
+ /* Allocate and fill result buffer */
+ buf = calloc(sizeof *buf, 1+EXTRA);
+ if (!buf) return EAI_MEMORY;
+ family = sa.sin.sin_family;
+ buf->ai.ai_protocol = proto;
+ buf->ai.ai_socktype = type;
+ buf->ai.ai_addr = (void *)&buf->sa;
+ buf->ai.ai_addrlen = family==AF_INET6 ? sizeof sa.sin6 : sizeof sa.sin;
+ buf->ai.ai_family = family;
+ buf->sa = sa;
+ buf->sa.sin.sin_port = port;
+
+ /* Extract first name as canonical name */
+ for (; *p && isspace(*p); p++);
+ buf->ai.ai_canonname = (void *)(buf+1);
+ snprintf(buf->ai.ai_canonname, 256, "%s", p);
+ for (p=buf->ai.ai_canonname; *p && !isspace(*p); p++);
+ *p = 0;
+ if (!is_valid(buf->ai.ai_canonname))
+ buf->ai.ai_canonname = 0;
+
+ *res = &buf->ai;
+ return 0;
+ }
+ if (f) __fclose_ca(f);
+
+#if 0
+ f = __fopen_rb_ca("/etc/resolv.conf", &_f, _buf, sizeof _buf);
+ if (f) while (fgets(line, sizeof line, f)) {
+ if (!isspace(line[10]) || (strncmp(line, "search", 6)
+ && strncmp(line, "domain", 6))) continue;
+ }
+ if (f) __fclose_ca(f);
+#endif
+
+ /* Perform one or more DNS queries for host */
+ memset(reply, 0, sizeof reply);
+ result = __dns_query(reply, host, family, 0);
+ if (result < 0) return result;
+
+ cnt = __dns_count_addrs(reply, result);
+ if (cnt <= 0) return EAI_NONAME;
+
+ buf = calloc(sizeof *buf, cnt+EXTRA);
+ if (!buf) return EAI_MEMORY;
+
+ i = 0;
+ if (family != AF_INET6) {
+ j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply, RR_A, 0);
+ while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+ }
+ if (family != AF_INET) {
+ j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply, RR_AAAA, 0);
+ while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+ }
+ if (result>1) {
+ j = __dns_get_rr(&buf[i].sa.sin.sin_addr, sizeof *buf, 4, cnt-i, reply+512, RR_A, 0);
+ while (j--) buf[i++].sa.sin.sin_family = AF_INET;
+ j = __dns_get_rr(&buf[i].sa.sin6.sin6_addr, sizeof *buf, 16, cnt-i, reply+512, RR_AAAA, 0);
+ while (j--) buf[i++].sa.sin.sin_family = AF_INET6;
+ }
+
+ if (__dns_get_rr((void *)&buf[cnt], 0, 256, 1, reply, RR_CNAME, 1) < 0)
+ strcpy((void *)&buf[cnt], host);
+
+ for (i=0; i<cnt; i++) {
+ buf[i].ai.ai_protocol = proto;
+ buf[i].ai.ai_socktype = type;
+ buf[i].ai.ai_addr = (void *)&buf[i].sa;
+ buf[i].ai.ai_addrlen = buf[i].sa.sin.sin_family==AF_INET6
+ ? sizeof sa.sin6 : sizeof sa.sin;
+ buf[i].ai.ai_family = buf[i].sa.sin.sin_family;
+ buf[i].sa.sin.sin_port = port;
+ buf[i].ai.ai_next = &buf[i+1].ai;
+ buf[i].ai.ai_canonname = (void *)&buf[cnt];
+ }
+ buf[cnt-1].ai.ai_next = 0;
+ *res = &buf->ai;
+
+ return 0;
+}
diff --git a/src/network/gethostbyaddr.c b/src/network/gethostbyaddr.c
new file mode 100644
index 00000000..51e1c569
--- /dev/null
+++ b/src/network/gethostbyaddr.c
@@ -0,0 +1,15 @@
+#define _GNU_SOURCE
+
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyaddr(const void *a, socklen_t l, int af)
+{
+ static struct hostent h;
+ static long buf[512/sizeof(long)];
+ struct hostent *res;
+ if (gethostbyaddr_r(a, l, af, &h,
+ (void *)buf, sizeof buf, &res, &h_errno)) return 0;
+ return &h;
+}
diff --git a/src/network/gethostbyaddr_r.c b/src/network/gethostbyaddr_r.c
new file mode 100644
index 00000000..cdb1d503
--- /dev/null
+++ b/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;
+
+ /* 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 -1;
+ }
+
+ /* 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) {
+ errno = ERANGE;
+ return -1;
+ }
+ 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 -1;
+ case EAI_OVERFLOW:
+ errno = ERANGE;
+ default:
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ case EAI_FAIL:
+ *err = NO_RECOVERY;
+ return -1;
+ case 0:
+ break;
+ }
+
+ h->h_addrtype = af;
+ h->h_name = h->h_aliases[0];
+ *res = h;
+ return 0;
+}
diff --git a/src/network/gethostbyname.c b/src/network/gethostbyname.c
new file mode 100644
index 00000000..5088a51e
--- /dev/null
+++ b/src/network/gethostbyname.c
@@ -0,0 +1,63 @@
+#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);
+}
+
+#if 0
+struct hostent *gethostbyname(const char *name)
+{
+ static struct hostent h;
+ static char *h_aliases[3];
+ static char h_canon[256];
+ static char *h_addr_list[10];
+ static char h_addr_data[10][4];
+ static const struct addrinfo hint = {
+ .ai_family = AF_INET, .ai_flags = AI_CANONNAME
+ };
+ struct addrinfo *ai, *p;
+ int i;
+
+ switch (getaddrinfo(name, 0, &hint, &ai)) {
+ case EAI_NONAME:
+ h_errno = HOST_NOT_FOUND;
+ break;
+ case EAI_AGAIN:
+ h_errno = TRY_AGAIN;
+ break;
+ case EAI_FAIL:
+ h_errno = NO_RECOVERY;
+ break;
+ default:
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ h_errno = NO_DATA;
+ break;
+ case 0:
+ break;
+ }
+
+ strcpy(h_canon, ai->ai_canonname);
+ h.h_name = h_canon;
+ h.h_aliases = h_aliases;
+ h.h_aliases[0] = h_canon;
+ h.h_aliases[1] = strcmp(h_canon, name) ? (char *)name : 0;
+ h.h_length = 4;
+ h.h_addr_list = h_addr_list;
+ for (i=0, p=ai; i<sizeof h_addr_data/4 && p; i++, p=p->ai_next) {
+ h.h_addr_list[i] = h_addr_data[i];
+ memcpy(h.h_addr_list[i],
+ &((struct sockaddr_in *)p->ai_addr)->sin_addr, 4);
+ }
+ h.h_addr_list[i] = 0;
+ h.h_addrtype = AF_INET;
+ freeaddrinfo(ai);
+ return &h;
+}
+#endif
diff --git a/src/network/gethostbyname2.c b/src/network/gethostbyname2.c
new file mode 100644
index 00000000..9fbe2647
--- /dev/null
+++ b/src/network/gethostbyname2.c
@@ -0,0 +1,16 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+
+struct hostent *gethostbyname2(const char *name, int af)
+{
+ static struct hostent h;
+ static long buf[512/sizeof(long)];
+ struct hostent *res;
+ if (gethostbyname2_r(name, af, &h,
+ (void *)buf, sizeof buf, &res, &h_errno)) return 0;
+ return &h;
+}
diff --git a/src/network/gethostbyname2_r.c b/src/network/gethostbyname2_r.c
new file mode 100644
index 00000000..c2ed75b4
--- /dev/null
+++ b/src/network/gethostbyname2_r.c
@@ -0,0 +1,99 @@
+#define _GNU_SOURCE
+
+#include <sys/socket.h>
+#include <netdb.h>
+#include <string.h>
+#include <netinet/in.h>
+#include <errno.h>
+#include <inttypes.h>
+
+int gethostbyname2_r(const char *name, int af,
+ struct hostent *h, char *buf, size_t buflen,
+ struct hostent **res, int *err)
+{
+ struct addrinfo hint = {
+ .ai_family = af==AF_INET6 ? af : AF_INET,
+ .ai_flags = AI_CANONNAME
+ };
+ struct addrinfo *ai, *p;
+ int i;
+ size_t need;
+ const char *canon;
+
+ af = hint.ai_family;
+
+ /* Align buffer */
+ i = (uintptr_t)buf & sizeof(char *)-1;
+ if (i) {
+ if (buflen < sizeof(char *)-i) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += sizeof(char *)-i;
+ buflen -= sizeof(char *)-i;
+ }
+
+ getaddrinfo(name, 0, &hint, &ai);
+ switch (getaddrinfo(name, 0, &hint, &ai)) {
+ case EAI_NONAME:
+ *err = HOST_NOT_FOUND;
+ return -1;
+ case EAI_AGAIN:
+ *err = TRY_AGAIN;
+ return -1;
+ default:
+ case EAI_MEMORY:
+ case EAI_SYSTEM:
+ case EAI_FAIL:
+ *err = NO_RECOVERY;
+ return -1;
+ case 0:
+ break;
+ }
+
+ h->h_addrtype = af;
+ h->h_length = af==AF_INET6 ? 16 : 4;
+
+ canon = ai->ai_canonname ? ai->ai_canonname : name;
+ need = 4*sizeof(char *);
+ for (i=0, p=ai; p; i++, p=p->ai_next)
+ need += sizeof(char *) + h->h_length;
+ need += strlen(name)+1;
+ need += strlen(canon)+1;
+
+ if (need > buflen) {
+ freeaddrinfo(ai);
+ errno = ERANGE;
+ return -1;
+ }
+
+ h->h_aliases = (void *)buf;
+ buf += 3*sizeof(char *);
+ h->h_addr_list = (void *)buf;
+ buf += (i+1)*sizeof(char *);
+
+ 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;
+
+ for (i=0, p=ai; p; i++, p=p->ai_next) {
+ h->h_addr_list[i] = (void *)buf;
+ buf += h->h_length;
+ memcpy(h->h_addr_list[i],
+ &((struct sockaddr_in *)p->ai_addr)->sin_addr,
+ h->h_length);
+ }
+ h->h_addr_list[i] = 0;
+
+ *res = h;
+ freeaddrinfo(ai);
+ return 0;
+}
diff --git a/src/network/gethostbyname_r.c b/src/network/gethostbyname_r.c
new file mode 100644
index 00000000..cd872541
--- /dev/null
+++ b/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/src/network/getnameinfo.c b/src/network/getnameinfo.c
new file mode 100644
index 00000000..0763ca88
--- /dev/null
+++ b/src/network/getnameinfo.c
@@ -0,0 +1,54 @@
+#include <netdb.h>
+#include <limits.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "__dns.h"
+
+int getnameinfo(const struct sockaddr *sa, socklen_t sl,
+ char *node, socklen_t nodelen,
+ char *serv, socklen_t servlen,
+ int flags)
+{
+ char buf[256];
+ unsigned char reply[512];
+ int af = sa->sa_family;
+ unsigned char *a;
+
+ switch (af) {
+ case AF_INET:
+ a = (void *)&((struct sockaddr_in *)sa)->sin_addr;
+ if (sl != sizeof(struct sockaddr_in)) return EAI_FAMILY;
+ break;
+ case AF_INET6:
+ a = (void *)&((struct sockaddr_in6 *)sa)->sin6_addr;
+ if (sl != sizeof(struct sockaddr_in6)) return EAI_FAMILY;
+ break;
+ default:
+ return EAI_FAMILY;
+ }
+
+ if (node && nodelen) {
+ if ((flags & NI_NUMERICHOST)
+ || __dns_query(reply, a, af, 1) <= 0
+ || __dns_get_rr(buf, 0, 256, 1, reply, RR_PTR, 1) <= 0)
+ {
+ if (flags & NI_NAMEREQD) return EAI_NONAME;
+ inet_ntop(af, a, buf, sizeof buf);
+ }
+ if (strlen(buf) >= nodelen) return EAI_OVERFLOW;
+ strcpy(node, buf);
+ }
+
+ if (serv && servlen) {
+ if (snprintf(buf, sizeof buf, "%d",
+ ntohs(((struct sockaddr_in *)sa)->sin_port))>=servlen)
+ return EAI_OVERFLOW;
+ strcpy(serv, buf);
+ }
+
+ return 0;
+}
diff --git a/src/network/getpeername.c b/src/network/getpeername.c
new file mode 100644
index 00000000..7ecbe375
--- /dev/null
+++ b/src/network/getpeername.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getpeername(int fd, struct sockaddr *addr, socklen_t *len)
+{
+ unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+ return syscall2(__NR_socketcall, SYS_GETPEERNAME, (long)args);
+}
diff --git a/src/network/getservbyname.c b/src/network/getservbyname.c
new file mode 100644
index 00000000..0b00ce11
--- /dev/null
+++ b/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 long buf[32/sizeof(long)];
+ struct servent *res;
+ if (getservbyname_r(name, prots, &se, (void *)buf, sizeof buf, &res))
+ return 0;
+ return &se;
+}
diff --git a/src/network/getservbyname_r.c b/src/network/getservbyname_r.c
new file mode 100644
index 00000000..5c025150
--- /dev/null
+++ b/src/network/getservbyname_r.c
@@ -0,0 +1,41 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.h>
+
+int getservbyname_r(const char *name, const char *prots,
+ struct servent *se, char *buf, size_t buflen, struct servent **res)
+{
+ struct addrinfo *ai, hint = { .ai_family = AF_INET };
+ int i;
+
+ /* Align buffer */
+ i = (uintptr_t)buf & sizeof(char *)-1;
+ if (!i) i = sizeof(char *);
+ if (buflen < 3*sizeof(char *)-i) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += sizeof(char *)-i;
+ buflen -= sizeof(char *)-i;
+
+ if (!strcmp(prots, "tcp")) hint.ai_protocol = IPPROTO_TCP;
+ else if (!strcmp(prots, "udp")) hint.ai_protocol = IPPROTO_UDP;
+ else return -1;
+
+ if (getaddrinfo(0, name, &hint, &ai) < 0) return -1;
+
+ 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 = ((struct sockaddr_in *)ai->ai_addr)->sin_port;
+ se->s_proto = (char *)prots;
+
+ freeaddrinfo(ai);
+ *res = se;
+ return 0;
+}
diff --git a/src/network/getservbyport.c b/src/network/getservbyport.c
new file mode 100644
index 00000000..c9ecbb11
--- /dev/null
+++ b/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/src/network/getservbyport_r.c b/src/network/getservbyport_r.c
new file mode 100644
index 00000000..004a6168
--- /dev/null
+++ b/src/network/getservbyport_r.c
@@ -0,0 +1,43 @@
+#define _GNU_SOURCE
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+#include <inttypes.h>
+#include <errno.h>
+#include <string.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,
+ };
+
+ /* Align buffer */
+ i = (uintptr_t)buf & sizeof(char *)-1;
+ if (!i) i = sizeof(char *);
+ if (buflen < 3*sizeof(char *)-i) {
+ errno = ERANGE;
+ return -1;
+ }
+ buf += sizeof(char *)-i;
+ buflen -= sizeof(char *)-i;
+
+ if (strcmp(prots, "tcp") && strcmp(prots, "udp")) return -1;
+
+ 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;
+
+ if (getnameinfo((void *)&sin, sizeof sin, 0, 0, buf, buflen,
+ strcmp(prots, "udp") ? 0 : NI_DGRAM) < 0) return -1;
+
+ *res = se;
+ return 0;
+}
diff --git a/src/network/getsockname.c b/src/network/getsockname.c
new file mode 100644
index 00000000..4b1002f8
--- /dev/null
+++ b/src/network/getsockname.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getsockname(int fd, struct sockaddr *addr, socklen_t *len)
+{
+ unsigned long args[] = { fd, (unsigned long)addr, (unsigned long)len };
+ return syscall2(__NR_socketcall, SYS_GETSOCKNAME, (long)args);
+}
diff --git a/src/network/getsockopt.c b/src/network/getsockopt.c
new file mode 100644
index 00000000..8c818863
--- /dev/null
+++ b/src/network/getsockopt.c
@@ -0,0 +1,13 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int getsockopt(int fd, int level, int optname, void *optval, socklen_t *optlen)
+{
+ unsigned long args[] = {
+ fd, level, optname,
+ (unsigned long)optval,
+ (unsigned long)optlen
+ };
+ return syscall2(__NR_socketcall, SYS_GETSOCKOPT, (long)args);
+}
diff --git a/src/network/h_errno.c b/src/network/h_errno.c
new file mode 100644
index 00000000..73ead046
--- /dev/null
+++ b/src/network/h_errno.c
@@ -0,0 +1 @@
+int h_errno;
diff --git a/src/network/hstrerror.c b/src/network/hstrerror.c
new file mode 100644
index 00000000..b7a6ab6c
--- /dev/null
+++ b/src/network/hstrerror.c
@@ -0,0 +1,16 @@
+#define _GNU_SOURCE
+#include <netdb.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++);
+ return *s ? s : s+1;
+}
diff --git a/src/network/htonl.c b/src/network/htonl.c
new file mode 100644
index 00000000..b21dace0
--- /dev/null
+++ b/src/network/htonl.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint32_t htonl(uint32_t n)
+{
+ union {
+ uint8_t b[4];
+ uint32_t i;
+ } u = { { n>>24, n>>16, n>>8, n } };
+ return u.i;
+}
diff --git a/src/network/htons.c b/src/network/htons.c
new file mode 100644
index 00000000..522504a5
--- /dev/null
+++ b/src/network/htons.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint16_t htons(uint16_t n)
+{
+ union {
+ uint8_t b[2];
+ uint16_t s;
+ } u = { { n>>8, n } };
+ return u.s;
+}
diff --git a/src/network/in6addr_any.c b/src/network/in6addr_any.c
new file mode 100644
index 00000000..995387fa
--- /dev/null
+++ b/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/src/network/in6addr_loopback.c b/src/network/in6addr_loopback.c
new file mode 100644
index 00000000..b96005b8
--- /dev/null
+++ b/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/src/network/inet_addr.c b/src/network/inet_addr.c
new file mode 100644
index 00000000..84137281
--- /dev/null
+++ b/src/network/inet_addr.c
@@ -0,0 +1,11 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include "__dns.h"
+
+in_addr_t inet_addr(const char *p)
+{
+ struct sockaddr_in sin;
+ if (__ipparse(&sin, AF_INET, p)) return -1;
+ return sin.sin_addr.s_addr;
+}
diff --git a/src/network/inet_aton.c b/src/network/inet_aton.c
new file mode 100644
index 00000000..ea4ee165
--- /dev/null
+++ b/src/network/inet_aton.c
@@ -0,0 +1,7 @@
+#include <sys/socket.h>
+#include <arpa/inet.h>
+
+int inet_aton(const char *cp, struct in_addr *inp)
+{
+ return inet_pton(AF_INET, cp, (void *)inp) > 0;
+}
diff --git a/src/network/inet_ntoa.c b/src/network/inet_ntoa.c
new file mode 100644
index 00000000..71411e0b
--- /dev/null
+++ b/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/src/network/inet_ntop.c b/src/network/inet_ntop.c
new file mode 100644
index 00000000..3e8a6db0
--- /dev/null
+++ b/src/network/inet_ntop.c
@@ -0,0 +1,48 @@
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+const char *inet_ntop(int af, const void *a0, char *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:
+ memset(buf, 'x', sizeof buf);
+ buf[sizeof buf-1]=0;
+ snprintf(buf, sizeof buf,
+ "%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x:%.0x%x",
+ a[0],a[1],a[2],a[3],a[4],a[5],a[6],a[7],
+ a[8],a[9],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>2) {
+ buf[best] = buf[best+1] = ':';
+ strcpy(buf+best+2, buf+best+max);
+ }
+ if (strlen(buf) < l) {
+ strcpy(s, buf);
+ return s;
+ }
+ break;
+ default:
+ errno = EAFNOSUPPORT;
+ return 0;
+ }
+ errno = ENOSPC;
+ return 0;
+}
diff --git a/src/network/inet_pton.c b/src/network/inet_pton.c
new file mode 100644
index 00000000..349c4025
--- /dev/null
+++ b/src/network/inet_pton.c
@@ -0,0 +1,31 @@
+#include <sys/socket.h>
+#include <netdb.h>
+#include <arpa/inet.h>
+#include <stdlib.h>
+#include <ctype.h>
+#include <errno.h>
+#include "__dns.h"
+
+int inet_pton(int af, const char *s, void *a0)
+{
+ unsigned char *a = a0;
+ const char *z;
+ unsigned long x;
+ int i;
+
+ /* Reimplement this because inet_pton cannot accept special v4 forms */
+ if (af==AF_INET) {
+ for (i=0; i<4 && *s; i++) {
+ a[i] = x = strtoul(s, (char **)&z, 10);
+ if (!isdigit(*s) || z==s || (*z && *z != '.') || x>255)
+ return 0;
+ s=z+1;
+ }
+ return 0;
+ } else if (af==AF_INET6) {
+ return !__ipparse(a, AF_INET6, s);
+ }
+
+ errno = EAFNOSUPPORT;
+ return 0;
+}
diff --git a/src/network/listen.c b/src/network/listen.c
new file mode 100644
index 00000000..7c8c1a8a
--- /dev/null
+++ b/src/network/listen.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int listen(int fd, int backlog)
+{
+ unsigned long args[] = { fd, backlog };
+ return syscall2(__NR_socketcall, SYS_LISTEN, (long)args);
+}
diff --git a/src/network/ntohl.c b/src/network/ntohl.c
new file mode 100644
index 00000000..64379196
--- /dev/null
+++ b/src/network/ntohl.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint32_t ntohl(uint32_t n)
+{
+ union {
+ uint32_t i;
+ uint8_t b[4];
+ } u = { n };
+ return (u.b[0]<<24) | (u.b[1]<<16) | (u.b[2]<<8) | u.b[3];
+}
diff --git a/src/network/ntohs.c b/src/network/ntohs.c
new file mode 100644
index 00000000..3544a479
--- /dev/null
+++ b/src/network/ntohs.c
@@ -0,0 +1,10 @@
+#include <netinet/in.h>
+
+uint16_t ntohs(uint16_t n)
+{
+ union {
+ uint16_t s;
+ uint8_t b[2];
+ } u = { n };
+ return (u.b[0]<<8) | u.b[1];
+}
diff --git a/src/network/proto.c b/src/network/proto.c
new file mode 100644
index 00000000..8c25c53a
--- /dev/null
+++ b/src/network/proto.c
@@ -0,0 +1,58 @@
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+/* do we really need all these?? */
+
+static int idx;
+static const unsigned char protos[][6] = {
+ "\000ip",
+ "\001icmp",
+ "\002igmp",
+ "\003ggp",
+ "\006tcp",
+ "\014pup",
+ "\021udp",
+ "\026idp",
+ "\377raw"
+ "\0\0"
+};
+
+void endprotoent(void)
+{
+ idx = 0;
+}
+
+void setprotoent(int stayopen)
+{
+ idx = 0;
+}
+
+struct protoent *getprotoent(void)
+{
+ static struct protoent p;
+ static const char *aliases;
+ if (!protos[idx][1]) return NULL;
+ p.p_proto = protos[idx][0];
+ p.p_name = (char *)protos[idx++]+1;
+ p.p_aliases = (char **)&aliases;
+ 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/src/network/recv.c b/src/network/recv.c
new file mode 100644
index 00000000..521a4b19
--- /dev/null
+++ b/src/network/recv.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recv(int fd, void *buf, size_t len, int flags)
+{
+ unsigned long args[] = { fd, (unsigned long)buf, len, flags };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_RECV, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/recvfrom.c b/src/network/recvfrom.c
new file mode 100644
index 00000000..df50114b
--- /dev/null
+++ b/src/network/recvfrom.c
@@ -0,0 +1,17 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr *addr, socklen_t *alen)
+{
+ unsigned long args[] = {
+ fd, (unsigned long)buf, len, flags,
+ (unsigned long)addr, (unsigned long)alen
+ };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_RECVFROM, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/recvmsg.c b/src/network/recvmsg.c
new file mode 100644
index 00000000..ead16f9c
--- /dev/null
+++ b/src/network/recvmsg.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t recvmsg(int fd, struct msghdr *msg, int flags)
+{
+ unsigned long args[] = { fd, (unsigned long)msg, flags };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_RECVMSG, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/res_init.c b/src/network/res_init.c
new file mode 100644
index 00000000..cbd5b155
--- /dev/null
+++ b/src/network/res_init.c
@@ -0,0 +1,4 @@
+int res_init()
+{
+ return 0;
+}
diff --git a/src/network/res_query.c b/src/network/res_query.c
new file mode 100644
index 00000000..4ebeb102
--- /dev/null
+++ b/src/network/res_query.c
@@ -0,0 +1,20 @@
+#include <netdb.h>
+#include "__dns.h"
+
+int res_query(const char *name, int class, int type, unsigned char *dest, int len)
+{
+ if (class != 1 || len < 512)
+ return -1;
+ switch(__dns_doqueries(dest, name, &type, 1)) {
+ case EAI_NONAME:
+ h_errno = HOST_NOT_FOUND;
+ return -1;
+ case EAI_AGAIN:
+ h_errno = TRY_AGAIN;
+ return -1;
+ case EAI_FAIL:
+ h_errno = NO_RECOVERY;
+ return -1;
+ }
+ return 512;
+}
diff --git a/src/network/send.c b/src/network/send.c
new file mode 100644
index 00000000..d72fb03c
--- /dev/null
+++ b/src/network/send.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t send(int fd, const void *buf, size_t len, int flags)
+{
+ unsigned long args[] = { fd, (unsigned long)buf, len, flags };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_SEND, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/sendmsg.c b/src/network/sendmsg.c
new file mode 100644
index 00000000..ea2fe482
--- /dev/null
+++ b/src/network/sendmsg.c
@@ -0,0 +1,14 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t sendmsg(int fd, const struct msghdr *msg, int flags)
+{
+ unsigned long args[] = { fd, (unsigned long)msg, flags };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_SENDMSG, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/sendto.c b/src/network/sendto.c
new file mode 100644
index 00000000..5d224b0b
--- /dev/null
+++ b/src/network/sendto.c
@@ -0,0 +1,17 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+#include "libc.h"
+
+ssize_t sendto(int fd, const void *buf, size_t len, int flags, const struct sockaddr *addr, socklen_t alen)
+{
+ unsigned long args[] = {
+ fd, (unsigned long)buf, len, flags,
+ (unsigned long)addr, alen
+ };
+ ssize_t r;
+ CANCELPT_BEGIN;
+ r = syscall2(__NR_socketcall, SYS_SENDTO, (long)args);
+ CANCELPT_END;
+ return r;
+}
diff --git a/src/network/serv.c b/src/network/serv.c
new file mode 100644
index 00000000..5ade6ad1
--- /dev/null
+++ b/src/network/serv.c
@@ -0,0 +1,16 @@
+#include <netdb.h>
+#include <stdio.h>
+#include <string.h>
+
+void endservent(void)
+{
+}
+
+void setservent(int stayopen)
+{
+}
+
+struct servent *getservent(void)
+{
+ return 0;
+}
diff --git a/src/network/setsockopt.c b/src/network/setsockopt.c
new file mode 100644
index 00000000..b50303b8
--- /dev/null
+++ b/src/network/setsockopt.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int setsockopt(int fd, int level, int optname, const void *optval, socklen_t optlen)
+{
+ unsigned long args[] = { fd, level, optname, (unsigned long)optval, optlen };
+ return syscall2(__NR_socketcall, SYS_SETSOCKOPT, (long)args);
+}
diff --git a/src/network/shutdown.c b/src/network/shutdown.c
new file mode 100644
index 00000000..91950c8a
--- /dev/null
+++ b/src/network/shutdown.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int shutdown(int fd, int how)
+{
+ unsigned long args[] = { fd, how };
+ return syscall2(__NR_socketcall, SYS_SHUTDOWN, (long)args);
+}
diff --git a/src/network/sockatmark.c b/src/network/sockatmark.c
new file mode 100644
index 00000000..5328a855
--- /dev/null
+++ b/src/network/sockatmark.c
@@ -0,0 +1,11 @@
+#include <sys/socket.h>
+#include <sys/ioctl.h>
+#include "socketcall.h"
+
+int sockatmark(int s)
+{
+ int ret;
+ if (ioctl(s, SIOCATMARK, &ret) < 0)
+ return -1;
+ return ret;
+}
diff --git a/src/network/socket.c b/src/network/socket.c
new file mode 100644
index 00000000..afaeb411
--- /dev/null
+++ b/src/network/socket.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int socket(int domain, int type, int protocol)
+{
+ unsigned long args[] = { domain, type, protocol };
+ return syscall2(__NR_socketcall, SYS_SOCKET, (long)args);
+}
diff --git a/src/network/socketcall.h b/src/network/socketcall.h
new file mode 100644
index 00000000..9ae98587
--- /dev/null
+++ b/src/network/socketcall.h
@@ -0,0 +1,24 @@
+#define SYS_SOCKET 1
+#define SYS_BIND 2
+#define SYS_CONNECT 3
+#define SYS_LISTEN 4
+#define SYS_ACCEPT 5
+#define SYS_GETSOCKNAME 6
+#define SYS_GETPEERNAME 7
+#define SYS_SOCKETPAIR 8
+#define SYS_SEND 9
+#define SYS_RECV 10
+#define SYS_SENDTO 11
+#define SYS_RECVFROM 12
+#define SYS_SHUTDOWN 13
+#define SYS_SETSOCKOPT 14
+#define SYS_GETSOCKOPT 15
+#define SYS_SENDMSG 16
+#define SYS_RECVMSG 17
+
+#define FIOSETOWN 0x8901
+#define SIOCSPGRP 0x8902
+#define FIOGETOWN 0x8903
+#define SIOCGPGRP 0x8904
+#define SIOCATMARK 0x8905
+#define SIOCGSTAMP 0x8906
diff --git a/src/network/socketpair.c b/src/network/socketpair.c
new file mode 100644
index 00000000..65a47fd9
--- /dev/null
+++ b/src/network/socketpair.c
@@ -0,0 +1,9 @@
+#include <sys/socket.h>
+#include "syscall.h"
+#include "socketcall.h"
+
+int socketpair(int domain, int type, int protocol, int fd[2])
+{
+ unsigned long args[] = { domain, type, protocol, (unsigned long)fd };
+ return syscall2(__NR_socketcall, SYS_SOCKETPAIR, (long)args);
+}