]> git.lizzy.rs Git - plan9front.git/blob - sys/src/ape/lib/bsd/getaddrinfo.c
audiohda: fix syntax error
[plan9front.git] / sys / src / ape / lib / bsd / getaddrinfo.c
1 /* posix */
2 #include <sys/types.h>
3 #include <unistd.h>
4 #include <stdlib.h>
5 #include <stdio.h>
6 #include <fcntl.h>
7 #include <string.h>
8 #include <errno.h>
9
10 /* bsd extensions */
11 #include <sys/uio.h>
12 #include <sys/socket.h>
13 #include <netinet/in.h>
14 #include <netdb.h>
15
16 #include "priv.h"
17
18 /* for malloc/free */
19 #include <stdlib.h>
20
21 void
22 freeaddrinfo(struct addrinfo *res)
23 {
24         struct addrinfo *info;
25
26         while((info = res) != 0){
27                 res = res->ai_next;
28                 free(info->ai_canonname);
29                 free(info->ai_addr);
30                 free(info);
31         }
32 }
33
34 static int
35 sockfamily(char *addr)
36 {
37         if(strchr(addr, ':') != 0)
38                 return AF_INET6;
39         else
40                 return AF_INET;
41 }
42
43 static int
44 sockproto(char *proto)
45 {
46         if(strcmp(proto, "tcp") == 0)
47                 return SOCK_STREAM;
48         if(strcmp(proto, "udp") == 0)
49                 return SOCK_DGRAM;
50         if(strcmp(proto, "il") == 0)
51                 return SOCK_RDM;
52         return 0;
53 }
54
55 static int
56 filladdrinfo(char *s, struct addrinfo *a, struct addrinfo *h)
57 {
58         struct sockaddr sa;
59         char *p, *q;
60
61         if(*s != '/')
62                 return 1;
63         if((q = strchr(s, ' ')) == 0)
64                 return 1;
65         while(*q == ' ')
66                 *q++ = 0;
67         if((p = strrchr(s+1, '/')) == 0)
68                 return 1;
69         *p = 0;
70         if((p = strrchr(s+1, '/')) == 0)
71                 return 1;
72         *p++ = 0;
73         if(*p == 0)
74                 return 1;
75
76         if((a->ai_socktype = sockproto(p)) == 0)
77                 return 1;
78         if((p = strchr(q, '!')) != 0){
79                 *p++ = 0;
80                 a->ai_family = sockfamily(q);
81         } else{
82                 p = q;
83                 q = 0;
84                 if((a->ai_family = h->ai_family) == 0)
85                         a->ai_family = AF_INET;
86         }
87         if((a->ai_socktype == SOCK_RDM || h->ai_socktype != 0)
88         && (a->ai_socktype != h->ai_socktype))
89                 return 1;
90         if(h->ai_family != 0 && a->ai_family != h->ai_family)
91                 return 1;
92         if(_sock_inaddr(a->ai_family, q, p, &sa, &a->ai_addrlen) <= 0)
93                 return 1;
94         if((a->ai_addr = malloc(a->ai_addrlen)) == 0)
95                 return EAI_MEMORY;
96         memmove(a->ai_addr, &sa, a->ai_addrlen);
97         return 0;
98 }
99
100 int
101 getaddrinfo(char *node, char *serv, struct addrinfo *hints, struct addrinfo **res)
102 {
103         static struct addrinfo nohints;
104         struct addrinfo *a, *head, **tail;
105         char buf[1024], *proto;
106         int n, fd, err;
107
108         if(res != 0)
109                 *res = 0;
110
111         if(hints == 0)
112                 hints = &nohints;
113
114         proto = "net";
115         switch(hints->ai_family){
116         default:
117                 return EAI_FAMILY;
118         case AF_INET:
119         case AF_INET6:
120                 switch(hints->ai_socktype){
121                 default:
122                         return EAI_SOCKTYPE;
123                 case SOCK_STREAM:
124                         proto = "tcp";
125                         break;
126                 case SOCK_DGRAM:
127                         proto = "udp";
128                         break;
129                 case SOCK_RDM:
130                         proto = "il";
131                         break;
132                 case 0:
133                         break;
134                 }
135                 break;
136         case AF_UNSPEC:
137                 break;
138         }
139         if(serv == 0){
140                 if(node == 0)
141                         return EAI_NONAME;
142                 serv = "0";
143         }
144         if(node == 0){
145                 if(hints->ai_flags & AI_PASSIVE)
146                         node = "*";
147                 else if(hints->ai_family == AF_INET6)
148                         node = "::1";
149                 else
150                         node = "127.0.0.1";
151         }
152
153         if((fd = open("/net/cs", O_RDWR)) < 0)
154                 return EAI_SYSTEM;
155
156         snprintf(buf, sizeof(buf), "%s!%s!%s", proto, node, serv);
157         n = strlen(buf);
158         if(write(fd, buf, n) != n){
159                 close(fd);
160                 return EAI_AGAIN;
161         }
162         lseek(fd, 0, 0);
163
164         head = 0;
165         tail = &head;
166         for(;;){
167                 if((n = read(fd, buf, sizeof(buf)-1)) <= 0)
168                         break;
169                 buf[n] = '\0';
170                 if((a = malloc(sizeof(*a))) == 0){
171                         freeaddrinfo(head);
172                         close(fd);
173                         return EAI_MEMORY;
174                 }
175                 memset(a, 0, sizeof(*a));
176                 if((err = filladdrinfo(buf, a, hints)) != 0){
177                         freeaddrinfo(a);
178                         if(err < 0){
179                                 freeaddrinfo(head);
180                                 close(fd);
181                                 return err;
182                         }
183                 } else {
184                         *tail = a;
185                         tail = &a->ai_next;
186                 }
187         }
188         close(fd);
189
190         if(head == 0)
191                 return EAI_NODATA;
192
193         if((hints->ai_flags & AI_CANONNAME) != 0 && (hints->ai_flags & AI_NUMERICHOST) == 0){
194                 n = _sock_ipattr(node);
195                 if(n != Tsys && n != Tdom){
196                         if(getnameinfo(head->ai_addr, head->ai_addrlen, buf, sizeof(buf), 0, 0, NI_NAMEREQD) == 0)
197                                 node = buf;
198                         else
199                                 node = 0;
200                 }
201                 if(node != 0){
202                         n = strlen(node)+1;
203                         if((head->ai_canonname = malloc(n)) == 0){
204                                 freeaddrinfo(head);
205                                 return EAI_MEMORY;
206                         }
207                         memmove(head->ai_canonname, node, n);
208                 }
209         }
210
211         if(res != 0)
212                 *res = head;
213         else
214                 freeaddrinfo(head);
215
216         return 0;
217 }