_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 }