182 lines · 3.9 KB · C
RawDownload
#include <u.h>#define WINVER 0x0501#include <mingw32.h>#include <ws2tcpip.h>#define NOPLAN9DEFINES#include <libc.h> #include <sys/types.h> static char *nets[] = { "tcp", "udp", nil };#define CLASS(p) ((*(uchar*)(p))>>6) static struct {	char *net;	char *service;	int port;} porttbl[] = {	"tcp",	"9fs",	564,	"tcp",	"whoami",	565,	"tcp",	"guard",	566,	"tcp",	"ticket",	567,	"tcp",	"exportfs",	17007,	"tcp",	"rexexec",	17009,	"tcp",	"ncpu",	17010,	"tcp",	"cpu",	17013,	"tcp",	"venti",	17034,	"tcp",	"wiki",	17035,	"tcp",	"secstore",	5356,	"udp",	"dns",	53,	"tcp",	"dns",	53,}; static intsetport(struct sockaddr_storage *ss, int port){	switch(ss->ss_family){	case AF_INET:		((struct sockaddr_in*)ss)->sin_port = htons(port);		break;	case AF_INET6:		((struct sockaddr_in6*)ss)->sin6_port = htons(port);		break;	default:		errstr("unknown protocol family %d", ss->ss_family);		return -1;	}	return 0;} intp9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport){	char *net, *host, *port, *e;	int i;	struct servent *se;	struct hostent *he;	struct sockaddr_storage *ss;	struct addrinfo *result; 	ss = phost; 	memset(ss, 0, sizeof *ss); 	*punix = nil;	net = addr;	if((host = strchr(net, '!')) == nil){		werrstr("malformed address");		return -1;	}	*host++ = 0;	if((port = strchr(host, '!')) == nil){		if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){		Unix:			if(strlen(host)+1 > 128){				werrstr("unix socket name too long");				return -1;			}			*punix = host;			*pnet = "unix";			*pport = 0;			return 0;		}		werrstr("malformed address");		return -1;	}	*port++ = 0; 	if(*host == 0){		werrstr("malformed address (empty host)");		return -1;	}	if(*port == 0){		werrstr("malformed address (empty port)");		return -1;	} 	if(strcmp(net, "unix") == 0)		goto Unix; 	if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){		werrstr("bad network %s!%s!%s", net, host, port);		return -1;	} 	/* translate host */	if(strcmp(host, "*") == 0){		ss->ss_family = AF_INET6;		((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any;	}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){		ss->ss_family = he->h_addrtype;		switch(ss->ss_family){		case AF_INET:			((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list);			break;		case AF_INET6:			((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list);			break;		default:			errstr("unknown protocol family %d", ss->ss_family);			return -1;		}	}else if(getaddrinfo(host, NULL, NULL, &result) == 0) {		switch (result->ai_family) {		case AF_INET:			memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen);			break;		case AF_INET6:			memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen);			break;		default:			errstr("unknown protocol family %d", ss->ss_family);			return -1;		}	}else{		werrstr("unknown host %s", host);		return -1;	} 	/* translate network and port; should return list rather than first */	if(strcmp(net, "net") == 0){		for(i=0; nets[i]; i++){			if((se = getservbyname(port, nets[i])) != nil){				*pnet = nets[i];				*pport = ntohs(se->s_port);				return setport(ss, *pport);			}		}	} 	for(i=0; i<nelem(porttbl); i++){		if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)		if(strcmp(porttbl[i].service, port) == 0){			*pnet = porttbl[i].net;			*pport = porttbl[i].port;			return setport(ss, *pport);		}	} 	if(strcmp(net, "net") == 0){		werrstr("unknown service net!*!%s", port);		return -1;	} 	if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){		werrstr("unknown network %s", net);		return -1;	} 	*pnet = net;	i = strtol(port, &e, 0);	if(*e == 0){		*pport = i;		return setport(ss, *pport);	} 	if((se = getservbyname(port, net)) != nil){		*pport = ntohs(se->s_port);		return setport(ss, *pport);	}	werrstr("unknown service %s!*!%s", net, port);	return -1;}