vfs: Remove KFS, blockdev and devfs
[akaros.git] / kern / src / net / dial.c
1 /* Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
2  * Portions Copyright © 1997-1999 Vita Nuova Limited
3  * Portions Copyright © 2000-2007 Vita Nuova Holdings Limited
4  *                                (www.vitanuova.com)
5  * Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
6  *
7  * Modified for the Akaros operating system:
8  * Copyright (c) 2013-2014 The Regents of the University of California
9  * Copyright (c) 2013-2015 Google Inc.
10  *
11  * Permission is hereby granted, free of charge, to any person obtaining a copy
12  * of this software and associated documentation files (the "Software"), to deal
13  * in the Software without restriction, including without limitation the rights
14  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15  * copies of the Software, and to permit persons to whom the Software is
16  * furnished to do so, subject to the following conditions:
17  *
18  * The above copyright notice and this permission notice shall be included in
19  * all copies or substantial portions of the Software.
20  *
21  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27  * SOFTWARE. */
28
29 #include <vfs.h>
30 #include <slab.h>
31 #include <kmalloc.h>
32 #include <kref.h>
33 #include <string.h>
34 #include <stdio.h>
35 #include <assert.h>
36 #include <error.h>
37 #include <cpio.h>
38 #include <pmap.h>
39 #include <smp.h>
40 #include <net/ip.h>
41
42 typedef struct DS DS;
43
44 static int call(char *cp, char *cp1, DS * DS);
45 static int csdial(DS * DS);
46 static void _dial_string_parse(char *cp, DS * DS);
47 static int nettrans(char *cp, char *cp1, int na, char *cp2, int i);
48
49 enum {
50         Maxstring = 128,
51 };
52
53 struct DS {
54         char buf[Maxstring];            /* dist string */
55         char *netdir;
56         char *proto;
57         char *rem;
58         char *local;                            /* other args */
59         char *dir;
60         int *cfdp;
61 };
62
63 /* only used here for now. */
64 static void kerrstr(void *err, int len)
65 {
66         strlcpy(err, current_errstr(), len);
67 }
68
69 /*
70  *  the dialstring is of the form '[/net/]proto!dest'
71  */
72 int kdial(char *dest, char *local, char *dir, int *cfdp)
73 {
74         DS ds;
75         int rv;
76         char *err, *alterr;
77
78         err = kmalloc(ERRMAX, MEM_WAIT);
79         alterr = kmalloc(ERRMAX, MEM_WAIT);
80
81         ds.local = local;
82         ds.dir = dir;
83         ds.cfdp = cfdp;
84
85         _dial_string_parse(dest, &ds);
86         if (ds.netdir) {
87                 rv = csdial(&ds);
88                 goto out;
89         }
90
91         ds.netdir = "/net";
92         rv = csdial(&ds);
93         if (rv >= 0)
94                 goto out;
95
96         err[0] = 0;
97         strlcpy(err, current_errstr(), ERRMAX);
98         if (strstr(err, "refused") != 0) {
99                 goto out;
100         }
101
102         ds.netdir = "/net.alt";
103         rv = csdial(&ds);
104         if (rv >= 0)
105                 goto out;
106
107         alterr[0] = 0;
108         kerrstr(alterr, ERRMAX);
109
110         if (strstr(alterr, "translate") || strstr(alterr, "does not exist"))
111                 kerrstr(err, ERRMAX);
112         else
113                 kerrstr(alterr, ERRMAX);
114 out:
115         kfree(err);
116         kfree(alterr);
117         return rv;
118 }
119
120 static int csdial(DS * ds)
121 {
122         int n, fd, rv = -1;
123         char *p, *buf, *clone, *err, *besterr;
124
125         buf = kmalloc(Maxstring, MEM_WAIT);
126         clone = kmalloc(Maxpath, MEM_WAIT);
127         err = kmalloc(ERRMAX, MEM_WAIT);
128         besterr = kmalloc(ERRMAX, MEM_WAIT);
129         /*
130          *  open connection server
131          */
132         snprintf(buf, Maxstring, "%s/cs", ds->netdir);
133         fd = sysopen(buf, O_RDWR);
134         if (fd < 0) {
135                 /* no connection server, don't translate */
136                 snprintf(clone, Maxpath, "%s/%s/clone", ds->netdir, ds->proto);
137                 rv = call(clone, ds->rem, ds);
138                 goto out;
139         }
140
141         /*
142          *  ask connection server to translate
143          */
144         snprintf(buf, Maxstring, "%s!%s", ds->proto, ds->rem);
145         if (syswrite(fd, buf, strlen(buf)) < 0) {
146                 kerrstr(err, ERRMAX);
147                 sysclose(fd);
148                 set_errstr("%s (%s)", err, buf);
149                 goto out;
150         }
151
152         /*
153          *  loop through each address from the connection server till
154          *  we get one that works.
155          */
156         *besterr = 0;
157         strlcpy(err, "csdial() connection reset", ERRMAX);
158         sysseek(fd, 0, 0);
159         while ((n = sysread(fd, buf, Maxstring - 1)) > 0) {
160                 buf[n] = 0;
161                 p = strchr(buf, ' ');
162                 if (p == 0)
163                         continue;
164                 *p++ = 0;
165                 rv = call(buf, p, ds);
166                 if (rv >= 0)
167                         break;
168                 err[0] = 0;
169                 kerrstr(err, ERRMAX);
170                 if (strstr(err, "does not exist") == 0)
171                         memmove(besterr, err, ERRMAX);
172         }
173         sysclose(fd);
174
175         if (rv < 0 && *besterr)
176                 kerrstr(besterr, ERRMAX);
177         else
178                 kerrstr(err, ERRMAX);
179 out:
180         kfree(buf);
181         kfree(clone);
182         kfree(err);
183         kfree(besterr);
184         return rv;
185 }
186
187 static int call(char *clone, char *dest, DS * ds)
188 {
189         int fd, cfd, n, retval;
190         char *name, *data, *err, *p;
191
192         name = kmalloc(Maxpath, MEM_WAIT);
193         data = kmalloc(Maxpath, MEM_WAIT);
194         err = kmalloc(ERRMAX, MEM_WAIT);
195
196         cfd = sysopen(clone, O_RDWR);
197         if (cfd < 0) {
198                 kerrstr(err, ERRMAX);
199                 set_errstr("%s (%s)", err, clone);
200                 retval = -1;
201                 goto out;
202         }
203
204         /* get directory name */
205         n = sysread(cfd, name, Maxpath - 1);
206         if (n < 0) {
207                 kerrstr(err, ERRMAX);
208                 sysclose(cfd);
209                 set_errstr("read %s: %s", clone, err);
210                 retval = -1;
211                 goto out;
212         }
213         name[n] = 0;
214         for (p = name; *p == ' '; p++) ;
215         snprintf(name, Maxpath, "%ld", strtoul(p, 0, 0));
216         p = strrchr(clone, '/');
217         *p = 0;
218         if (ds->dir)
219                 snprintf(ds->dir, NETPATHLEN, "%s/%s", clone, name);
220         snprintf(data, Maxpath, "%s/%s/data", clone, name);
221
222         /* connect */
223         if (ds->local)
224                 snprintf(name, Maxpath, "connect %s %s", dest, ds->local);
225         else
226                 snprintf(name, Maxpath, "connect %s", dest);
227         if (syswrite(cfd, name, strlen(name)) < 0) {
228                 err[0] = 0;
229                 kerrstr(err, ERRMAX);
230                 sysclose(cfd);
231                 set_errstr("%s (%s)", err, name);
232                 retval = -1;
233                 goto out;
234         }
235
236         /* open data connection */
237         fd = sysopen(data, O_RDWR);
238         if (fd < 0) {
239                 err[0] = 0;
240                 kerrstr(err, ERRMAX);
241                 set_errstr("%s (%s)", err, data);
242                 sysclose(cfd);
243                 retval = -1;
244                 goto out;
245         }
246         if (ds->cfdp)
247                 *ds->cfdp = cfd;
248         else
249                 sysclose(cfd);
250         retval = fd;
251 out:
252         kfree(name);
253         kfree(data);
254         kfree(err);
255
256         return retval;
257 }
258
259 /*
260  *  parse a dial string
261  */
262 static void _dial_string_parse(char *str, DS * ds)
263 {
264         char *p, *p2;
265
266         strlcpy(ds->buf, str, Maxstring);
267
268         p = strchr(ds->buf, '!');
269         if (p == 0) {
270                 ds->netdir = 0;
271                 ds->proto = "net";
272                 ds->rem = ds->buf;
273         } else {
274                 if (*ds->buf != '/' && *ds->buf != '#') {
275                         ds->netdir = 0;
276                         ds->proto = ds->buf;
277                 } else {
278                         for (p2 = p; *p2 != '/'; p2--) ;
279                         *p2++ = 0;
280                         ds->netdir = ds->buf;
281                         ds->proto = p2;
282                 }
283                 *p = 0;
284                 ds->rem = p + 1;
285         }
286 }
287
288 /*
289  *  announce a network service.
290  */
291 int kannounce(char *addr, char *dir, size_t dirlen)
292 {
293         int ctl, n, m;
294         char buf[NETPATHLEN];
295         char buf2[Maxpath];
296         char netdir[NETPATHLEN];
297         char naddr[Maxpath];
298         char *cp;
299
300         /*
301          *  translate the address
302          */
303         if (nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
304                 return -1;
305
306         /*
307          * get a control channel
308          */
309         ctl = sysopen(netdir, O_RDWR);
310         if (ctl < 0)
311                 return -1;
312         cp = strrchr(netdir, '/');
313         *cp = 0;
314
315         /*
316          *  find out which line we have
317          */
318         n = snprintf(buf, sizeof(buf), "%.*s/", sizeof buf, netdir);
319         m = sysread(ctl, &buf[n], sizeof(buf) - n - 1);
320         if (m <= 0) {
321                 sysclose(ctl);
322                 return -1;
323         }
324         buf[n + m] = 0;
325
326         /*
327          *  make the call
328          */
329         n = snprintf(buf2, sizeof buf2, "announce %s", naddr);
330         if (syswrite(ctl, buf2, n) != n) {
331                 sysclose(ctl);
332                 return -1;
333         }
334
335         /*
336          *  return directory etc.
337          */
338         if (dir)
339                 strlcpy(dir, buf, dirlen);
340         return ctl;
341 }
342
343 /*
344  *  listen for an incoming call
345  */
346 int klisten(char *dir, char *newdir, size_t newdirlen)
347 {
348         int ctl, n, m;
349         char buf[NETPATHLEN + 1];
350         char *cp;
351
352         /*
353          *  open listen, wait for a call
354          */
355         snprintf(buf, sizeof buf, "%s/listen", dir);
356         ctl = sysopen(buf, O_RDWR);
357         if (ctl < 0)
358                 return -1;
359
360         /*
361          *  find out which line we have
362          */
363         strlcpy(buf, dir, sizeof(buf));
364         cp = strrchr(buf, '/');
365         *++cp = 0;
366         n = cp - buf;
367         m = sysread(ctl, cp, sizeof(buf) - n - 1);
368         if (m <= 0) {
369                 sysclose(ctl);
370                 return -1;
371         }
372         buf[n + m] = 0;
373
374         /*
375          *  return directory etc.
376          */
377         if (newdir)
378                 strlcpy(newdir, buf, newdirlen);
379         return ctl;
380
381 }
382
383 /*
384  *  perform the identity translation (in case we can't reach cs)
385  */
386 static int
387 identtrans(char *netdir, char *addr, char *naddr, int na, char *file, int nf)
388 {
389         char proto[Maxpath];
390         char *p;
391
392         /* parse the protocol */
393         strlcpy(proto, addr, sizeof(proto));
394         p = strchr(proto, '!');
395         if (p)
396                 *p++ = 0;
397
398         snprintf(file, nf, "%s/%s/clone", netdir, proto);
399         strlcpy(naddr, p, na);
400
401         return 1;
402 }
403
404 /*
405  *  call up the connection server and get a translation
406  */
407 static int nettrans(char *addr, char *naddr, int na, char *file, int nf)
408 {
409         int i, fd;
410         char buf[Maxpath];
411         char netdir[NETPATHLEN];
412         char *p, *p2;
413         long n;
414
415         /*
416          *  parse, get network directory
417          */
418         p = strchr(addr, '!');
419         if (p == 0) {
420                 set_errstr("bad dial string: %s", addr);
421                 return -1;
422         }
423         if (*addr != '/') {
424                 strlcpy(netdir, "/net", sizeof(netdir));
425         } else {
426                 for (p2 = p; *p2 != '/'; p2--) ;
427                 i = p2 - addr;
428                 if (i == 0 || i >= sizeof(netdir)) {
429                         set_errstr("bad dial string: %s", addr);
430                         return -1;
431                 }
432                 strlcpy(netdir, addr, i + 1);
433                 addr = p2 + 1;
434         }
435
436         /*
437          *  ask the connection server
438          */
439         snprintf(buf, sizeof(buf), "%s/cs", netdir);
440         fd = sysopen(buf, O_RDWR);
441         if (fd < 0)
442                 return identtrans(netdir, addr, naddr, na, file, nf);
443         if (syswrite(fd, addr, strlen(addr)) < 0) {
444                 sysclose(fd);
445                 return -1;
446         }
447         sysseek(fd, 0, 0);
448         n = sysread(fd, buf, sizeof(buf) - 1);
449         sysclose(fd);
450         if (n <= 0)
451                 return -1;
452         buf[n] = 0;
453
454         /*
455          *  parse the reply
456          */
457         p = strchr(buf, ' ');
458         if (p == 0)
459                 return -1;
460         *p++ = 0;
461         strlcpy(naddr, p, na);
462         strlcpy(file, buf, nf);
463         return 0;
464 }