aboutsummaryrefslogtreecommitdiff
path: root/src/lib9/_p9dialparse.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib9/_p9dialparse.c')
-rw-r--r--src/lib9/_p9dialparse.c151
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;
+}