iproute.c compiles
[akaros.git] / kern / src / net / dial.c
1 // INFERNO
2 #include <vfs.h>
3 #include <kfs.h>
4 #include <slab.h>
5 #include <kmalloc.h>
6 #include <kref.h>
7 #include <string.h>
8 #include <stdio.h>
9 #include <assert.h>
10 #include <error.h>
11 #include <cpio.h>
12 #include <pmap.h>
13 #include <smp.h>
14 #include <ip.h>
15
16 typedef struct DS DS;
17
18 static int      call( char *cp, char*cp, DS*DS);
19 static int      csdial(DS*DS);
20 static void     _dial_string_parse( char *cp, DS*DS);
21 static int      nettrans( char *cp, char*cp1, int na, char*cp2, int i);
22
23 enum
24 {
25         Maxstring=      128,
26         Maxpath=        100
27 };
28
29 struct DS
30 {
31         char    buf[Maxstring];                 /* dist string */
32         char    *netdir;
33         char    *proto;
34         char    *rem;
35         char    *local;                         /* other args */
36         char    *dir;
37         int     *cfdp;
38 };
39
40 /*
41  *  the dialstring is of the form '[/net/]proto!dest'
42  */
43 int
44 kdial(char *dest, char *local, char *dir, int *cfdp)
45 {
46         DS ds;
47         int rv;
48         char err[ERRMAX], alterr[ERRMAX];
49
50         ds.local = local;
51         ds.dir = dir;
52         ds.cfdp = cfdp;
53
54         _dial_string_parse(dest, &ds);
55         if(ds.netdir)
56                 return csdial(&ds);
57
58         ds.netdir = "/net";
59         rv = csdial(&ds);
60         if(rv >= 0)
61                 return rv;
62
63         err[0] = 0;
64         kerrstr(err, sizeof err);
65         if(strstr(err, "refused") != 0){
66                 kerrstr(err, sizeof err);
67                 return rv;
68         }
69
70         ds.netdir = "/net.alt";
71         rv = csdial(&ds);
72         if(rv >= 0)
73                 return rv;
74
75         alterr[0] = 0;
76         kerrstr(alterr, sizeof err);
77
78         if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
79                 kerrstr(err, sizeof err);
80         else
81                 kerrstr(alterr, sizeof alterr);
82         return rv;
83 }
84
85 static int
86 csdial(DS *ds)
87 {
88         int n, fd, rv;
89         char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
90
91         /*
92          *  open connection server
93          */
94         snprintf(buf, sizeof(buf), "%s/cs", ds->netdir);
95         fd = sysopen(buf, ORDWR);
96         if(fd < 0){
97                 /* no connection server, don't translate */
98                 snprintf(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
99                 return call(clone, ds->rem, ds);
100         }
101
102         /*
103          *  ask connection server to translate
104          */
105         sprint(buf, "%s!%s", ds->proto, ds->rem);
106         if(kwrite(fd, buf, strlen(buf)) < 0){
107                 kerrstr(err, sizeof err);
108                 sysclose(fd);
109                 kwerrstr("%s (%s)", err, buf);
110                 return -1;
111         }
112
113         /*
114          *  loop through each address from the connection server till
115          *  we get one that works.
116          */
117         *besterr = 0;
118         strncpy(err,  Egreg, sizeof(err));
119         rv = -1;
120         kseek(fd, 0, 0);
121         while((n = sysread(fd, buf, sizeof(buf) - 1)) > 0){
122                 buf[n] = 0;
123                 p = strchr(buf, ' ');
124                 if(p == 0)
125                         continue;
126                 *p++ = 0;
127                 rv = call(buf, p, ds);
128                 if(rv >= 0)
129                         break;
130                 err[0] = 0;
131                 kerrstr(err, sizeof err);
132                 if(strstr(err, "does not exist") == 0)
133                         memmove(besterr, err, sizeof besterr);
134         }
135         sysclose(fd);
136
137         if(rv < 0 && *besterr)
138                 kerrstr(besterr, sizeof besterr);
139         else
140                 kerrstr(err, sizeof err);
141         return rv;
142 }
143
144 static int
145 call(char *clone, char *dest, DS *ds)
146 {
147         int fd, cfd, n;
148         char name[Maxpath], data[Maxpath], err[ERRMAX], *p;
149
150         cfd = sysopen(clone, ORDWR);
151         if(cfd < 0){
152                 kerrstr(err, sizeof err);
153                 kwerrstr("%s (%s)", err, clone);
154                 return -1;
155         }
156
157         /* get directory name */
158         n = sysread(cfd, name, sizeof(name)-1);
159         if(n < 0){
160                 kerrstr(err, sizeof err);
161                 sysclose(cfd);
162                 kwerrstr("read %s: %s", clone, err);
163                 return -1;
164         }
165         name[n] = 0;
166         for(p = name; *p == ' '; p++)
167                 ;
168         sprint(name, "%ld", strtoul(p, 0, 0));
169         p = strrchr(clone, '/');
170         *p = 0;
171         if(ds->dir)
172                 snprintf(ds->dir, NETPATHLEN, "%s/%s", clone, name);
173         snprintf(data, sizeof(data), "%s/%s/data", clone, name);
174
175         /* connect */
176         if(ds->local)
177                 snprintf(name, sizeof(name), "connect %s %s", dest, ds->local);
178         else
179                 snprintf(name, sizeof(name), "connect %s", dest);
180         if(kwrite(cfd, name, strlen(name)) < 0){
181                 err[0] = 0;
182                 kerrstr(err, sizeof err);
183                 sysclose(cfd);
184                 kwerrstr("%s (%s)", err, name);
185                 return -1;
186         }
187
188         /* open data connection */
189         fd = sysopen(data, ORDWR);
190         if(fd < 0){
191                 err[0] = 0;
192                 kerrstr(err, sizeof err);
193                 kwerrstr("%s (%s)", err, data);
194                 sysclose(cfd);
195                 return -1;
196         }
197         if(ds->cfdp)
198                 *ds->cfdp = cfd;
199         else
200                 sysclose(cfd);
201
202         return fd;
203 }
204
205 /*
206  *  parse a dial string
207  */
208 static void
209 _dial_string_parse(char *str, DS *ds)
210 {
211         char *p, *p2;
212
213         strncpy(ds->buf, str, Maxstring);
214         ds->buf[Maxstring-1] = 0;
215
216         p = strchr(ds->buf, '!');
217         if(p == 0) {
218                 ds->netdir = 0;
219                 ds->proto = "net";
220                 ds->rem = ds->buf;
221         } else {
222                 if(*ds->buf != '/' && *ds->buf != '#'){
223                         ds->netdir = 0;
224                         ds->proto = ds->buf;
225                 } else {
226                         for(p2 = p; *p2 != '/'; p2--)
227                                 ;
228                         *p2++ = 0;
229                         ds->netdir = ds->buf;
230                         ds->proto = p2;
231                 }
232                 *p = 0;
233                 ds->rem = p + 1;
234         }
235 }
236
237 /*
238  *  announce a network service.
239  */
240 int
241 kannounce(char *addr, char *dir)
242 {
243         int ctl, n, m;
244         char buf[NETPATHLEN];
245         char buf2[Maxpath];
246         char netdir[NETPATHLEN];
247         char naddr[Maxpath];
248         char *cp;
249
250         /*
251          *  translate the address
252          */
253         if(nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
254                 return -1;
255
256         /*
257          * get a control channel
258          */
259         ctl = sysopen(netdir, ORDWR);
260         if(ctl<0)
261                 return -1;
262         cp = strrchr(netdir, '/');
263         *cp = 0;
264
265         /*
266          *  find out which line we have
267          */
268         n = sprint(buf, "%.*s/", sizeof buf, netdir);
269         m = sysread(ctl, &buf[n], sizeof(buf)-n-1);
270         if(m <= 0){
271                 sysclose(ctl);
272                 return -1;
273         }
274         buf[n+m] = 0;
275
276         /*
277          *  make the call
278          */
279         n = snprintf(buf2, sizeof buf2, "announce %s", naddr);
280         if(kwrite(ctl, buf2, n)!=n){
281                 sysclose(ctl);
282                 return -1;
283         }
284
285         /*
286          *  return directory etc.
287          */
288         if(dir)
289                 strncpy(dir,  buf, sizeof(dir));
290         return ctl;
291 }
292
293 /*
294  *  listen for an incoming call
295  */
296 int
297 klisten(char *dir, char *newdir)
298 {
299         int ctl, n, m;
300         char buf[NETPATHLEN];
301         char *cp;
302
303         /*
304          *  open listen, wait for a call
305          */
306         snprintf(buf, sizeof buf, "%s/listen", dir);
307         ctl = sysopen(buf, ORDWR);
308         if(ctl < 0)
309                 return -1;
310
311         /*
312          *  find out which line we have
313          */
314         strncpy(buf,  dir, sizeof(buf));
315         cp = strrchr(buf, '/');
316         *++cp = 0;
317         n = cp-buf;
318         m = sysread(ctl, cp, sizeof(buf) - n - 1);
319         if(m <= 0){
320                 sysclose(ctl);
321                 return -1;
322         }
323         buf[n+m] = 0;
324
325         /*
326          *  return directory etc.
327          */
328         if(newdir)
329                 strncpy(newdir,  buf, sizeof(newdir));
330         return ctl;
331
332 }
333
334 /*
335  *  perform the identity translation (in case we can't reach cs)
336  */
337 static int
338 identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf)
339 {
340         char proto[Maxpath];
341         char *p;
342
343
344         /* parse the protocol */
345         strncpy(proto, addr, sizeof(proto));
346         proto[sizeof(proto)-1] = 0;
347         p = strchr(proto, '!');
348         if(p)
349                 *p++ = 0;
350
351         snprintf(file, nf, "%s/%s/clone", netdir, proto);
352         strncpy(naddr, p, na);
353         naddr[na-1] = 0;
354
355         return 1;
356 }
357
358 /*
359  *  call up the connection server and get a translation
360  */
361 static int
362 nettrans(char *addr, char *naddr, int na, char *file, int nf)
363 {
364         int i, fd;
365         char buf[Maxpath];
366         char netdir[NETPATHLEN];
367         char *p, *p2;
368         long n;
369
370         /*
371          *  parse, get network directory
372          */
373         p = strchr(addr, '!');
374         if(p == 0){
375                 kwerrstr("bad dial string: %s", addr);
376                 return -1;
377         }
378         if(*addr != '/'){
379                 strncpy(netdir,  "/net", sizeof(netdir));
380         } else {
381                 for(p2 = p; *p2 != '/'; p2--)
382                         ;
383                 i = p2 - addr;
384                 if(i == 0 || i >= sizeof(netdir)){
385                         kwerrstr("bad dial string: %s", addr);
386                         return -1;
387                 }
388                 strncpy(netdir, addr, i);
389                 netdir[i] = 0;
390                 addr = p2 + 1;
391         }
392
393         /*
394          *  ask the connection server
395          */
396         sprint(buf, "%s/cs", netdir);
397         fd = sysopen(buf, ORDWR);
398         if(fd < 0)
399                 return identtrans(netdir, addr, naddr, na, file, nf);
400         if(kwrite(fd, addr, strlen(addr)) < 0){
401                 sysclose(fd);
402                 return -1;
403         }
404         kseek(fd, 0, 0);
405         n = sysread(fd, buf, sizeof(buf)-1);
406         sysclose(fd);
407         if(n <= 0)
408                 return -1;
409         buf[n] = 0;
410
411         /*
412          *  parse the reply
413          */
414         p = strchr(buf, ' ');
415         if(p == 0)
416                 return -1;
417         *p++ = 0;
418         strncpy(naddr, p, na);
419         naddr[na-1] = 0;
420         strncpy(file, buf, nf);
421         file[nf-1] = 0;
422         return 0;
423 }