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