akaros/user/iplib/announce.c
<<
>>
Prefs
   1/*
   2 * This file is part of the UCB release of Plan 9. It is subject to the license
   3 * terms in the LICENSE file found in the top-level directory of this
   4 * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No
   5 * part of the UCB release of Plan 9, including this file, may be copied,
   6 * modified, propagated, or distributed except according to the terms contained
   7 * in the LICENSE file.
   8 */
   9#include <stdlib.h>
  10
  11#include <fcntl.h>
  12#include <iplib/iplib.h>
  13#include <parlib/parlib.h>
  14#include <signal.h>
  15#include <stdio.h>
  16#include <unistd.h>
  17
  18static int nettrans(char *, char *, int na, char *, int);
  19
  20enum {
  21        Maxpath = 256,
  22};
  23
  24/* Helper, given a net directory (translated from an addr/dialstring) by
  25 * nettrans), clones a conversation, returns the ctl, and optionally fills in
  26 * dir with the path of the directory (e.g. /net/tcp/1/).
  27 *
  28 * Returns the ctl FD, or -1 on error.  err_func is the function name to print
  29 * for error output. */
  30static int __clone9(char *netdir, char *dir, char *err_func, int flags)
  31{
  32        int ctl, n, m;
  33        char buf[Maxpath];
  34        char *cp;
  35
  36        /* get a control channel */
  37        ctl = open(netdir, O_RDWR);
  38        if (ctl < 0) {
  39                fprintf(stderr, "%s opening %s: %r\n", err_func, netdir);
  40                return -1;
  41        }
  42        cp = strrchr(netdir, '/');
  43        if (cp == NULL) {
  44                fprintf(stderr, "%s arg format %s\n", err_func, netdir);
  45                close(ctl);
  46                return -1;
  47        }
  48        *cp = 0;
  49
  50        /* find out which line we have */
  51        n = snprintf(buf, sizeof(buf), "%s/", netdir);
  52        m = read(ctl, &buf[n], sizeof(buf) - n - 1);
  53        if (m <= 0) {
  54                fprintf(stderr, "%s reading %s: %r\n", err_func, netdir);
  55                close(ctl);
  56                return -1;
  57        }
  58        buf[n + m] = 0;
  59
  60        /* return directory etc. */
  61        if (dir) {
  62                strncpy(dir, buf, NETPATHLEN);
  63                dir[NETPATHLEN - 1] = 0;
  64        }
  65        return ctl;
  66}
  67
  68/* Clones a new network connection for a given dialstring (e.g. tcp!*!22). */
  69int clone9(char *addr, char *dir, int flags)
  70{
  71        char netdir[Maxpath];
  72        char naddr[Maxpath];
  73
  74        if (nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
  75                return -1;
  76        return __clone9(addr, dir, "clone", flags);
  77}
  78
  79/*
  80 *  announce a network service.
  81 */
  82int announce9(char *addr, char *dir, int flags)
  83{
  84        int ctl, n;
  85        char buf[Maxpath];
  86        char netdir[Maxpath];
  87        char naddr[Maxpath];
  88
  89        /*
  90         *  translate the address
  91         */
  92        if (nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
  93                return -1;
  94
  95        ctl = __clone9(netdir, dir, "announce", flags);
  96        if (ctl < 0)
  97                return -1;
  98
  99        /*
 100         *  make the call
 101         */
 102        n = snprintf(buf, sizeof(buf), "announce %s", naddr);
 103        if (write(ctl, buf, n) != n) {
 104                fprintf(stderr, "announce writing %s: %r\n", netdir);
 105                close(ctl);
 106                return -1;
 107        }
 108
 109        return ctl;
 110}
 111
 112/* Gets a conversation and bypasses the protocol layer */
 113int bypass9(char *addr, char *conv_dir, int flags)
 114{
 115        int ctl, n;
 116        char buf[Maxpath];
 117        char netdir[Maxpath];
 118        char naddr[Maxpath];
 119
 120        if (nettrans(addr, naddr, sizeof(naddr), netdir, sizeof(netdir)) < 0)
 121                return -1;
 122        ctl = __clone9(netdir, conv_dir, "bypass", flags);
 123        if (ctl < 0)
 124                return -1;
 125        n = snprintf(buf, sizeof(buf), "bypass %s", naddr);
 126        if (write(ctl, buf, n) != n) {
 127                fprintf(stderr, "bypass writing %s: %r\n", netdir);
 128                close(ctl);
 129                return -1;
 130        }
 131        return ctl;
 132}
 133
 134/*
 135 *  listen for an incoming call
 136 */
 137int listen9(char *dir, char *newdir, int flags)
 138{
 139        int ctl, n, m;
 140        char buf[Maxpath];
 141        char *cp;
 142
 143        /*
 144         *  open listen, wait for a call
 145         */
 146        snprintf(buf, sizeof(buf), "%s/listen", dir);
 147        ctl = open(buf, O_RDWR | (flags & O_NONBLOCK));
 148        if (ctl < 0) {
 149                if ((errno != EAGAIN) && (errno != EWOULDBLOCK))
 150                        fprintf(stderr, "listen opening %s: %r\n", buf);
 151                return -1;
 152        }
 153
 154        /*
 155         *  find out which line we have
 156         */
 157        strncpy(buf, dir, sizeof(buf) - 1);
 158        buf[sizeof(buf) - 1] = 0;
 159        cp = strrchr(buf, '/');
 160        if (cp == NULL) {
 161                close(ctl);
 162                fprintf(stderr, "listen arg format %s\n", dir);
 163                return -1;
 164        }
 165        *++cp = 0;
 166        n = cp - buf;
 167        m = read(ctl, cp, sizeof(buf) - n - 1);
 168        if (m <= 0) {
 169                close(ctl);
 170                fprintf(stderr, "listen reading %s/listen: %r\n", dir);
 171                return -1;
 172        }
 173        buf[n + m] = 0;
 174
 175        /*
 176         *  return directory etc.
 177         */
 178        if (newdir) {
 179                strncpy(newdir, buf, NETPATHLEN);
 180                newdir[NETPATHLEN - 1] = 0;
 181        }
 182        return ctl;
 183}
 184
 185/*
 186 *  accept a call, return an fd to the open data file
 187 */
 188int accept9(int ctl, char *dir)
 189{
 190        char buf[Maxpath];
 191        char *num;
 192        long n;
 193
 194        num = strrchr(dir, '/');
 195        if (num == NULL)
 196                num = dir;
 197        else
 198                num++;
 199
 200        n = snprintf(buf, sizeof(buf), "accept %s", num);
 201        /* ignore return value, network might not need accepts */
 202        write(ctl, buf, n);
 203
 204        snprintf(buf, sizeof(buf), "%s/data", dir);
 205        return open(buf, O_RDWR);
 206}
 207
 208/*
 209 *  reject a call, tell device the reason for the rejection
 210 */
 211int reject9(int ctl, char *dir, char *cause)
 212{
 213        char buf[Maxpath];
 214        char *num;
 215        long n;
 216
 217        num = strrchr(dir, '/');
 218        if (num == 0)
 219                num = dir;
 220        else
 221                num++;
 222        snprintf(buf, sizeof(buf), "reject %s %s", num, cause);
 223        n = strlen(buf);
 224        if (write(ctl, buf, n) != n)
 225                return -1;
 226        return 0;
 227}
 228
 229/*
 230 *  perform the identity translation (in case we can't reach cs)
 231 */
 232static int identtrans(char *netdir, char *addr, char *naddr, int na, char *file,
 233                      int nf)
 234{
 235        char proto[Maxpath];
 236        char *p;
 237
 238        /* parse the protocol */
 239        strncpy(proto, addr, sizeof(proto));
 240        proto[sizeof(proto) - 1] = 0;
 241        p = strchr(proto, '!');
 242        if (p)
 243                *p++ = 0;
 244
 245        snprintf(file, nf, "%s/%s/clone", netdir, proto);
 246        strncpy(naddr, p, na);
 247        naddr[na - 1] = 0;
 248
 249        return 1;
 250}
 251
 252/*
 253 *  call up the connection server and get a translation
 254 */
 255static int nettrans(char *addr, char *naddr, int na, char *file, int nf)
 256{
 257        int i, fd;
 258        char buf[Maxpath];
 259        char netdir[Maxpath];
 260        char *p, *p2;
 261        long n;
 262
 263        /*
 264         *  parse, get network directory
 265         */
 266        p = strchr(addr, '!');
 267        if (p == 0) {
 268                fprintf(stderr, "bad dial string: %s\n", addr);
 269                return -1;
 270        }
 271        if (*addr != '/') {
 272                strncpy(netdir, "/net", sizeof(netdir));
 273                netdir[sizeof(netdir) - 1] = 0;
 274        } else {
 275                for (p2 = p; *p2 != '/'; p2--)
 276                        ;
 277                i = p2 - addr;
 278                if (i == 0 || i >= sizeof(netdir)) {
 279                        fprintf(stderr, "bad dial string: %s\n", addr);
 280                        return -1;
 281                }
 282                strncpy(netdir, addr, i);
 283                netdir[i] = 0;
 284                addr = p2 + 1;
 285        }
 286
 287        /*
 288         *  ask the connection server
 289         */
 290        snprintf(buf, sizeof(buf), "%s/cs", netdir);
 291        fd = open(buf, O_RDWR);
 292        if (fd < 0)
 293                return identtrans(netdir, addr, naddr, na, file, nf);
 294        if (write(fd, addr, strlen(addr)) < 0) {
 295                close(fd);
 296                return -1;
 297        }
 298        lseek(fd, 0, 0);
 299        n = read(fd, buf, sizeof(buf) - 1);
 300        close(fd);
 301        if (n <= 0)
 302                return -1;
 303        buf[n] = 0;
 304
 305        /*
 306         *  parse the reply
 307         */
 308        p = strchr(buf, ' ');
 309        if (p == 0)
 310                return -1;
 311        *p++ = 0;
 312        strncpy(naddr, p, na);
 313        naddr[na - 1] = 0;
 314
 315        if (buf[0] == '/') {
 316                p = strchr(buf + 1, '/');
 317                if (p == NULL)
 318                        p = buf;
 319                else
 320                        p++;
 321        }
 322        snprintf(file, nf, "%s/%s", netdir, p);
 323        return 0;
 324}
 325
 326int open_data_fd9(char *conv_dir, int flags)
 327{
 328        char path_buf[MAX_PATH_LEN];
 329
 330        snprintf(path_buf, sizeof(path_buf), "%s/data", conv_dir);
 331        return open(path_buf, O_RDWR | flags);
 332}
 333
 334/* Given a conversation directory, return the "remote" or "local" port, passed
 335 * as the string which.  Returns the port via *port and TRUE on success. */
 336bool get_port9(char *conv_dir, char *which, uint16_t *port)
 337{
 338        /* We don't have a MAX_DIALSTRING, but MAX_PATH_LEN should be enough. */
 339        char buf[MAX_PATH_LEN];
 340        int local_fd;
 341        int ret;
 342        char *p;
 343
 344        snprintf(buf, sizeof(buf), "%s/%s", conv_dir, which);
 345        local_fd = open(buf, O_RDONLY);
 346        if (local_fd < 0)
 347                return FALSE;
 348        ret = read(local_fd, buf, sizeof(buf));
 349        close(local_fd);
 350        if (ret <= 0)
 351                return FALSE;
 352        p = strrchr(buf, '!');
 353        if (!p)
 354                return FALSE;
 355        p++;
 356        *port = atoi(p);
 357        return TRUE;
 358}
 359