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