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