diff options
author | rsc <devnull@localhost> | 2003-11-23 18:12:54 +0000 |
---|---|---|
committer | rsc <devnull@localhost> | 2003-11-23 18:12:54 +0000 |
commit | fd04aacee17b348da206c13a550dc1029669805f (patch) | |
tree | 9bdd35a25ff6e3d6e9a0171b06240a76723f922c /src/lib9/_p9dialparse.c | |
parent | 74f990ad84deb1591ddb91be4fc8152ec0c46222 (diff) | |
download | plan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.gz plan9port-fd04aacee17b348da206c13a550dc1029669805f.tar.bz2 plan9port-fd04aacee17b348da206c13a550dc1029669805f.zip |
Various additions and fixes.
Diffstat (limited to 'src/lib9/_p9dialparse.c')
-rw-r--r-- | src/lib9/_p9dialparse.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/src/lib9/_p9dialparse.c b/src/lib9/_p9dialparse.c new file mode 100644 index 00000000..93c98425 --- /dev/null +++ b/src/lib9/_p9dialparse.c @@ -0,0 +1,151 @@ +#include <u.h> +#include <libc.h> + +#include <netdb.h> +#include <sys/un.h> + +static char *nets[] = { "tcp", "udp", nil }; +#define CLASS(p) ((*(uchar*)(p))>>6) + +static int +parseip(char *host, u32int *pip) +{ + uchar addr[4]; + int x, i; + char *p; + + p = host; + for(i=0; i<4 && *p; i++){ + x = strtoul(p, &p, 0); + if(x < 0 || x >= 256) + return -1; + if(*p != '.' && *p != 0) + return -1; + if(*p == '.') + p++; + addr[i] = x; + } + + switch(CLASS(addr)){ + case 0: + case 1: + if(i == 3){ + addr[3] = addr[2]; + addr[2] = addr[1]; + addr[1] = 0; + }else if(i == 2){ + addr[3] = addr[1]; + addr[2] = 0; + addr[1] = 0; + }else if(i != 4) + return -1; + break; + case 2: + if(i == 3){ + addr[3] = addr[2]; + addr[2] = 0; + }else if(i != 4) + return -1; + break; + } + *pip = *(u32int*)addr; + return 0; +} + +int +_p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport) +{ + char *net, *host, *port, *e; + int i; + struct servent *se; + struct hostent *he; + struct sockaddr_un *sun; + + if(strncmp(addr, "/net/", 5) == 0) + addr += 5; + + 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 > sizeof sun->sun_path){ + werrstr("unix socket name too long"); + return -1; + } + *punix = host; + *pnet = "unix"; + *phost = 0; + *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){ + werrstr("bad network %s!%s!%s", net, host, port); + return -1; + } + + /* translate host */ + if(strcmp(host, "*") == 0) + *phost = 0; + else if(parseip(host, phost) == 0) + {} + else if((he = gethostbyname(host)) != nil) + *phost = *(u32int*)(he->h_addr); + 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 0; + } + } + werrstr("unknown service %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 0; + } + + if((se = getservbyname(port, net)) != nil){ + *pport = ntohs(se->s_port); + return 0; + } + werrstr("unknown service %s", port); + return -1; +} |