#include #define NOPLAN9DEFINES #include #include #include #include #include #include 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 int setport(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; } int p9dialparse(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 > sizeof ((struct sockaddr_un*)ss)->sun_path){ werrstr("unix socket name too long"); return -1; } *punix = host; *pnet = "unix"; ss->ss_family = AF_UNIX; strcpy(((struct sockaddr_un*)ss)->sun_path, host); *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; is_port); return setport(ss, *pport); } werrstr("unknown service %s!*!%s", net, port); return -1; }