ape: initial IPv6 support, inet_pton()/inet_ntop(), getaddrinfo()/getnameinfo()

This commit is contained in:
cinap_lenrek 2013-03-31 18:52:45 +02:00
parent 9c7e1db701
commit b6dc4ba5a4
26 changed files with 762 additions and 259 deletions

View file

@ -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>

View file

@ -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

View file

@ -101,14 +101,40 @@ 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

View file

@ -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];
};
/*

View file

@ -15,17 +15,74 @@
#include "priv.h"
void
_sock_ingetaddr(Rock *r, struct sockaddr_in *ip, int *alen, char *a)
void*
_sock_inip(struct sockaddr *a)
{
int n, fd;
char *p;
char name[Ctlsize];
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, void *a, int *alen, char *file)
{
char name[Ctlsize], *p;
int n, fd;
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);
}
}

View file

@ -27,6 +27,8 @@ _sock_ipattr(char *name)
alpha = 1;
else if(*p == '.')
dot = 1;
else if(*p == ':')
return Tip;
else
return Tsys;
}

View file

@ -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;

View file

@ -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){

View file

@ -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;
}

View file

@ -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;

View file

@ -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];
}

View file

@ -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;
}

View file

@ -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;

View file

@ -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;
}

View file

@ -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;

View file

@ -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);

View file

@ -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);

View file

@ -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;

View file

@ -0,0 +1,4 @@
#include <netinet/in.h>
struct in6_addr in6addr_any = IN6ADDR_ANY_INIT;
struct in6_addr in6addr_loopback = IN6ADDR_LOOPBACK_INIT;

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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;
}

View file

@ -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\

View file

@ -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*);

View file

@ -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]);

View file

@ -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;
}