Plan 9 from Bell Labs’s /usr/web/sources/patch/ape-erik/getnameinfo.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


#define _SUSV2_SOURCE
#define _C99_SNPRINTF_EXTENSION
#include <sys/types.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <string.h>
#include <inttypes.h>

#include <arpa/inet.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netdb.h>

#define nil ((void*)0)

static int
getport(char *trans, int port, char *srv, int srvlen)
{
	char buf[128], match[5], *p, *q;
	int fd, r, n;

	r = EAI_FAIL;
	fd = open("/net/cs", O_RDWR);
	if(fd < 0)
		return r;
	snprintf(buf, sizeof buf, "!port=%d %s=*", port, trans);
	snprintf(match, sizeof match, "%s=", trans);
	if(write(fd, buf, strlen(buf)) == -1){
		close(fd);
		return r;
	}

	lseek(fd, 0, 0);
	n = read(fd, buf, sizeof buf - 1);
	if(n > 0){
		buf[n] = 0;
		for(p = buf; p != nil; p = q){
			q = strchr(buf, ' ');
			if(q != nil)
				*q++ = 0;
			if(strncmp(p, match, 4) == 0){
				r = snprintf(srv, srvlen, "%s", p+4);
				break;
			}
		}
	}
	close(fd);
	return r;
}

static int
getname(int af, void *addr, char *host, long hostlen, int flags)
{
	char ipbuf[128], buf[128], *p, *q;
	int fd, r, n;

	r = EAI_FAIL;
	if(inet_ntop(af, addr, ipbuf, sizeof ipbuf) == nil)
		return EAI_SYSTEM;
	fd = open("/net/cs", O_RDWR);
	if(fd < 0)
		return r;
	snprintf(buf, sizeof buf, "!ip=%s dom=*", ipbuf);
	if(write(fd, buf, strlen(buf)) == -1){
		close(fd);
		return r;
	}

	lseek(fd, 0, 0);
	n = read(fd, buf, sizeof buf - 1);
	if(n > 0){
		buf[n] = 0;
		for(p = buf; p != nil; p = q){
			q = strchr(buf, ' ');
			if(q != nil)
				*q++ = 0;
			if(strncmp(p, "dom=", 4) == 0){
				r = snprintf(ipbuf, sizeof ipbuf, "%s", p+4);
				break;
			}
		}
	}
	close(fd);

	if(r >= 0){
		if(flags & NI_NOFQDN){
			p = strchr(ipbuf, '.');
			if(p != nil)
				*p = 0;
		}
		r = EAI_OVERFLOW;
		if(snprintf(host, hostlen, "%s", ipbuf) >= 0)
			r = 0;
	}
	return r;
}

static int
afhinfo(int af, void *addr, int port, char *host, long hostlen, char *srv, long srvlen, int flags)
{
	char *trans;
	int r;

	trans = "tcp";
	if(flags & NI_DGRAM)
		trans = "udp";

	if(flags & NI_NUMERICSERV || getport(trans, port, srv, srvlen) < 0)
		snprintf(srv, srvlen, "%d", port);

	/* require name even if not returning it */
	if(flags & NI_NAMEREQD){
		r = getname(af, addr, host, hostlen, flags);
		if(r < 0)
			return r;
	}
	if(flags & NI_NUMERICHOST){
		if(inet_ntop(af, addr, host, hostlen) == nil)
			return EAI_SYSTEM;
		return 0;
	}
	if(getname(af, addr, host, hostlen, flags) == 0)
		return 0;
	return 0;
}

int
getnameinfo(const struct sockaddr *sa, int len, char *host, long hostlen, char *srv, long srvlen, int flags)
{
	char fakehost[64], fakesrv[16];
	struct sockaddr_in *in;
	struct sockaddr_in6 *in6;

	if(host != nil && hostlen != 0)
		*host = 0;
	else{
		host = fakehost;
		hostlen = sizeof fakehost;
	}
	if(srv != nil && hostlen != 0)
		*srv = 0;
	else{
		srv = fakesrv;
		srvlen = sizeof fakesrv;
	}

	switch(sa->sa_family){
	default:
		return EAI_SOCKTYPE;
	case AF_INET:
		if(len < sizeof *in)
			return EAI_OVERFLOW;
		in = (struct sockaddr_in*)sa;
		return afhinfo(AF_INET, &in->sin_addr,  ntohs(in->sin_port),
			host, hostlen, srv, srvlen, flags);
	case AF_INET6:
		if(len < sizeof *in6)
			return EAI_OVERFLOW;
		in6 = (struct sockaddr_in6*)sa;
		return afhinfo(AF_INET6, &in6->sin6_addr,  ntohs(in6->sin6_port),
			host, hostlen, srv, srvlen, flags);
	}
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.