plan9port

[fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port # fast
git clone https://src.adamsgaard.dk/plan9port.git # slow
Log | Files | Refs | README | LICENSE Back to index

_p9dialparse.c (4145B)


      1 #include <u.h>
      2 #define NOPLAN9DEFINES
      3 #include <libc.h>
      4 
      5 #include <sys/types.h>
      6 #include <sys/socket.h>
      7 #include <netdb.h>
      8 #include <sys/un.h>
      9 #include <netinet/in.h>
     10 
     11 static char *nets[] = { "tcp", "udp", nil };
     12 #define CLASS(p) ((*(uchar*)(p))>>6)
     13 
     14 static struct {
     15 	char *net;
     16 	char *service;
     17 	int port;
     18 } porttbl[] = {
     19 	"tcp",	"9fs",	564,
     20 	"tcp",	"whoami",	565,
     21 	"tcp",	"guard",	566,
     22 	"tcp",	"ticket",	567,
     23 	"tcp",	"exportfs",	17007,
     24 	"tcp",	"rexexec",	17009,
     25 	"tcp",	"ncpu",	17010,
     26 	"tcp",	"cpu",	17013,
     27 	"tcp",	"venti",	17034,
     28 	"tcp",	"wiki",	17035,
     29 	"tcp",	"secstore",	5356,
     30 	"udp",	"dns",	53,
     31 	"tcp",	"dns",	53,
     32 };
     33 
     34 static int
     35 setport(struct sockaddr_storage *ss, int port)
     36 {
     37 	switch(ss->ss_family){
     38 	case AF_INET:
     39 		((struct sockaddr_in*)ss)->sin_port = htons(port);
     40 		break;
     41 	case AF_INET6:
     42 		((struct sockaddr_in6*)ss)->sin6_port = htons(port);
     43 		break;
     44 	default:
     45 		errstr("unknown protocol family %d", ss->ss_family);
     46 		return -1;
     47 	}
     48 	return 0;
     49 }
     50 
     51 int
     52 p9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport)
     53 {
     54 	char *net, *host, *port, *e;
     55 	int i;
     56 	struct servent *se;
     57 	struct hostent *he;
     58 	struct sockaddr_storage *ss;
     59 	struct addrinfo *result;
     60 
     61 	ss = phost;
     62 
     63 	memset(ss, 0, sizeof *ss);
     64 
     65 	*punix = nil;
     66 	net = addr;
     67 	if((host = strchr(net, '!')) == nil){
     68 		werrstr("malformed address");
     69 		return -1;
     70 	}
     71 	*host++ = 0;
     72 	if((port = strchr(host, '!')) == nil){
     73 		if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
     74 		Unix:
     75 			if(strlen(host)+1 > sizeof ((struct sockaddr_un*)ss)->sun_path){
     76 				werrstr("unix socket name too long");
     77 				return -1;
     78 			}
     79 			*punix = host;
     80 			*pnet = "unix";
     81 			ss->ss_family = AF_UNIX;
     82 			strcpy(((struct sockaddr_un*)ss)->sun_path, host);
     83 			*pport = 0;
     84 			return 0;
     85 		}
     86 		werrstr("malformed address");
     87 		return -1;
     88 	}
     89 	*port++ = 0;
     90 
     91 	if(*host == 0){
     92 		werrstr("malformed address (empty host)");
     93 		return -1;
     94 	}
     95 	if(*port == 0){
     96 		werrstr("malformed address (empty port)");
     97 		return -1;
     98 	}
     99 
    100 	if(strcmp(net, "unix") == 0)
    101 		goto Unix;
    102 
    103 	if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){
    104 		werrstr("bad network %s!%s!%s", net, host, port);
    105 		return -1;
    106 	}
    107 
    108 	/* translate host */
    109 	if(strcmp(host, "*") == 0){
    110 		ss->ss_family = AF_INET6;
    111 		((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any;
    112 	}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){
    113 		ss->ss_family = he->h_addrtype;
    114 		switch(ss->ss_family){
    115 		case AF_INET:
    116 			((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list);
    117 			break;
    118 		case AF_INET6:
    119 			((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list);
    120 			break;
    121 		default:
    122 			errstr("unknown protocol family %d", ss->ss_family);
    123 			return -1;
    124 		}
    125 	}else if(getaddrinfo(host, NULL, NULL, &result) == 0) {
    126 		switch (result->ai_family) {
    127 		case AF_INET:
    128 			memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen);
    129 			break;
    130 		case AF_INET6:
    131 			memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen);
    132 			break;
    133 		default:
    134 			errstr("unknown protocol family %d", ss->ss_family);
    135 			return -1;
    136 		}
    137 	}else{
    138 		werrstr("unknown host %s", host);
    139 		return -1;
    140 	}
    141 
    142 	/* translate network and port; should return list rather than first */
    143 	if(strcmp(net, "net") == 0){
    144 		for(i=0; nets[i]; i++){
    145 			if((se = getservbyname(port, nets[i])) != nil){
    146 				*pnet = nets[i];
    147 				*pport = ntohs(se->s_port);
    148 				return setport(ss, *pport);
    149 			}
    150 		}
    151 	}
    152 
    153 	for(i=0; i<nelem(porttbl); i++){
    154 		if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)
    155 		if(strcmp(porttbl[i].service, port) == 0){
    156 			*pnet = porttbl[i].net;
    157 			*pport = porttbl[i].port;
    158 			return setport(ss, *pport);
    159 		}
    160 	}
    161 
    162 	if(strcmp(net, "net") == 0){
    163 		werrstr("unknown service net!*!%s", port);
    164 		return -1;
    165 	}
    166 
    167 	if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
    168 		werrstr("unknown network %s", net);
    169 		return -1;
    170 	}
    171 
    172 	*pnet = net;
    173 	i = strtol(port, &e, 0);
    174 	if(*e == 0){
    175 		*pport = i;
    176 		return setport(ss, *pport);
    177 	}
    178 
    179 	if((se = getservbyname(port, net)) != nil){
    180 		*pport = ntohs(se->s_port);
    181 		return setport(ss, *pport);
    182 	}
    183 	werrstr("unknown service %s!*!%s", net, port);
    184 	return -1;
    185 }