akaros/kern/src/net/dial.c
<<
>>
Prefs
   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
  41typedef struct DS DS;
  42
  43static int call(char *cp, char *cp1, DS * DS);
  44static int csdial(DS * DS);
  45static void _dial_string_parse(char *cp, DS * DS);
  46static int nettrans(char *cp, char *cp1, int na, char *cp2, int i);
  47
  48enum {
  49        Maxstring = 128,
  50};
  51
  52struct 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. */
  63static 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 */
  71int 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);
 113out:
 114        kfree(err);
 115        kfree(alterr);
 116        return rv;
 117}
 118
 119static 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);
 178out:
 179        kfree(buf);
 180        kfree(clone);
 181        kfree(err);
 182        kfree(besterr);
 183        return rv;
 184}
 185
 186static 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;
 250out:
 251        kfree(name);
 252        kfree(data);
 253        kfree(err);
 254
 255        return retval;
 256}
 257
 258/*
 259 *  parse a dial string
 260 */
 261static 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 */
 290int 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 */
 345int 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 */
 385static int identtrans(char *netdir, char *addr, char *naddr, int na, char *file,
 386                      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 */
 406static 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}
 464