Blob


1 #include <u.h>
2 #define NOPLAN9DEFINES
3 #include <libc.h>
5 #include <sys/types.h>
6 #include <sys/socket.h>
7 #include <netdb.h>
8 #include <sys/un.h>
9 #include <netinet/in.h>
11 static char *nets[] = { "tcp", "udp", nil };
12 #define CLASS(p) ((*(uchar*)(p))>>6)
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 };
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 }
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;
61 ss = phost;
63 memset(ss, 0, sizeof *ss);
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;
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 }
100 if(strcmp(net, "unix") == 0)
101 goto Unix;
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;
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;
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;
137 }else{
138 werrstr("unknown host %s", host);
139 return -1;
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);
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);
162 if(strcmp(net, "net") == 0){
163 werrstr("unknown service net!*!%s", port);
164 return -1;
167 if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
168 werrstr("unknown network %s", net);
169 return -1;
172 *pnet = net;
173 i = strtol(port, &e, 0);
174 if(*e == 0){
175 *pport = i;
176 return setport(ss, *pport);
179 if((se = getservbyname(port, net)) != nil){
180 *pport = ntohs(se->s_port);
181 return setport(ss, *pport);
183 werrstr("unknown service %s!*!%s", net, port);
184 return -1;