diff options
author | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-03-31 18:52:45 +0200 |
---|---|---|
committer | cinap_lenrek <cinap_lenrek@gmx.de> | 2013-03-31 18:52:45 +0200 |
commit | b6dc4ba5a44a2ed2a68266598ceb28b7a7d51af2 (patch) | |
tree | b2af773db48a3606bd078055db925dbba6d4ffaa | |
parent | 9c7e1db701e0e80b42bb5990e2f6839d712bb984 (diff) | |
download | plan9front-b6dc4ba5a44a2ed2a68266598ceb28b7a7d51af2.tar.xz |
ape: initial IPv6 support, inet_pton()/inet_ntop(), getaddrinfo()/getnameinfo()
26 files changed, 760 insertions, 257 deletions
diff --git a/sys/include/ape/arpa/inet.h b/sys/include/ape/arpa/inet.h index 5417eb094..260020a6a 100644 --- a/sys/include/ape/arpa/inet.h +++ b/sys/include/ape/arpa/inet.h @@ -1,146 +1 @@ -#ifndef __netinet_in__ -#define __netinet_in__ - -#ifdef __cplusplus -extern "C" { -#endif - -/* - * Copyright (c) 1982, 1986, 1990 Regents of the University of California. - * All rights reserved. - * - * Redistribution is only permitted until one year after the first shipment - * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and - * binary forms are permitted provided that: (1) source distributions retain - * this entire copyright notice and comment, and (2) distributions including - * binaries display the following acknowledgement: This product includes - * software developed by the University of California, Berkeley and its - * contributors'' in the documentation or other materials provided with the - * distribution and in all advertising materials mentioning features or use - * of this software. Neither the name of the University nor the names of - * its contributors may be used to endorse or promote products derived from - * this software without specific prior written permission. - * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. - * - * @(#)in.h 7.10 (Berkeley) 6/28/90 plus MULTICAST 1.1 - */ - -/* - * Constants and structures defined by the internet system, - * Per RFC 790, September 1981. - */ - -/* - * Protocols - */ -#define IPPROTO_IP 0 /* dummy for IP */ -#define IPPROTO_ICMP 1 /* control message protocol */ -#define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ -#define IPPROTO_TCP 6 /* tcp */ -#define IPPROTO_EGP 8 /* exterior gateway protocol */ -#define IPPROTO_PUP 12 /* pup */ -#define IPPROTO_UDP 17 /* user datagram protocol */ -#define IPPROTO_IDP 22 /* xns idp */ -#define IPPROTO_TP 29 /* tp-4 w/ class negotiation */ -#define IPPROTO_EON 80 /* ISO cnlp */ - -#define IPPROTO_RAW 255 /* raw IP packet */ -#define IPPROTO_MAX 256 - - -/* - * Local port number conventions: - * Ports < IPPORT_RESERVED are reserved for - * privileged processes (e.g. root). - * Ports > IPPORT_USERRESERVED are reserved - * for servers, not necessarily privileged. - */ -#define IPPORT_RESERVED 1024 -#define IPPORT_USERRESERVED 5000 - -/* - * Internet address (a structure for historical reasons) - */ -struct in_addr { - unsigned long s_addr; -}; - -/* - * Definitions of bits in internet address integers. - * On subnets, the decomposition of addresses to host and net parts - * is done according to subnet mask, not the masks here. - */ -#define IN_CLASSA(i) (((long)(i) & 0x80000000) == 0) -#define IN_CLASSA_NET 0xff000000 -#define IN_CLASSA_NSHIFT 24 -#define IN_CLASSA_HOST 0x00ffffff -#define IN_CLASSA_MAX 128 - -#define IN_CLASSB(i) (((long)(i) & 0xc0000000) == 0x80000000) -#define IN_CLASSB_NET 0xffff0000 -#define IN_CLASSB_NSHIFT 16 -#define IN_CLASSB_HOST 0x0000ffff -#define IN_CLASSB_MAX 65536 - -#define IN_CLASSC(i) (((long)(i) & 0xe0000000) == 0xc0000000) -#define IN_CLASSC_NET 0xffffff00 -#define IN_CLASSC_NSHIFT 8 -#define IN_CLASSC_HOST 0x000000ff - -#define IN_CLASSD(i) (((long)(i) & 0xf0000000) == 0xe0000000) -#define IN_MULTICAST(i) IN_CLASSD(i) - -#define IN_EXPERIMENTAL(i) (((long)(i) & 0xe0000000) == 0xe0000000) -#define IN_BADCLASS(i) (((long)(i) & 0xf0000000) == 0xf0000000) - -#define INADDR_ANY (unsigned long)0x00000000 -#define INADDR_BROADCAST (unsigned long)0xffffffff /* must be masked */ - -#define IN_LOOPBACKNET 127 /* official! */ - -/* - * Socket address, internet style. - */ -struct sockaddr_in { - short sin_family; - unsigned short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; -}; - -/* - * Structure used to describe IP options. - * Used to store options internally, to pass them to a process, - * or to restore options retrieved earlier. - * The ip_dst is used for the first-hop gateway when using a source route - * (this gets put into the header proper). - */ -struct ip_opts { - struct in_addr ip_dst; /* first hop, 0 w/o src rt */ - char ip_opts[40]; /* actually variable in size */ -}; - -/* - * Options for use with [gs]etsockopt at the IP level. - * First word of comment is data type; bool is stored in int. - */ -#define IP_OPTIONS 1 /* buf/ip_opts; set/get IP per-packet options */ -#define IP_HDRINCL 7 /* int; header is included with data (raw) */ -#define IP_TOS 8 /* int; IP type of service and precedence */ -#define IP_TTL 9 /* int; IP time to live */ - -extern unsigned long ntohl(unsigned long x); -extern unsigned short ntohs(unsigned short x); -extern unsigned long htonl(unsigned long x); -extern unsigned short htons(unsigned short x); -extern unsigned long inet_addr(char*); -extern char* inet_ntoa(struct in_addr); -extern unsigned long nptohl(void*); - -#ifdef __cplusplus -} -#endif - -#endif /* __netinet_in__ */ +#include <netinet/in.h> diff --git a/sys/include/ape/netdb.h b/sys/include/ape/netdb.h index 5885c3ab3..2f5fd7539 100644 --- a/sys/include/ape/netdb.h +++ b/sys/include/ape/netdb.h @@ -114,6 +114,54 @@ extern char *hstrerror(int); #define __HOST_SVC_NOT_AVAIL 99 /* libc internal use only */ +struct addrinfo { + int ai_flags; /* Input flags. */ + int ai_family; /* Protocol family for socket. */ + int ai_socktype; /* Socket type. */ + int ai_protocol; /* Protocol for socket. */ + int ai_addrlen; /* Length of socket address. */ + struct sockaddr *ai_addr; /* Socket address for socket. */ + char *ai_canonname; /* Canonical name for service location. */ + struct addrinfo *ai_next; /* Pointer to next in list. */ +}; + +extern int getaddrinfo(char *, char *, struct addrinfo *, struct addrinfo **); +extern void freeaddrinfo(struct addrinfo *); +extern int getnameinfo(struct sockaddr *, int, char *, int, char *, int, unsigned int); +extern char *gai_strerror(int); + +/* Possible values for `ai_flags' field in `addrinfo' structure. */ +#define AI_PASSIVE 0x0001 /* Socket address is intended for `bind'. */ +#define AI_CANONNAME 0x0002 /* Request for canonical name. */ +#define AI_NUMERICHOST 0x0004 /* Don't use name resolution. */ +#define AI_V4MAPPED 0x0008 /* IPv4 mapped addresses are acceptable. */ +#define AI_ALL 0x0010 /* Return IPv4 mapped and IPv6 addresses. */ +#define AI_ADDRCONFIG 0x0020 /* Use configuration of this host to choose returned address type.. */ +#define AI_NUMERICSERV 0x0400 /* Don't use name resolution. */ + +/* getnameinfo flags */ +#define NI_NOFQDN 0x0001 /* Only the nodename portion of the FQDN is returned for local hosts. */ +#define NI_NUMERICHOST 0x0002 /* The numeric form of the node's address is returned instead of its name. */ +#define NI_NAMEREQD 0x0004 /* Return an error if the node's name cannot be located in the database. */ +#define NI_NUMERICSERV 0x0008 /* The numeric form of the service address is returned instead of its name. */ +#define NI_NUMERICSCOPE 0x0010 /* For IPv6 addresses, the numeric form of the scope identifier is returned + instead of its name. */ +#define NI_DGRAM 0x0020 /* Indicates that the service is a datagram service (SOCK_DGRAM). */ + +/* Error values for `getaddrinfo' and `getnameinfo' functions. */ +#define EAI_BADFLAGS -1 /* Invalid value for `ai_flags' field */ +#define EAI_NONAME -2 /* NAME or SERVICE is unknown */ +#define EAI_AGAIN -3 /* Temporary failure in name resolution */ +#define EAI_FAIL -4 /* Non-recoverable failure in name resolution */ +#define EAI_NODATA -5 /* No address associated with NAME */ +#define EAI_FAMILY -6 /* `ai_family' not supported */ +#define EAI_SOCKTYPE -7 /* `ai_socktype' not supported */ +#define EAI_SERVICE -8 /* SERVICE not supported for `ai_socktype' */ +#define EAI_ADDRFAMILY -9 /* Address family for NAME not supported */ +#define EAI_MEMORY -10 /* Memory allocation failure */ +#define EAI_SYSTEM -11 /* System error returned in `errno' */ +#define EAI_OVERFLOW -12 /* Argument buffer overflow */ + #ifdef __cplusplus } #endif diff --git a/sys/include/ape/netinet/in.h b/sys/include/ape/netinet/in.h index 3d04f8ee1..8444c1bcf 100644 --- a/sys/include/ape/netinet/in.h +++ b/sys/include/ape/netinet/in.h @@ -102,13 +102,39 @@ struct in_addr { #define IN_LOOPBACKNET 127 /* official! */ /* + * IPv6 internet address. + */ +struct in6_addr { + unsigned char s6_addr[16]; +}; + +extern struct in6_addr in6addr_any; +extern struct in6_addr in6addr_loopback; + +#define IN6ADDR_ANY_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }} + +#define IN6ADDR_LOOPBACK_INIT \ + {{ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, \ + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01 }} + +/* * Socket address, internet style. */ struct sockaddr_in { - short sin_family; + short sin_family; unsigned short sin_port; - struct in_addr sin_addr; - char sin_zero[8]; + struct in_addr sin_addr; + char sin_zero[8]; +}; + +struct sockaddr_in6 { + short sin6_family; + unsigned short sin6_port; + unsigned long sin6_flowinfo; + struct in6_addr sin6_addr; + unsigned long sin6_scope_id; }; /* @@ -140,6 +166,12 @@ extern unsigned long inet_addr(char*); extern char* inet_ntoa(struct in_addr); extern unsigned long nptohl(void*); +extern char* inet_ntop(int af, void *src, char *dst, int size); +extern int inet_pton(int af, char *src, void *dst); + +#define INET_ADDRSTRLEN 16 +#define INET6_ADDRSTRLEN 46 + #ifdef __cplusplus } #endif diff --git a/sys/include/ape/sys/socket.h b/sys/include/ape/sys/socket.h index df7ad5849..5d60c77a7 100644 --- a/sys/include/ape/sys/socket.h +++ b/sys/include/ape/sys/socket.h @@ -22,6 +22,8 @@ extern "C" { /* * Definitions related to sockets: types, address families, options. */ +typedef int socklen_t; +typedef unsigned short sa_family_t; /* * Types @@ -108,7 +110,12 @@ struct linger { */ struct sockaddr { unsigned short sa_family; /* address family */ - char sa_data[108]; + char sa_data[108]; +}; + +struct sockaddr_storage { + unsigned short ss_family; + char ss_data[108]; }; /* 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; } |