summaryrefslogtreecommitdiff
path: root/sys/src/ape
diff options
context:
space:
mode:
authorcinap_lenrek <cinap_lenrek@gmx.de>2013-03-31 18:52:45 +0200
committercinap_lenrek <cinap_lenrek@gmx.de>2013-03-31 18:52:45 +0200
commitb6dc4ba5a44a2ed2a68266598ceb28b7a7d51af2 (patch)
treeb2af773db48a3606bd078055db925dbba6d4ffaa /sys/src/ape
parent9c7e1db701e0e80b42bb5990e2f6839d712bb984 (diff)
ape: initial IPv6 support, inet_pton()/inet_ntop(), getaddrinfo()/getnameinfo()
Diffstat (limited to 'sys/src/ape')
-rw-r--r--sys/src/ape/lib/bsd/_sock_ingetaddr.c72
-rw-r--r--sys/src/ape/lib/bsd/_sock_ipattr.c2
-rw-r--r--sys/src/ape/lib/bsd/_sock_srv.c2
-rw-r--r--sys/src/ape/lib/bsd/accept.c30
-rw-r--r--sys/src/ape/lib/bsd/bind.c16
-rw-r--r--sys/src/ape/lib/bsd/connect.c36
-rw-r--r--sys/src/ape/lib/bsd/gai_strerror.c34
-rw-r--r--sys/src/ape/lib/bsd/getaddrinfo.c217
-rw-r--r--sys/src/ape/lib/bsd/gethostbyname.c25
-rw-r--r--sys/src/ape/lib/bsd/getnameinfo.c126
-rw-r--r--sys/src/ape/lib/bsd/getpeername.c8
-rw-r--r--sys/src/ape/lib/bsd/getprotobyname.c3
-rw-r--r--sys/src/ape/lib/bsd/getservbyname.c6
-rw-r--r--sys/src/ape/lib/bsd/getsockname.c8
-rw-r--r--sys/src/ape/lib/bsd/in6_addr.c4
-rw-r--r--sys/src/ape/lib/bsd/inet_ntop.c54
-rw-r--r--sys/src/ape/lib/bsd/inet_pton.c79
-rw-r--r--sys/src/ape/lib/bsd/listen.c15
-rw-r--r--sys/src/ape/lib/bsd/mkfile8
-rw-r--r--sys/src/ape/lib/bsd/priv.h7
-rw-r--r--sys/src/ape/lib/bsd/socket.c13
-rw-r--r--sys/src/ape/lib/bsd/writev.c10
22 files changed, 668 insertions, 107 deletions
diff --git a/sys/src/ape/lib/bsd/_sock_ingetaddr.c b/sys/src/ape/lib/bsd/_sock_ingetaddr.c
index 603eb9c78..c8304f0cf 100644
--- a/sys/src/ape/lib/bsd/_sock_ingetaddr.c
+++ b/sys/src/ape/lib/bsd/_sock_ingetaddr.c
@@ -15,17 +15,74 @@
#include "priv.h"
+void*
+_sock_inip(struct sockaddr *a)
+{
+ switch(a->sa_family){
+ case AF_INET:
+ return &((struct sockaddr_in*)a)->sin_addr;
+ case AF_INET6:
+ return &((struct sockaddr_in6*)a)->sin6_addr;
+ }
+ return 0;
+}
+
+int
+_sock_inport(struct sockaddr *a)
+{
+ switch(a->sa_family){
+ case AF_INET:
+ return ntohs(((struct sockaddr_in*)a)->sin_port);
+ case AF_INET6:
+ return ntohs(((struct sockaddr_in6*)a)->sin6_port);
+ }
+ return 0;
+}
+
+int
+_sock_inaddr(int af, char *ip, char *port, void *a, int *alen)
+{
+ int len;
+
+ len = 0;
+ if(af == AF_INET){
+ struct sockaddr_in *in = a;
+
+ len = sizeof(*in);
+ memset(in, 0, len);
+ in->sin_family = af;
+ if(port != 0 && *port != 0)
+ in->sin_port = htons(atoi(port));
+ if(ip != 0 && *ip != 0)
+ inet_pton(af, ip, &in->sin_addr);
+ } else if(af == AF_INET6){
+ struct sockaddr_in6 *in = a;
+
+ len = sizeof(*in);
+ memset(in, 0, len);
+ in->sin6_family = af;
+ if(port != 0 && *port != 0)
+ in->sin6_port = htons(atoi(port));
+ if(ip != 0 && *ip != 0)
+ inet_pton(af, ip, &in->sin6_addr);
+ }
+ if(alen != 0)
+ *alen = len;
+ return len;
+}
+
void
-_sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
+_sock_ingetaddr(Rock *r, void *a, int *alen, char *file)
{
+ char name[Ctlsize], *p;
int n, fd;
- char *p;
- char name[Ctlsize];
+ if(r->domain != PF_INET && r->domain != PF_INET6)
+ return;
/* get remote address */
strcpy(name, r->ctl);
p = strrchr(name, '/');
- strcpy(p+1, a);
+ strcpy(p+1, file);
fd = open(name, O_RDONLY);
if(fd >= 0){
n = read(fd, name, sizeof(name)-1);
@@ -34,14 +91,9 @@ _sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
p = strchr(name, '!');
if(p){
*p++ = 0;
- ip->sin_family = AF_INET;
- ip->sin_port = htons(atoi(p));
- ip->sin_addr.s_addr = inet_addr(name);
- if(alen)
- *alen = sizeof(struct sockaddr_in);
+ _sock_inaddr(r->domain, name, p, a, alen);
}
}
close(fd);
}
-
}
diff --git a/sys/src/ape/lib/bsd/_sock_ipattr.c b/sys/src/ape/lib/bsd/_sock_ipattr.c
index b9b0c8ac8..882ae1663 100644
--- a/sys/src/ape/lib/bsd/_sock_ipattr.c
+++ b/sys/src/ape/lib/bsd/_sock_ipattr.c
@@ -27,6 +27,8 @@ _sock_ipattr(char *name)
alpha = 1;
else if(*p == '.')
dot = 1;
+ else if(*p == ':')
+ return Tip;
else
return Tsys;
}
diff --git a/sys/src/ape/lib/bsd/_sock_srv.c b/sys/src/ape/lib/bsd/_sock_srv.c
index 1f2988d03..22346d3c4 100644
--- a/sys/src/ape/lib/bsd/_sock_srv.c
+++ b/sys/src/ape/lib/bsd/_sock_srv.c
@@ -44,12 +44,10 @@ _sock_srv(char *path, int fd)
sfd = creat(msg, 0666);
if(sfd < 0){
close(fd);
- _syserrno();
return -1;
}
snprintf(msg, sizeof msg, "%d", fd);
if(write(sfd, msg, strlen(msg)) < 0){
- _syserrno();
close(sfd);
close(fd);
return -1;
diff --git a/sys/src/ape/lib/bsd/accept.c b/sys/src/ape/lib/bsd/accept.c
index 483e4c6ed..4f6203652 100644
--- a/sys/src/ape/lib/bsd/accept.c
+++ b/sys/src/ape/lib/bsd/accept.c
@@ -20,7 +20,6 @@ accept(int fd, void *a, int *alen)
{
int n, nfd, cfd;
Rock *r, *nr;
- struct sockaddr_in *ip;
char name[Ctlsize];
char file[8+Ctlsize+1];
char *p, *net;
@@ -33,6 +32,7 @@ accept(int fd, void *a, int *alen)
switch(r->domain){
case PF_INET:
+ case PF_INET6:
switch(r->stype){
case SOCK_DGRAM:
net = "udp";
@@ -40,41 +40,35 @@ accept(int fd, void *a, int *alen)
case SOCK_STREAM:
net = "tcp";
break;
+ case SOCK_RDM:
+ net = "il";
+ break;
}
/* get control file name from listener process */
n = read(fd, name, sizeof(name)-1);
- if(n <= 0){
- _syserrno();
+ if(n <= 0)
return -1;
- }
name[n] = 0;
cfd = open(name, O_RDWR);
- if(cfd < 0){
- _syserrno();
+ if(cfd < 0)
return -1;
- }
nfd = _sock_data(cfd, net, r->domain, r->stype, r->protocol, &nr);
- if(nfd < 0){
- _syserrno();
+ if(nfd < 0)
return -1;
- }
if(write(fd, "OK", 2) < 0){
close(nfd);
- _syserrno();
return -1;
}
-
/* get remote address */
- ip = (struct sockaddr_in*)&nr->raddr;
- _sock_ingetaddr(nr, ip, &n, "remote");
- if(a){
- memmove(a, ip, sizeof(struct sockaddr_in));
- *alen = sizeof(struct sockaddr_in);
+ _sock_ingetaddr(nr, &nr->raddr, &n, "remote");
+ if(a != 0){
+ if(n > 0)
+ memmove(a, &nr->raddr, n);
+ *alen = n;
}
-
return nfd;
case PF_UNIX:
if(r->other >= 0){
diff --git a/sys/src/ape/lib/bsd/bind.c b/sys/src/ape/lib/bsd/bind.c
index 040c62fa0..902fbcd46 100644
--- a/sys/src/ape/lib/bsd/bind.c
+++ b/sys/src/ape/lib/bsd/bind.c
@@ -24,10 +24,9 @@
int
bind(int fd, void *a, int alen)
{
- int n, len, cfd;
+ int n, len, cfd, port;
Rock *r;
char msg[128];
- struct sockaddr_in *lip;
/* assign the address */
r = _sock_findrock(fd, 0);
@@ -42,7 +41,7 @@ bind(int fd, void *a, int alen)
memmove(&r->addr, a, alen);
/* the rest is IP sepecific */
- if (r->domain != PF_INET)
+ if (r->domain != PF_INET && r->domain != PF_INET6)
return 0;
cfd = open(r->ctl, O_RDWR);
@@ -50,9 +49,9 @@ bind(int fd, void *a, int alen)
errno = EBADF;
return -1;
}
- lip = (struct sockaddr_in*)&r->addr;
- if(lip->sin_port > 0)
- snprintf(msg, sizeof msg, "bind %d", ntohs(lip->sin_port));
+ port = _sock_inport(&r->addr);
+ if(port > 0)
+ snprintf(msg, sizeof msg, "bind %d", port);
else
strcpy(msg, "bind *");
n = write(cfd, msg, strlen(msg));
@@ -62,9 +61,8 @@ bind(int fd, void *a, int alen)
return -1;
}
close(cfd);
-
- if(lip->sin_port <= 0)
- _sock_ingetaddr(r, lip, &len, "local");
+ if(port <= 0)
+ _sock_ingetaddr(r, &r->addr, 0, "local");
return 0;
}
diff --git a/sys/src/ape/lib/bsd/connect.c b/sys/src/ape/lib/bsd/connect.c
index 3f7dcd6b4..ebc63182a 100644
--- a/sys/src/ape/lib/bsd/connect.c
+++ b/sys/src/ape/lib/bsd/connect.c
@@ -21,7 +21,7 @@ connect(int fd, void *a, int alen)
Rock *r;
int n, cfd, nfd;
char msg[8+256+1], file[8+256+1];
- struct sockaddr_in *lip, *rip;
+ struct sockaddr *sa;
struct sockaddr_un *runix;
static int vers;
@@ -34,35 +34,35 @@ connect(int fd, void *a, int alen)
errno = ENAMETOOLONG;
return -1;
}
+ sa = (struct sockaddr*)a;
+ if(sa->sa_family != r->domain){
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
memmove(&r->raddr, a, alen);
switch(r->domain){
case PF_INET:
+ case PF_INET6:
/* set up a tcp or udp connection */
cfd = open(r->ctl, O_RDWR);
- if(cfd < 0){
- _syserrno();
+ if(cfd < 0)
return -1;
- }
- rip = a;
- lip = (struct sockaddr_in*)&r->addr;
- if(lip->sin_port)
+ if(_sock_inport(&r->addr) > 0) {
snprintf(msg, sizeof msg, "connect %s!%d%s %d",
- inet_ntoa(rip->sin_addr), ntohs(rip->sin_port),
+ inet_ntop(sa->sa_family, _sock_inip(sa), file, sizeof(file)),
+ _sock_inport(sa),
r->reserved ? "!r" : "",
- ntohs(lip->sin_port));
- else
+ _sock_inport(&r->addr));
+ } else {
snprintf(msg, sizeof msg, "connect %s!%d%s",
- inet_ntoa(rip->sin_addr), ntohs(rip->sin_port),
+ inet_ntop(sa->sa_family, _sock_inip(sa), file, sizeof(file)),
+ _sock_inport(sa),
r->reserved ? "!r" : "");
- n = write(cfd, msg, strlen(msg));
- if(n < 0){
- _syserrno();
- close(cfd);
- return -1;
}
+ n = write(cfd, msg, strlen(msg));
close(cfd);
- return 0;
+ return (n < 0) ? -1 : 0;
case PF_UNIX:
/* null terminate the address */
if(alen == sizeof(r->raddr))
@@ -87,12 +87,10 @@ connect(int fd, void *a, int alen)
_sock_srvname(file, runix->sun_path);
nfd = open(file, O_RDWR);
if(nfd < 0){
- _syserrno();
unlink(msg);
return -1;
}
if(write(nfd, msg, strlen(msg)) < 0){
- _syserrno();
close(nfd);
unlink(msg);
return -1;
diff --git a/sys/src/ape/lib/bsd/gai_strerror.c b/sys/src/ape/lib/bsd/gai_strerror.c
new file mode 100644
index 000000000..bcb1f8e70
--- /dev/null
+++ b/sys/src/ape/lib/bsd/gai_strerror.c
@@ -0,0 +1,34 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+char*
+gai_strerror(int err)
+{
+ static char *tab[] = {
+ /* 0 */ "No error",
+ /* EAI_BADFLAGS */ "Invalid value for `ai_flags' field",
+ /* EAI_NONAME */ "NAME or SERVICE is unknown",
+ /* EAI_AGAIN */ "Temporary failure in name resolution",
+ /* EAI_FAIL */ "Non-recoverable failure in name resolution",
+ /* EAI_NODATA */ "No address associated with NAME",
+ /* EAI_FAMILY */ "`ai_family' not supported",
+ /* EAI_SOCKTYPE */ "`ai_socktype' not supported",
+ /* EAI_SERVICE */ "SERVICE not supported for `ai_socktype'",
+ /* EAI_ADDRFAMILY */ "Address family for NAME not supported",
+ /* EAI_MEMORY */ "Memory allocation failure",
+ /* EAI_SYSTEM */ "System error returned in `errno'",
+ /* EAI_OVERFLOW */ "Argument buffer overflow",
+ };
+
+ err = -err;
+ if(err < 0 || err >= (sizeof(tab)/sizeof(tab[0])))
+ return "Unknown error";
+ return tab[err];
+}
diff --git a/sys/src/ape/lib/bsd/getaddrinfo.c b/sys/src/ape/lib/bsd/getaddrinfo.c
new file mode 100644
index 000000000..158f22f62
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getaddrinfo.c
@@ -0,0 +1,217 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+/* for malloc/free */
+#include <stdlib.h>
+
+void
+freeaddrinfo(struct addrinfo *res)
+{
+ struct addrinfo *info;
+
+ while((info = res) != 0){
+ res = res->ai_next;
+ free(info->ai_canonname);
+ free(info->ai_addr);
+ free(info);
+ }
+}
+
+static int
+sockfamily(char *addr)
+{
+ if(strchr(addr, ':') != 0)
+ return AF_INET6;
+ else
+ return AF_INET;
+}
+
+static int
+sockproto(char *proto)
+{
+ if(strcmp(proto, "tcp") == 0)
+ return SOCK_STREAM;
+ if(strcmp(proto, "udp") == 0)
+ return SOCK_DGRAM;
+ if(strcmp(proto, "il") == 0)
+ return SOCK_RDM;
+ return 0;
+}
+
+static int
+filladdrinfo(char *s, struct addrinfo *a, struct addrinfo *h)
+{
+ struct sockaddr sa;
+ char *p, *q;
+
+ if(*s != '/')
+ return 1;
+ if((q = strchr(s, ' ')) == 0)
+ return 1;
+ while(*q == ' ')
+ *q++ = 0;
+ if((p = strrchr(s+1, '/')) == 0)
+ return 1;
+ *p = 0;
+ if((p = strrchr(s+1, '/')) == 0)
+ return 1;
+ *p++ = 0;
+ if(*p == 0)
+ return 1;
+
+ if((a->ai_socktype = sockproto(p)) == 0)
+ return 1;
+ if((p = strchr(q, '!')) != 0){
+ *p++ = 0;
+ a->ai_family = sockfamily(q);
+ } else{
+ p = q;
+ q = 0;
+ if((a->ai_family = h->ai_family) == 0)
+ a->ai_family = AF_INET;
+ }
+ if((a->ai_socktype == SOCK_RDM || h->ai_socktype != 0)
+ && (a->ai_socktype != h->ai_socktype))
+ return 1;
+ if(h->ai_family != 0 && a->ai_family != h->ai_family)
+ return 1;
+ if(_sock_inaddr(a->ai_family, q, p, &sa, &a->ai_addrlen) <= 0)
+ return 1;
+ if((a->ai_addr = malloc(a->ai_addrlen)) == 0)
+ return EAI_MEMORY;
+ memmove(a->ai_addr, &sa, a->ai_addrlen);
+ return 0;
+}
+
+int
+getaddrinfo(char *node, char *serv, struct addrinfo *hints, struct addrinfo **res)
+{
+ static struct addrinfo nohints;
+ struct addrinfo *a, *head, **tail;
+ char buf[1024], *proto;
+ int n, fd, err;
+
+ if(res != 0)
+ *res = 0;
+
+ if(hints == 0)
+ hints = &nohints;
+
+ proto = "net";
+ switch(hints->ai_family){
+ default:
+ return EAI_FAMILY;
+ case AF_INET:
+ case AF_INET6:
+ switch(hints->ai_socktype){
+ default:
+ return EAI_SOCKTYPE;
+ case SOCK_STREAM:
+ proto = "tcp";
+ break;
+ case SOCK_DGRAM:
+ proto = "udp";
+ break;
+ case SOCK_RDM:
+ proto = "il";
+ break;
+ case 0:
+ break;
+ }
+ break;
+ case AF_UNSPEC:
+ break;
+ }
+ if(serv == 0){
+ if(node == 0)
+ return EAI_NONAME;
+ serv = "0";
+ }
+ if(node == 0){
+ if(hints->ai_flags & AI_PASSIVE)
+ node = "*";
+ else if(hints->ai_family == AF_INET6)
+ node = "::1";
+ else
+ node = "127.0.0.1";
+ }
+
+ if((fd = open("/net/cs", O_RDWR)) < 0)
+ return EAI_SYSTEM;
+
+ snprintf(buf, sizeof(buf), "%s!%s!%s", proto, node, serv);
+ n = strlen(buf);
+ if(write(fd, buf, n) != n){
+ close(fd);
+ return EAI_AGAIN;
+ }
+ lseek(fd, 0, 0);
+
+ head = 0;
+ tail = &head;
+ for(;;){
+ if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
+ break;
+ buf[n] = '\0';
+ if((a = malloc(sizeof(*a))) == 0){
+ freeaddrinfo(head);
+ close(fd);
+ return EAI_MEMORY;
+ }
+ memset(a, 0, sizeof(*a));
+ if((err = filladdrinfo(buf, a, hints)) != 0){
+ freeaddrinfo(a);
+ if(err < 0){
+ freeaddrinfo(head);
+ close(fd);
+ return err;
+ }
+ } else {
+ *tail = a;
+ tail = &a->ai_next;
+ }
+ }
+ close(fd);
+
+ if(head == 0)
+ return EAI_NODATA;
+
+ if((hints->ai_flags & AI_CANONNAME) != 0 && (hints->ai_flags & AI_NUMERICHOST) == 0){
+ n = _sock_ipattr(node);
+ if(n != Tsys && n != Tdom){
+ if(getnameinfo(head->ai_addr, head->ai_addrlen, buf, sizeof(buf), 0, 0, NI_NAMEREQD) == 0)
+ node = buf;
+ else
+ node = 0;
+ }
+ if(node != 0){
+ n = strlen(node)+1;
+ if((head->ai_canonname = malloc(n)) == 0){
+ freeaddrinfo(head);
+ return EAI_MEMORY;
+ }
+ memmove(head->ai_canonname, node, n);
+ }
+ }
+
+ if(res != 0)
+ *res = head;
+ else
+ freeaddrinfo(head);
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/gethostbyname.c b/sys/src/ape/lib/bsd/gethostbyname.c
index 749798510..9393865fb 100644
--- a/sys/src/ape/lib/bsd/gethostbyname.c
+++ b/sys/src/ape/lib/bsd/gethostbyname.c
@@ -29,7 +29,7 @@ struct hostent*
gethostbyname(char *name)
{
int i, t, fd, m;
- char *p, *bp;
+ char *p, *k, *bp;
int nn, na;
unsigned long x;
static struct hostent h;
@@ -44,7 +44,6 @@ gethostbyname(char *name)
/* connect to server */
fd = open("/net/cs", O_RDWR);
if(fd < 0){
- _syserrno();
h_errno = NO_RECOVERY;
return 0;
}
@@ -64,8 +63,8 @@ gethostbyname(char *name)
/* query the server */
if(write(fd, buf, strlen(buf)) < 0){
- _syserrno();
h_errno = TRY_AGAIN;
+ close(fd);
return 0;
}
lseek(fd, 0, 0);
@@ -81,19 +80,26 @@ gethostbyname(char *name)
/* parse the reply */
nn = na = 0;
for(bp = buf;;){
- p = strchr(bp, '=');
+ k = bp;
+ p = strchr(k, '=');
if(p == 0)
break;
*p++ = 0;
- if(strcmp(bp, "dom") == 0){
+ for(bp = p; *bp && *bp != ' '; bp++)
+ ;
+ if(*bp)
+ *bp++ = 0;
+ if(strcmp(k, "dom") == 0){
if(h.h_name == 0)
h.h_name = p;
if(nn < Nname)
nptr[nn++] = p;
- } else if(strcmp(bp, "sys") == 0){
+ } else if(strcmp(k, "sys") == 0){
if(nn < Nname)
nptr[nn++] = p;
- } else if(strcmp(bp, "ip") == 0){
+ } else if(strcmp(k, "ip") == 0){
+ if(strchr(p, ':') != 0)
+ continue; /* ignore ipv6 addresses */
x = inet_addr(p);
x = ntohl(x);
if(na < Nname){
@@ -105,11 +111,6 @@ gethostbyname(char *name)
na++;
}
}
- while(*p && *p != ' ')
- p++;
- if(*p)
- *p++ = 0;
- bp = p;
}
if(nn+na == 0){
h_errno = HOST_NOT_FOUND;
diff --git a/sys/src/ape/lib/bsd/getnameinfo.c b/sys/src/ape/lib/bsd/getnameinfo.c
new file mode 100644
index 000000000..70db2c246
--- /dev/null
+++ b/sys/src/ape/lib/bsd/getnameinfo.c
@@ -0,0 +1,126 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <fcntl.h>
+#include <string.h>
+#include <errno.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <netdb.h>
+
+#include "priv.h"
+
+static int
+netquery(char *buf, int nbuf)
+{
+ int fd, i, n;
+
+ if((fd = open("/net/cs", O_RDWR)) < 0)
+ return EAI_SYSTEM;
+ n = strlen(buf);
+ if(write(fd, buf, n) != n){
+ close(fd);
+ return EAI_NONAME;
+ }
+ lseek(fd, 0, 0);
+ for(i = 0; i < nbuf-1; i += n){
+ n = read(fd, buf+i, nbuf - 1 - i);
+ if(n <= 0)
+ break;
+ buf[i+n++] = ' ';
+ }
+ close(fd);
+ buf[i] = 0;
+ return i;
+}
+
+int
+getnameinfo(struct sockaddr *sa, int salen,
+ char *host, int hostlen,
+ char *serv, int servlen,
+ unsigned int flags)
+{
+ char buf[8*1024], *b, *p;
+ int err;
+
+ if(sa->sa_family != AF_INET && sa->sa_family != AF_INET6)
+ return EAI_FAMILY;
+
+ if(host != 0 && hostlen > 0){
+ if(inet_ntop(sa->sa_family, _sock_inip(sa), host, hostlen) == 0)
+ return EAI_SYSTEM;
+
+ if((flags & NI_NUMERICHOST) == 0){
+ snprintf(buf, sizeof(buf), "!ip=%s", host);
+ if((err = netquery(buf, sizeof(buf))) < 0){
+ if((flags & NI_NAMEREQD) != 0)
+ return err;
+ } else {
+ char *sys, *dom;
+
+ sys = dom = 0;
+ for(b = buf;;){
+ if((p = strchr(b, '=')) == 0)
+ break;
+ *p++ = 0;
+ if(strcmp(b, "sys") == 0)
+ sys = p;
+ else if(strcmp(b, "dom") == 0)
+ dom = p;
+ while(*p && *p != ' ')
+ p++;
+ while(*p == ' ')
+ *p++ = 0;
+ b = p;
+ }
+ if(sys == 0){
+ if(dom == 0 && (flags & NI_NAMEREQD) != 0)
+ return EAI_NONAME;
+ if(dom != 0 && (flags & NI_NOFQDN) != 0){
+ if((p = strchr(dom, '.')) != 0)
+ *p = 0;
+ }
+ sys = dom;
+ }
+ snprintf(host, hostlen, "%s", sys);
+ }
+ }
+ }
+
+ if(serv != 0 && servlen > 0){
+ snprintf(serv, servlen, "%d", _sock_inport(sa));
+ if((flags & NI_NUMERICSERV) == 0){
+ snprintf(buf, sizeof(buf), "!port=%s", serv);
+ if(netquery(buf, sizeof(buf)) > 0){
+ char *tcp, *udp;
+
+ tcp = udp = 0;
+ for(b = buf;;){
+ if((p = strchr(b, '=')) == 0)
+ break;
+ *p++ = 0;
+ if(strcmp(b, "tcp") == 0)
+ tcp = p;
+ else if(strcmp(b, "udp") == 0)
+ udp = p;
+ while(*p && *p != ' ')
+ p++;
+ while(*p == ' ')
+ *p++ = 0;
+ b = p;
+ }
+ if(udp != 0 && (flags & NI_DGRAM) != 0)
+ snprintf(serv, servlen, "%s", udp);
+ else if(tcp != 0)
+ snprintf(serv, servlen, "%s", tcp);
+ }
+ }
+ }
+
+ return 0;
+}
diff --git a/sys/src/ape/lib/bsd/getpeername.c b/sys/src/ape/lib/bsd/getpeername.c
index e4dd3109c..55b4f8eb3 100644
--- a/sys/src/ape/lib/bsd/getpeername.c
+++ b/sys/src/ape/lib/bsd/getpeername.c
@@ -20,7 +20,6 @@ getpeername(int fd, struct sockaddr *addr, int *alen)
{
Rock *r;
int i;
- struct sockaddr_in *rip;
struct sockaddr_un *runix;
r = _sock_findrock(fd, 0);
@@ -31,10 +30,13 @@ getpeername(int fd, struct sockaddr *addr, int *alen)
switch(r->domain){
case PF_INET:
- rip = (struct sockaddr_in*)&r->raddr;
- memmove(addr, rip, sizeof(struct sockaddr_in));
+ memmove(addr, &r->raddr, sizeof(struct sockaddr_in));
*alen = sizeof(struct sockaddr_in);
break;
+ case PF_INET6:
+ memmove(addr, &r->raddr, sizeof(struct sockaddr_in6));
+ *alen = sizeof(struct sockaddr_in6);
+ break;
case PF_UNIX:
runix = (struct sockaddr_un*)&r->raddr;
i = &runix->sun_path[strlen(runix->sun_path)] - (char*)runix;
diff --git a/sys/src/ape/lib/bsd/getprotobyname.c b/sys/src/ape/lib/bsd/getprotobyname.c
index f88d70148..bd13a0cc5 100644
--- a/sys/src/ape/lib/bsd/getprotobyname.c
+++ b/sys/src/ape/lib/bsd/getprotobyname.c
@@ -35,7 +35,6 @@ struct protoent *getprotobyname(const char *name) {
/* connect to server */
fd = open("/net/cs", O_RDWR);
if(fd < 0){
- _syserrno();
h_errno = NO_RECOVERY;
return 0;
}
@@ -45,8 +44,8 @@ struct protoent *getprotobyname(const char *name) {
/* query the server */
if(write(fd, buf, strlen(buf)) < 0){
- _syserrno();
h_errno = TRY_AGAIN;
+ close(fd);
return 0;
}
lseek(fd, 0, 0);
diff --git a/sys/src/ape/lib/bsd/getservbyname.c b/sys/src/ape/lib/bsd/getservbyname.c
index 0212d5403..5ad73b220 100644
--- a/sys/src/ape/lib/bsd/getservbyname.c
+++ b/sys/src/ape/lib/bsd/getservbyname.c
@@ -43,10 +43,8 @@ getservbyname(char *name, char *proto)
/* connect to server */
fd = open("/net/cs", O_RDWR);
- if(fd < 0){
- _syserrno();
+ if(fd < 0)
return 0;
- }
/* construct the query, always expect an ip# back */
if(num)
@@ -56,7 +54,7 @@ getservbyname(char *name, char *proto)
/* query the server */
if(write(fd, buf, strlen(buf)) < 0){
- _syserrno();
+ close(fd);
return 0;
}
lseek(fd, 0, 0);
diff --git a/sys/src/ape/lib/bsd/getsockname.c b/sys/src/ape/lib/bsd/getsockname.c
index aa22d3217..cdf149779 100644
--- a/sys/src/ape/lib/bsd/getsockname.c
+++ b/sys/src/ape/lib/bsd/getsockname.c
@@ -20,7 +20,6 @@ getsockname(int fd, struct sockaddr *addr, int *alen)
{
Rock *r;
int i;
- struct sockaddr_in *lip;
struct sockaddr_un *lunix;
r = _sock_findrock(fd, 0);
@@ -31,14 +30,15 @@ getsockname(int fd, struct sockaddr *addr, int *alen)
switch(r->domain){
case PF_INET:
- lip = (struct sockaddr_in*)addr;
- _sock_ingetaddr(r, lip, alen, "local");
+ case PF_INET6:
+ _sock_ingetaddr(r, addr, alen, "local");
break;
case PF_UNIX:
lunix = (struct sockaddr_un*)&r->addr;
i = &lunix->sun_path[strlen(lunix->sun_path)] - (char*)lunix;
memmove(addr, lunix, i);
- *alen = i;
+ if(alen != 0)
+ *alen = i;
break;
default:
errno = EAFNOSUPPORT;
diff --git a/sys/src/ape/lib/bsd/in6_addr.c b/sys/src/ape/lib/bsd/in6_addr.c
new file mode 100644
index 000000000..324593a32
--- /dev/null
+++ b/sys/src/ape/lib/bsd/in6_addr.c
@@ -0,0 +1,4 @@
+#include <netinet/in.h>
+
+struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
+struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;
diff --git a/sys/src/ape/lib/bsd/inet_ntop.c b/sys/src/ape/lib/bsd/inet_ntop.c
new file mode 100644
index 000000000..0f9c9e2b0
--- /dev/null
+++ b/sys/src/ape/lib/bsd/inet_ntop.c
@@ -0,0 +1,54 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+
+char*
+inet_ntop(int af, void *src, char *dst, int size)
+{
+ unsigned char *p;
+ char *t, *e;
+ int i;
+
+ if(af == AF_INET){
+ if(size < INET_ADDRSTRLEN){
+ errno = ENOSPC;
+ return 0;
+ }
+ p = (unsigned char*)&(((struct in_addr*)src)->s_addr);
+ snprintf(dst, size, "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ return dst;
+ }
+
+ if(af != AF_INET6){
+ errno = EAFNOSUPPORT;
+ return 0;
+ }
+ if(size < INET6_ADDRSTRLEN){
+ errno = ENOSPC;
+ return 0;
+ }
+
+ p = (unsigned char*)((struct in6_addr*)src)->s6_addr;
+ t = dst;
+ e = t + size;
+ for(i=0; i<16; i += 2){
+ unsigned int w;
+
+ if(i > 0)
+ *t++ = ':';
+ w = p[i]<<8 | p[i+1];
+ snprintf(t, e - t, "%x", w);
+ t += strlen(t);
+ }
+ return dst;
+}
diff --git a/sys/src/ape/lib/bsd/inet_pton.c b/sys/src/ape/lib/bsd/inet_pton.c
new file mode 100644
index 000000000..863124b00
--- /dev/null
+++ b/sys/src/ape/lib/bsd/inet_pton.c
@@ -0,0 +1,79 @@
+/* posix */
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+
+/* bsd extensions */
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+
+#include <errno.h>
+
+static int
+ipcharok(int c)
+{
+ return c == ':' || isascii(c) && isxdigit(c);
+}
+
+static int
+delimchar(int c)
+{
+ if(c == '\0')
+ return 1;
+ if(c == ':' || isascii(c) && isalnum(c))
+ return 0;
+ return 1;
+}
+
+int
+inet_pton(int af, char *src, void *dst)
+{
+ int i, elipsis = 0;
+ unsigned char *to;
+ unsigned long x;
+ char *p, *op;
+
+ if(af == AF_INET){
+ ((struct in_addr*)dst)->s_addr = inet_addr(src);
+ return 1;
+ }
+
+ if(af != AF_INET6){
+ errno = EAFNOSUPPORT;
+ return -1;
+ }
+
+ to = ((struct in6_addr*)dst)->s6_addr;
+ memset(to, 0, 16);
+
+ p = src;
+ for(i = 0; i < 16 && ipcharok(*p); i+=2){
+ op = p;
+ x = strtoul(p, &p, 16);
+
+ if(x != (unsigned short)x || *p != ':' && !delimchar(*p))
+ return 0; /* parse error */
+
+ to[i] = x>>8;
+ to[i+1] = x;
+ if(*p == ':'){
+ if(*++p == ':'){ /* :: is elided zero short(s) */
+ if (elipsis)
+ return 0; /* second :: */
+ elipsis = i+2;
+ p++;
+ }
+ } else if (p == op) /* strtoul made no progress? */
+ break;
+ }
+ if (p == src || !delimchar(*p))
+ return 0; /* parse error */
+ if(i < 16){
+ memmove(&to[elipsis+16-i], &to[elipsis], i-elipsis);
+ memset(&to[elipsis], 0, 16-i);
+ }
+ return 1;
+}
diff --git a/sys/src/ape/lib/bsd/listen.c b/sys/src/ape/lib/bsd/listen.c
index c5bf19069..b0408cd19 100644
--- a/sys/src/ape/lib/bsd/listen.c
+++ b/sys/src/ape/lib/bsd/listen.c
@@ -47,6 +47,9 @@ listenproc(Rock *r, int fd)
case SOCK_STREAM:
net = "tcp";
break;
+ case SOCK_RDM:
+ net = "il";
+ break;
}
strcpy(listen, r->ctl);
@@ -118,9 +121,8 @@ listen(fd, backlog)
int backlog;
{
Rock *r;
- int n, cfd;
+ int n, cfd, port;
char msg[128];
- struct sockaddr_in *lip;
struct sockaddr_un *lunix;
r = _sock_findrock(fd, 0);
@@ -131,20 +133,20 @@ listen(fd, backlog)
switch(r->domain){
case PF_INET:
+ case PF_INET6:
cfd = open(r->ctl, O_RDWR);
if(cfd < 0){
errno = EBADF;
return -1;
}
- lip = (struct sockaddr_in*)&r->addr;
- if(lip->sin_port >= 0) {
+ port = _sock_inport(&r->addr);
+ if(port >= 0) {
if(write(cfd, "bind 0", 6) < 0) {
errno = EGREG;
close(cfd);
return -1;
}
- snprintf(msg, sizeof msg, "announce %d",
- ntohs(lip->sin_port));
+ snprintf(msg, sizeof msg, "announce %d", port);
}
else
strcpy(msg, "announce *");
@@ -164,7 +166,6 @@ listen(fd, backlog)
}
lunix = (struct sockaddr_un*)&r->addr;
if(_sock_srv(lunix->sun_path, r->other) < 0){
- _syserrno();
r->other = -1;
return -1;
}
diff --git a/sys/src/ape/lib/bsd/mkfile b/sys/src/ape/lib/bsd/mkfile
index 3034e13a4..5f95c9b02 100644
--- a/sys/src/ape/lib/bsd/mkfile
+++ b/sys/src/ape/lib/bsd/mkfile
@@ -9,10 +9,13 @@ OFILES=\
connect.$O\
endhostent.$O\
ffs.$O\
+ gai_strerror.$O\
+ getaddrinfo.$O\
getdtablesize.$O\
- gethostbyname.$O\
gethostbyaddr.$O\
+ gethostbyname.$O\
gethostname.$O\
+ getnameinfo.$O\
getopt.$O\
getpeername.$O\
getprotobyname.$O\
@@ -20,8 +23,11 @@ OFILES=\
getservbyname.$O\
getsockname.$O\
gettimeofday.$O\
+ in6_addr.$O\
inet_addr.$O\
inet_ntoa.$O\
+ inet_ntop.$O\
+ inet_pton.$O\
ioctl.$O\
listen.$O\
lstat.$O\
diff --git a/sys/src/ape/lib/bsd/priv.h b/sys/src/ape/lib/bsd/priv.h
index f99fc5673..7004f3cc6 100644
--- a/sys/src/ape/lib/bsd/priv.h
+++ b/sys/src/ape/lib/bsd/priv.h
@@ -41,6 +41,7 @@ extern void _sock_srvname(char*, char*);
extern int _sock_srv(char*, int);
extern int _sock_data(int, char*, int, int, int, Rock**);
extern int _sock_ipattr(char*);
-extern void _sock_ingetaddr(Rock*, struct sockaddr_in*, int*, char*);
-
-extern void _syserrno(void);
+extern void* _sock_inip(struct sockaddr*);
+extern int _sock_inport(struct sockaddr*);
+extern int _sock_inaddr(int, char*, char*, void*, int*);
+extern void _sock_ingetaddr(Rock*, void*, int*, char*);
diff --git a/sys/src/ape/lib/bsd/socket.c b/sys/src/ape/lib/bsd/socket.c
index d14b35386..3cf8c6632 100644
--- a/sys/src/ape/lib/bsd/socket.c
+++ b/sys/src/ape/lib/bsd/socket.c
@@ -125,6 +125,7 @@ socket(int domain, int stype, int protocol)
switch(domain){
case PF_INET:
+ case PF_INET6:
/* get a free network directory */
switch(stype){
case SOCK_DGRAM:
@@ -135,20 +136,20 @@ socket(int domain, int stype, int protocol)
net = "tcp";
cfd = open("/net/tcp/clone", O_RDWR);
break;
+ case SOCK_RDM:
+ net = "il";
+ cfd = open("/net/il/clone", O_RDWR);
+ break;
default:
errno = EPROTONOSUPPORT;
return -1;
}
- if(cfd < 0){
- _syserrno();
+ if(cfd < 0)
return -1;
- }
return _sock_data(cfd, net, domain, stype, protocol, 0);
case PF_UNIX:
- if(pipe(pfd) < 0){
- _syserrno();
+ if(pipe(pfd) < 0)
return -1;
- }
r = _sock_newrock(pfd[0]);
if(r == 0){
close(pfd[0]);
diff --git a/sys/src/ape/lib/bsd/writev.c b/sys/src/ape/lib/bsd/writev.c
index fbb36b692..5de967743 100644
--- a/sys/src/ape/lib/bsd/writev.c
+++ b/sys/src/ape/lib/bsd/writev.c
@@ -33,12 +33,10 @@ writev(int fd, struct iovec *v, int ent)
f += i;
i = write(fd, buf, sizeof(buf));
if(i < 0){
- if(written > 0){
+ if(written > 0)
return written;
- }else{
- _syserrno();
+ else
return -1;
- }
}
written += i;
if(i != sizeof(buf)) {
@@ -51,10 +49,8 @@ writev(int fd, struct iovec *v, int ent)
if(i > 0){
n = write(fd, buf, i);
if(n < 0){
- if(written == 0){
- _syserrno();
+ if(written == 0)
return -1;
- }
} else
written += n;
}