]> git.lizzy.rs Git - plan9front.git/blobdiff - sys/src/libc/9sys/dial.c
allow # netpath in dial string
[plan9front.git] / sys / src / libc / 9sys / dial.c
index 74fc6e6aee5cf99fd3463daca9566dc176c000db..bf601ed9fbdea4a52ac23997613562d5866acea5 100644 (file)
@@ -1,24 +1,16 @@
-/*
- * dial - connect to a service (parallel version)
- */
 #include <u.h>
 #include <libc.h>
 
-typedef struct Conn Conn;
-typedef struct Dest Dest;
 typedef struct DS DS;
 
+static int     call(char*, char*, DS*);
+static int     csdial(DS*);
+static void    _dial_string_parse(char*, DS*);
+
 enum
 {
        Maxstring       = 128,
        Maxpath         = 256,
-
-       Maxcsreply      = 64*80,        /* this is probably overly generous */
-       /*
-        * this should be a plausible slight overestimate for non-interactive
-        * use even if it's ridiculously long for interactive use.
-        */
-       Maxconnms       = 20*60*1000,   /* 20 minutes */
 };
 
 struct DS {
@@ -34,42 +26,12 @@ struct DS {
        int     *cfdp;
 };
 
-/*
- * malloc these; they need to be writable by this proc & all children.
- * the stack is private to each proc, and static allocation in the data
- * segment would not permit concurrent dials within a multi-process program.
- */
-struct Conn {
-       int     pid;
-       int     dead;
-
-       int     dfd;
-       int     cfd;
-       char    dir[NETPATHLEN];
-       char    err[ERRMAX];
-};
-struct Dest {
-       Conn    *conn;                  /* allocated array */
-       Conn    *connend;
-       int     nkid;
-
-       QLock   winlck;
-       int     winner;                 /* index into conn[] */
-
-       char    *nextaddr;
-       char    addrlist[Maxcsreply];
-};
-
-static int     call(char*, char*, DS*, Dest*, Conn*);
-static int     csdial(DS*);
-static void    _dial_string_parse(char*, DS*);
-
 
 /*
  *  the dialstring is of the form '[/net/]proto!dest'
  */
-static int
-dialimpl(char *dest, char *local, char *dir, int *cfdp)
+int
+dial(char *dest, char *local, char *dir, int *cfdp)
 {
        DS ds;
        int rv;
@@ -107,224 +69,11 @@ dialimpl(char *dest, char *local, char *dir, int *cfdp)
        return rv;
 }
 
-/*
- * the thread library can't cope with rfork(RFMEM|RFPROC),
- * so it must override this with a private version of dial.
- */
-int (*_dial)(char *, char *, char *, int *) = dialimpl;
-
-int
-dial(char *dest, char *local, char *dir, int *cfdp)
-{
-       return (*_dial)(dest, local, dir, cfdp);
-}
-
-static int
-connsalloc(Dest *dp, int addrs)
-{
-       free(dp->conn);
-       dp->connend = nil;
-       assert(addrs > 0);
-
-       dp->conn = mallocz(addrs * sizeof *dp->conn, 1);
-       if(dp->conn == nil)
-               return -1;
-       dp->connend = dp->conn + addrs;
-       return 0;
-}
-
-static void
-freedest(Dest *dp)
-{
-       if (dp != nil) {
-               free(dp->conn);
-               free(dp);
-       }
-}
-
-static void
-closeopenfd(int *fdp)
-{
-       if (*fdp > 0) {
-               close(*fdp);
-               *fdp = -1;
-       }
-}
-
-static void
-notedeath(Dest *dp, char *exitsts)
-{
-       int i, n, pid;
-       char *fields[5];                        /* pid + 3 times + error */
-       Conn *conn;
-
-       for (i = 0; i < nelem(fields); i++)
-               fields[i] = "";
-       n = tokenize(exitsts, fields, nelem(fields));
-       if (n < 4)
-               return;
-       pid = atoi(fields[0]);
-       if (pid <= 0)
-               return;
-       for (conn = dp->conn; conn < dp->connend; conn++)
-               if (conn->pid == pid && !conn->dead) {  /* it's one we know? */
-                       if (conn - dp->conn != dp->winner) {
-                               closeopenfd(&conn->dfd);
-                               closeopenfd(&conn->cfd);
-                       }
-                       strncpy(conn->err, fields[4], sizeof conn->err);
-                       conn->dead = 1;
-                       return;
-               }
-       /* not a proc that we forked */
-}
-
-static int
-outstandingprocs(Dest *dp)
-{
-       Conn *conn;
-
-       for (conn = dp->conn; conn < dp->connend; conn++)
-               if (!conn->dead)
-                       return 1;
-       return 0;
-}
-
-static int
-reap(Dest *dp)
-{
-       char exitsts[2*ERRMAX];
-
-       if (outstandingprocs(dp) && await(exitsts, sizeof exitsts) >= 0) {
-               notedeath(dp, exitsts);
-               return 0;
-       }
-       return -1;
-}
-
-static int
-fillinds(DS *ds, Dest *dp)
-{
-       Conn *conn;
-
-       if (dp->winner < 0)
-               return -1;
-       conn = &dp->conn[dp->winner];
-       if (ds->cfdp)
-               *ds->cfdp = conn->cfd;
-       if (ds->dir)
-               strncpy(ds->dir, conn->dir, NETPATHLEN);
-       return conn->dfd;
-}
-
-static int
-connectwait(Dest *dp, char *besterr)
-{
-       Conn *conn;
-
-       /* wait for a winner or all attempts to time out */
-       while (dp->winner < 0 && reap(dp) >= 0)
-               ;
-
-       /* kill all of our still-live kids & reap them */
-       for (conn = dp->conn; conn < dp->connend; conn++)
-               if (!conn->dead)
-                       postnote(PNPROC, conn->pid, "die");
-       while (reap(dp) >= 0)
-               ;
-
-       /* rummage about and report some error string */
-       for (conn = dp->conn; conn < dp->connend; conn++)
-               if (conn - dp->conn != dp->winner && conn->dead &&
-                   conn->err[0]) {
-                       strncpy(besterr, conn->err, ERRMAX);
-                       break;
-               }
-       return dp->winner;
-}
-
-static int
-parsecs(Dest *dp, char **clonep, char **destp)
-{
-       char *dest, *p;
-
-       dest = strchr(dp->nextaddr, ' ');
-       if(dest == nil)
-               return -1;
-       *dest++ = '\0';
-       p = strchr(dest, '\n');
-       if(p == nil)
-               return -1;
-       *p++ = '\0';
-       *clonep = dp->nextaddr;
-       *destp = dest;
-       dp->nextaddr = p;               /* advance to next line */
-       return 0;
-}
-
-static void
-pickuperr(char *besterr, char *err)
-{
-       err[0] = '\0';
-       errstr(err, ERRMAX);
-       if(strstr(err, "does not exist") == 0)
-               strcpy(besterr, err);
-}
-
-/*
- * try all addresses in parallel and take the first one that answers;
- * this helps when systems have ip v4 and v6 addresses but are
- * only reachable from here on one (or some) of them.
- */
-static int
-dialmulti(DS *ds, Dest *dp)
-{
-       int rv, kid, kidme;
-       char *clone, *dest;
-       char err[ERRMAX], besterr[ERRMAX];
-
-       dp->winner = -1;
-       dp->nkid = 0;
-       while(dp->winner < 0 && *dp->nextaddr != '\0' &&
-           parsecs(dp, &clone, &dest) >= 0) {
-               kidme = dp->nkid++;             /* make private copy on stack */
-               kid = rfork(RFPROC|RFMEM);      /* spin off a call attempt */
-               if (kid < 0)
-                       --dp->nkid;
-               else if (kid == 0) {
-                       alarm(Maxconnms);
-                       *besterr = '\0';
-                       rv = call(clone, dest, ds, dp, &dp->conn[kidme]);
-                       if(rv < 0)
-                               pickuperr(besterr, err);
-                       _exits(besterr);        /* avoid atexit callbacks */
-               }
-       }
-       rv = connectwait(dp, besterr);
-       if(rv < 0 && *besterr)
-               werrstr("%s", besterr);
-       else
-               werrstr("%s", err);
-       return rv;
-}
-
 static int
 csdial(DS *ds)
 {
-       int n, fd, rv, addrs, bleft;
-       char c;
-       char *addrp, *clone2, *dest;
-       char buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
-       Dest *dp;
-
-       dp = mallocz(sizeof *dp, 1);
-       if(dp == nil)
-               return -1;
-       dp->winner = -1;
-       if (connsalloc(dp, 1) < 0) {            /* room for a single conn. */
-               freedest(dp);
-               return -1;
-       }
+       int n, fd, rv;
+       char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
 
        /*
         *  open connection server
@@ -334,10 +83,7 @@ csdial(DS *ds)
        if(fd < 0){
                /* no connection server, don't translate */
                snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
-               rv = call(clone, ds->rem, ds, dp, &dp->conn[0]);
-               fillinds(ds, dp);
-               freedest(dp);
-               return rv;
+               return call(clone, ds->rem, ds);
        }
 
        /*
@@ -346,63 +92,47 @@ csdial(DS *ds)
        snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
        if(write(fd, buf, strlen(buf)) < 0){
                close(fd);
-               freedest(dp);
                return -1;
        }
 
        /*
-        *  read all addresses from the connection server.
+        *  loop through each address from the connection server till
+        *  we get one that works.
         */
+       *besterr = 0;
+       rv = -1;
        seek(fd, 0, 0);
-       addrs = 0;
-       addrp = dp->nextaddr = dp->addrlist;
-       bleft = sizeof dp->addrlist - 2;        /* 2 is room for \n\0 */
-       while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) {
-               if (addrp[n-1] != '\n')
-                       addrp[n++] = '\n';
-               addrs++;
-               addrp += n;
-               bleft -= n;
+       while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
+               buf[n] = 0;
+               p = strchr(buf, ' ');
+               if(p == 0)
+                       continue;
+               *p++ = 0;
+               rv = call(buf, p, ds);
+               if(rv >= 0)
+                       break;
+               err[0] = '\0';
+               errstr(err, sizeof err);
+               if(strstr(err, "does not exist") == 0)
+                       strcpy(besterr, err);
        }
-       /*
-        * if we haven't read all of cs's output, assume the last line might
-        * have been truncated and ignore it.  we really don't expect this
-        * to happen.
-        */
-       if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1)
-               addrs--;
        close(fd);
 
-       *besterr = 0;
-       rv = -1;                                /* pessimistic default */
-       if (addrs == 0)
-               werrstr("no address to dial");
-       else if (addrs == 1) {
-               /* common case: dial one address without forking */
-               if (parsecs(dp, &clone2, &dest) >= 0 &&
-                   (rv = call(clone2, dest, ds, dp, &dp->conn[0])) < 0) {
-                       pickuperr(besterr, err);
-                       werrstr("%s", besterr);
-               }
-       } else if (connsalloc(dp, addrs) >= 0)
-               rv = dialmulti(ds, dp);
-
-       /* fill in results */
-       if (rv >= 0 && dp->winner >= 0)
-               rv = fillinds(ds, dp);
-
-       freedest(dp);
+       if(rv < 0 && *besterr)
+               werrstr("%s", besterr);
+       else
+               werrstr("%s", err);
        return rv;
 }
 
 static int
-call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
+call(char *clone, char *dest, DS *ds)
 {
        int fd, cfd, n;
        char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
 
        /* because cs is in a different name space, replace the mount point */
-       if(*clone == '/'){
+       if(*clone == '/' || *clone == '#'){
                p = strchr(clone+1, '/');
                if(p == nil)
                        p = clone;
@@ -412,15 +142,14 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
                p = clone;
        snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
 
-       conn->pid = getpid();
-       conn->cfd = cfd = open(cname, ORDWR);
+       cfd = open(cname, ORDWR);
        if(cfd < 0)
                return -1;
 
        /* get directory name */
        n = read(cfd, name, sizeof(name)-1);
        if(n < 0){
-               closeopenfd(&conn->cfd);
+               close(cfd);
                return -1;
        }
        name[n] = 0;
@@ -430,7 +159,7 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
        p = strrchr(cname, '/');
        *p = 0;
        if(ds->dir)
-               snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name);
+               snprint(ds->dir, NETPATHLEN, "%s/%s", cname, name);
        snprint(data, sizeof(data), "%s/%s/data", cname, name);
 
        /* connect */
@@ -439,23 +168,20 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
        else
                snprint(name, sizeof(name), "connect %s", dest);
        if(write(cfd, name, strlen(name)) < 0){
-               closeopenfd(&conn->cfd);
+               close(cfd);
                return -1;
        }
 
        /* open data connection */
-       conn->dfd = fd = open(data, ORDWR);
+       fd = open(data, ORDWR);
        if(fd < 0){
-               closeopenfd(&conn->cfd);
+               close(cfd);
                return -1;
        }
-       if(ds->cfdp == nil)
-               closeopenfd(&conn->cfd);
-
-       qlock(&dp->winlck);
-       if (dp->winner < 0 && conn < dp->connend)
-               dp->winner = conn - dp->conn;
-       qunlock(&dp->winlck);
+       if(ds->cfdp)
+               *ds->cfdp = cfd;
+       else
+               close(cfd);
        return fd;
 }
 
@@ -476,7 +202,13 @@ _dial_string_parse(char *str, DS *ds)
                ds->proto = "net";
                ds->rem = ds->buf;
        } else {
-               if(*ds->buf != '/' && *ds->buf != '#'){
+               p2 = ds->buf;
+               if(*p2 == '#'){
+                       p2 = strchr(p2, '/');
+                       if(p2 == nil || p2 > p)
+                               p2 = ds->buf;
+               }
+               if(*p2 != '/'){
                        ds->netdir = 0;
                        ds->proto = ds->buf;
                } else {