1*63afb9a5SDavid du Colombier /* 2*63afb9a5SDavid du Colombier * dial - connect to a service (threaded parallel version) 3*63afb9a5SDavid du Colombier */ 4*63afb9a5SDavid du Colombier #include <u.h> 5*63afb9a5SDavid du Colombier #include <libc.h> 6*63afb9a5SDavid du Colombier #include <ctype.h> 7*63afb9a5SDavid du Colombier #include <fcall.h> 8*63afb9a5SDavid du Colombier #include <thread.h> 9*63afb9a5SDavid du Colombier #include <9p.h> 10*63afb9a5SDavid du Colombier 11*63afb9a5SDavid du Colombier typedef struct Conn Conn; 12*63afb9a5SDavid du Colombier typedef struct Dest Dest; 13*63afb9a5SDavid du Colombier typedef struct DS DS; 14*63afb9a5SDavid du Colombier typedef struct Kidargs Kidargs; 15*63afb9a5SDavid du Colombier typedef struct Restup Restup; 16*63afb9a5SDavid du Colombier 17*63afb9a5SDavid du Colombier enum 18*63afb9a5SDavid du Colombier { 19*63afb9a5SDavid du Colombier Noblock, 20*63afb9a5SDavid du Colombier Block, 21*63afb9a5SDavid du Colombier 22*63afb9a5SDavid du Colombier Defstksize = 8192, 23*63afb9a5SDavid du Colombier 24*63afb9a5SDavid du Colombier Maxstring = 128, 25*63afb9a5SDavid du Colombier Maxpath = 256, 26*63afb9a5SDavid du Colombier 27*63afb9a5SDavid du Colombier Maxcsreply = 64*80, /* this is probably overly generous */ 28*63afb9a5SDavid du Colombier /* 29*63afb9a5SDavid du Colombier * this should be a plausible slight overestimate for non-interactive 30*63afb9a5SDavid du Colombier * use even if it's ridiculously long for interactive use. 31*63afb9a5SDavid du Colombier */ 32*63afb9a5SDavid du Colombier Maxconnms = 2*60*1000, /* 2 minutes */ 33*63afb9a5SDavid du Colombier }; 34*63afb9a5SDavid du Colombier 35*63afb9a5SDavid du Colombier struct DS { 36*63afb9a5SDavid du Colombier /* dial string */ 37*63afb9a5SDavid du Colombier char buf[Maxstring]; 38*63afb9a5SDavid du Colombier char *netdir; 39*63afb9a5SDavid du Colombier char *proto; 40*63afb9a5SDavid du Colombier char *rem; 41*63afb9a5SDavid du Colombier 42*63afb9a5SDavid du Colombier /* other args */ 43*63afb9a5SDavid du Colombier char *local; 44*63afb9a5SDavid du Colombier char *dir; 45*63afb9a5SDavid du Colombier int *cfdp; 46*63afb9a5SDavid du Colombier }; 47*63afb9a5SDavid du Colombier 48*63afb9a5SDavid du Colombier struct Conn { 49*63afb9a5SDavid du Colombier int cfd; 50*63afb9a5SDavid du Colombier char dir[NETPATHLEN]; 51*63afb9a5SDavid du Colombier }; 52*63afb9a5SDavid du Colombier struct Dest { 53*63afb9a5SDavid du Colombier DS *ds; 54*63afb9a5SDavid du Colombier 55*63afb9a5SDavid du Colombier Channel *reschan; /* all callprocs send results on this */ 56*63afb9a5SDavid du Colombier int nkid; 57*63afb9a5SDavid du Colombier int kidthrids[64]; /* one per addr; ought to be enough */ 58*63afb9a5SDavid du Colombier 59*63afb9a5SDavid du Colombier int windfd; 60*63afb9a5SDavid du Colombier char err[ERRMAX]; 61*63afb9a5SDavid du Colombier 62*63afb9a5SDavid du Colombier long oalarm; 63*63afb9a5SDavid du Colombier 64*63afb9a5SDavid du Colombier int naddrs; 65*63afb9a5SDavid du Colombier char *nextaddr; 66*63afb9a5SDavid du Colombier char addrlist[Maxcsreply]; 67*63afb9a5SDavid du Colombier }; 68*63afb9a5SDavid du Colombier 69*63afb9a5SDavid du Colombier struct Kidargs { /* arguments to callproc */ 70*63afb9a5SDavid du Colombier Dest *dp; 71*63afb9a5SDavid du Colombier int thridsme; 72*63afb9a5SDavid du Colombier char *clone; 73*63afb9a5SDavid du Colombier char *dest; 74*63afb9a5SDavid du Colombier }; 75*63afb9a5SDavid du Colombier 76*63afb9a5SDavid du Colombier struct Restup { /* result tuple from callproc */ 77*63afb9a5SDavid du Colombier int dfd; 78*63afb9a5SDavid du Colombier int cfd; 79*63afb9a5SDavid du Colombier char *err; 80*63afb9a5SDavid du Colombier char *conndir; 81*63afb9a5SDavid du Colombier }; 82*63afb9a5SDavid du Colombier 83*63afb9a5SDavid du Colombier static int call(char*, char*, Dest*, Conn*); 84*63afb9a5SDavid du Colombier static int call1(char*, char*, Dest*, Conn*); 85*63afb9a5SDavid du Colombier static int csdial(DS*); 86*63afb9a5SDavid du Colombier static void _dial_string_parse(char*, DS*); 87*63afb9a5SDavid du Colombier 88*63afb9a5SDavid du Colombier /* 89*63afb9a5SDavid du Colombier * the dialstring is of the form '[/net/]proto!dest' 90*63afb9a5SDavid du Colombier */ 91*63afb9a5SDavid du Colombier static int 92*63afb9a5SDavid du Colombier dialimpl(char *dest, char *local, char *dir, int *cfdp) 93*63afb9a5SDavid du Colombier { 94*63afb9a5SDavid du Colombier DS ds; 95*63afb9a5SDavid du Colombier int rv; 96*63afb9a5SDavid du Colombier char err[ERRMAX], alterr[ERRMAX]; 97*63afb9a5SDavid du Colombier 98*63afb9a5SDavid du Colombier ds.local = local; 99*63afb9a5SDavid du Colombier ds.dir = dir; 100*63afb9a5SDavid du Colombier ds.cfdp = cfdp; 101*63afb9a5SDavid du Colombier 102*63afb9a5SDavid du Colombier _dial_string_parse(dest, &ds); 103*63afb9a5SDavid du Colombier if(ds.netdir) 104*63afb9a5SDavid du Colombier return csdial(&ds); 105*63afb9a5SDavid du Colombier 106*63afb9a5SDavid du Colombier ds.netdir = "/net"; 107*63afb9a5SDavid du Colombier rv = csdial(&ds); 108*63afb9a5SDavid du Colombier if(rv >= 0) 109*63afb9a5SDavid du Colombier return rv; 110*63afb9a5SDavid du Colombier err[0] = '\0'; 111*63afb9a5SDavid du Colombier errstr(err, sizeof err); 112*63afb9a5SDavid du Colombier if(strstr(err, "refused") != 0){ 113*63afb9a5SDavid du Colombier werrstr("%s", err); 114*63afb9a5SDavid du Colombier return rv; 115*63afb9a5SDavid du Colombier } 116*63afb9a5SDavid du Colombier ds.netdir = "/net.alt"; 117*63afb9a5SDavid du Colombier rv = csdial(&ds); 118*63afb9a5SDavid du Colombier if(rv >= 0) 119*63afb9a5SDavid du Colombier return rv; 120*63afb9a5SDavid du Colombier 121*63afb9a5SDavid du Colombier alterr[0] = 0; 122*63afb9a5SDavid du Colombier errstr(alterr, sizeof alterr); 123*63afb9a5SDavid du Colombier if(strstr(alterr, "translate") || strstr(alterr, "does not exist")) 124*63afb9a5SDavid du Colombier werrstr("%s", err); 125*63afb9a5SDavid du Colombier else 126*63afb9a5SDavid du Colombier werrstr("%s", alterr); 127*63afb9a5SDavid du Colombier return rv; 128*63afb9a5SDavid du Colombier } 129*63afb9a5SDavid du Colombier 130*63afb9a5SDavid du Colombier /* 131*63afb9a5SDavid du Colombier * the thread library can't cope with rfork(RFMEM|RFPROC), 132*63afb9a5SDavid du Colombier * so it must override _dial with this version of dial. 133*63afb9a5SDavid du Colombier */ 134*63afb9a5SDavid du Colombier int (*_dial)(char *, char *, char *, int *) = dialimpl; 135*63afb9a5SDavid du Colombier 136*63afb9a5SDavid du Colombier int 137*63afb9a5SDavid du Colombier dial(char *dest, char *local, char *dir, int *cfdp) 138*63afb9a5SDavid du Colombier { 139*63afb9a5SDavid du Colombier return (*_dial)(dest, local, dir, cfdp); 140*63afb9a5SDavid du Colombier } 141*63afb9a5SDavid du Colombier 142*63afb9a5SDavid du Colombier static void 143*63afb9a5SDavid du Colombier freedest(Dest *dp) 144*63afb9a5SDavid du Colombier { 145*63afb9a5SDavid du Colombier if (dp) { 146*63afb9a5SDavid du Colombier if (dp->oalarm >= 0) 147*63afb9a5SDavid du Colombier alarm(dp->oalarm); 148*63afb9a5SDavid du Colombier free(dp); 149*63afb9a5SDavid du Colombier } 150*63afb9a5SDavid du Colombier } 151*63afb9a5SDavid du Colombier 152*63afb9a5SDavid du Colombier static void 153*63afb9a5SDavid du Colombier closeopenfd(int *fdp) 154*63afb9a5SDavid du Colombier { 155*63afb9a5SDavid du Colombier if (*fdp >= 0) { 156*63afb9a5SDavid du Colombier close(*fdp); 157*63afb9a5SDavid du Colombier *fdp = -1; 158*63afb9a5SDavid du Colombier } 159*63afb9a5SDavid du Colombier } 160*63afb9a5SDavid du Colombier 161*63afb9a5SDavid du Colombier static int 162*63afb9a5SDavid du Colombier parsecs(Dest *dp, char **clonep, char **destp) 163*63afb9a5SDavid du Colombier { 164*63afb9a5SDavid du Colombier char *dest, *p; 165*63afb9a5SDavid du Colombier 166*63afb9a5SDavid du Colombier dest = strchr(dp->nextaddr, ' '); 167*63afb9a5SDavid du Colombier if(dest == nil) 168*63afb9a5SDavid du Colombier return -1; 169*63afb9a5SDavid du Colombier *dest++ = '\0'; 170*63afb9a5SDavid du Colombier p = strchr(dest, '\n'); 171*63afb9a5SDavid du Colombier if(p == nil) 172*63afb9a5SDavid du Colombier return -1; 173*63afb9a5SDavid du Colombier *p++ = '\0'; 174*63afb9a5SDavid du Colombier *clonep = dp->nextaddr; 175*63afb9a5SDavid du Colombier *destp = dest; 176*63afb9a5SDavid du Colombier dp->nextaddr = p; /* advance to next line */ 177*63afb9a5SDavid du Colombier return 0; 178*63afb9a5SDavid du Colombier } 179*63afb9a5SDavid du Colombier 180*63afb9a5SDavid du Colombier static void 181*63afb9a5SDavid du Colombier pickuperr(char *besterr) 182*63afb9a5SDavid du Colombier { 183*63afb9a5SDavid du Colombier char err[ERRMAX]; 184*63afb9a5SDavid du Colombier 185*63afb9a5SDavid du Colombier err[0] = '\0'; 186*63afb9a5SDavid du Colombier errstr(err, ERRMAX); 187*63afb9a5SDavid du Colombier if(strstr(err, "does not exist") == 0) 188*63afb9a5SDavid du Colombier strcpy(besterr, err); 189*63afb9a5SDavid du Colombier } 190*63afb9a5SDavid du Colombier 191*63afb9a5SDavid du Colombier static int 192*63afb9a5SDavid du Colombier catcher(void *, char *s) 193*63afb9a5SDavid du Colombier { 194*63afb9a5SDavid du Colombier return strstr(s, "alarm") != nil; 195*63afb9a5SDavid du Colombier } 196*63afb9a5SDavid du Colombier 197*63afb9a5SDavid du Colombier static void 198*63afb9a5SDavid du Colombier callproc(void *p) 199*63afb9a5SDavid du Colombier { 200*63afb9a5SDavid du Colombier int dfd; 201*63afb9a5SDavid du Colombier char besterr[ERRMAX]; 202*63afb9a5SDavid du Colombier Conn lconn; 203*63afb9a5SDavid du Colombier Conn *conn; 204*63afb9a5SDavid du Colombier Kidargs *args; 205*63afb9a5SDavid du Colombier Restup *tup; 206*63afb9a5SDavid du Colombier 207*63afb9a5SDavid du Colombier threadnotify(catcher, 1); /* avoid atnotify callbacks in parent */ 208*63afb9a5SDavid du Colombier 209*63afb9a5SDavid du Colombier conn = &lconn; 210*63afb9a5SDavid du Colombier memset(conn, 0, sizeof *conn); 211*63afb9a5SDavid du Colombier *besterr = '\0'; 212*63afb9a5SDavid du Colombier args = (Kidargs *)p; 213*63afb9a5SDavid du Colombier dfd = call(args->clone, args->dest, args->dp, conn); 214*63afb9a5SDavid du Colombier if(dfd < 0) 215*63afb9a5SDavid du Colombier pickuperr(besterr); 216*63afb9a5SDavid du Colombier 217*63afb9a5SDavid du Colombier tup = (Restup *)emalloc9p(sizeof *tup); 218*63afb9a5SDavid du Colombier *tup = (Restup){dfd, conn->cfd, nil, nil}; 219*63afb9a5SDavid du Colombier if (dfd >= 0) 220*63afb9a5SDavid du Colombier tup->conndir = strdup(conn->dir); 221*63afb9a5SDavid du Colombier else 222*63afb9a5SDavid du Colombier tup->err = strdup(besterr); 223*63afb9a5SDavid du Colombier sendp(args->dp->reschan, tup); 224*63afb9a5SDavid du Colombier 225*63afb9a5SDavid du Colombier args->dp->kidthrids[args->thridsme] = -1; 226*63afb9a5SDavid du Colombier free(args); 227*63afb9a5SDavid du Colombier threadexits(besterr); /* better be no atexit callbacks */ 228*63afb9a5SDavid du Colombier } 229*63afb9a5SDavid du Colombier 230*63afb9a5SDavid du Colombier /* interrupt all of our still-live kids */ 231*63afb9a5SDavid du Colombier static void 232*63afb9a5SDavid du Colombier intrcallprocs(Dest *dp) 233*63afb9a5SDavid du Colombier { 234*63afb9a5SDavid du Colombier int i; 235*63afb9a5SDavid du Colombier 236*63afb9a5SDavid du Colombier for (i = 0; i < nelem(dp->kidthrids); i++) 237*63afb9a5SDavid du Colombier if (dp->kidthrids[i] >= 0) 238*63afb9a5SDavid du Colombier threadint(dp->kidthrids[i]); 239*63afb9a5SDavid du Colombier } 240*63afb9a5SDavid du Colombier 241*63afb9a5SDavid du Colombier static int 242*63afb9a5SDavid du Colombier recvresults(Dest *dp, int block) 243*63afb9a5SDavid du Colombier { 244*63afb9a5SDavid du Colombier DS *ds; 245*63afb9a5SDavid du Colombier Restup *tup; 246*63afb9a5SDavid du Colombier 247*63afb9a5SDavid du Colombier for (; dp->nkid > 0; dp->nkid--) { 248*63afb9a5SDavid du Colombier if (block) 249*63afb9a5SDavid du Colombier tup = recvp(dp->reschan); 250*63afb9a5SDavid du Colombier else 251*63afb9a5SDavid du Colombier tup = nbrecvp(dp->reschan); 252*63afb9a5SDavid du Colombier if (tup == nil) 253*63afb9a5SDavid du Colombier break; 254*63afb9a5SDavid du Colombier if (tup->dfd >= 0) /* connected? */ 255*63afb9a5SDavid du Colombier if (dp->windfd < 0) { /* first connection? */ 256*63afb9a5SDavid du Colombier ds = dp->ds; 257*63afb9a5SDavid du Colombier dp->windfd = tup->dfd; 258*63afb9a5SDavid du Colombier if (ds->cfdp) 259*63afb9a5SDavid du Colombier *ds->cfdp = tup->cfd; 260*63afb9a5SDavid du Colombier if (ds->dir) 261*63afb9a5SDavid du Colombier strncpy(ds->dir, tup->conndir, 262*63afb9a5SDavid du Colombier NETPATHLEN); 263*63afb9a5SDavid du Colombier intrcallprocs(dp); 264*63afb9a5SDavid du Colombier } else { 265*63afb9a5SDavid du Colombier close(tup->dfd); 266*63afb9a5SDavid du Colombier close(tup->cfd); 267*63afb9a5SDavid du Colombier } 268*63afb9a5SDavid du Colombier else if (dp->err[0] == '\0' && tup->err) 269*63afb9a5SDavid du Colombier strncpy(dp->err, tup->err, ERRMAX); 270*63afb9a5SDavid du Colombier free(tup->conndir); 271*63afb9a5SDavid du Colombier free(tup->err); 272*63afb9a5SDavid du Colombier free(tup); 273*63afb9a5SDavid du Colombier } 274*63afb9a5SDavid du Colombier return dp->windfd; 275*63afb9a5SDavid du Colombier } 276*63afb9a5SDavid du Colombier 277*63afb9a5SDavid du Colombier /* 278*63afb9a5SDavid du Colombier * try all addresses in parallel and take the first one that answers; 279*63afb9a5SDavid du Colombier * this helps when systems have ip v4 and v6 addresses but are 280*63afb9a5SDavid du Colombier * only reachable from here on one (or some) of them. 281*63afb9a5SDavid du Colombier */ 282*63afb9a5SDavid du Colombier static int 283*63afb9a5SDavid du Colombier dialmulti(Dest *dp) 284*63afb9a5SDavid du Colombier { 285*63afb9a5SDavid du Colombier int kidme; 286*63afb9a5SDavid du Colombier char *clone, *dest; 287*63afb9a5SDavid du Colombier Kidargs *argp; 288*63afb9a5SDavid du Colombier 289*63afb9a5SDavid du Colombier dp->reschan = chancreate(sizeof(void *), 0); 290*63afb9a5SDavid du Colombier dp->err[0] = '\0'; 291*63afb9a5SDavid du Colombier dp->nkid = 0; 292*63afb9a5SDavid du Colombier dp->windfd = -1; 293*63afb9a5SDavid du Colombier /* if too many addresses for dp->kidthrids, ignore the last few */ 294*63afb9a5SDavid du Colombier while(dp->windfd < 0 && dp->nkid < nelem(dp->kidthrids) && 295*63afb9a5SDavid du Colombier *dp->nextaddr != '\0' && parsecs(dp, &clone, &dest) >= 0) { 296*63afb9a5SDavid du Colombier kidme = dp->nkid++; 297*63afb9a5SDavid du Colombier 298*63afb9a5SDavid du Colombier argp = (Kidargs *)emalloc9p(sizeof *argp); 299*63afb9a5SDavid du Colombier *argp = (Kidargs){dp, kidme, clone, dest}; 300*63afb9a5SDavid du Colombier 301*63afb9a5SDavid du Colombier dp->kidthrids[kidme] = proccreate(callproc, argp, Defstksize); 302*63afb9a5SDavid du Colombier if (dp->kidthrids[kidme] < 0) 303*63afb9a5SDavid du Colombier --dp->nkid; 304*63afb9a5SDavid du Colombier } 305*63afb9a5SDavid du Colombier 306*63afb9a5SDavid du Colombier recvresults(dp, Block); 307*63afb9a5SDavid du Colombier assert(dp->nkid == 0); 308*63afb9a5SDavid du Colombier 309*63afb9a5SDavid du Colombier chanclose(dp->reschan); 310*63afb9a5SDavid du Colombier chanfree(dp->reschan); 311*63afb9a5SDavid du Colombier if(dp->windfd < 0 && dp->err[0]) 312*63afb9a5SDavid du Colombier werrstr("%s", dp->err); 313*63afb9a5SDavid du Colombier return dp->windfd; 314*63afb9a5SDavid du Colombier } 315*63afb9a5SDavid du Colombier 316*63afb9a5SDavid du Colombier /* call a single address and pass back cfd & conn dir after */ 317*63afb9a5SDavid du Colombier static int 318*63afb9a5SDavid du Colombier call1(char *clone, char *rem, Dest *dp, Conn *conn) 319*63afb9a5SDavid du Colombier { 320*63afb9a5SDavid du Colombier int dfd; 321*63afb9a5SDavid du Colombier DS *ds; 322*63afb9a5SDavid du Colombier 323*63afb9a5SDavid du Colombier ds = dp->ds; 324*63afb9a5SDavid du Colombier dfd = call(clone, rem, dp, conn); 325*63afb9a5SDavid du Colombier if (dfd < 0) 326*63afb9a5SDavid du Colombier return dfd; 327*63afb9a5SDavid du Colombier 328*63afb9a5SDavid du Colombier if (ds->cfdp) 329*63afb9a5SDavid du Colombier *ds->cfdp = conn->cfd; 330*63afb9a5SDavid du Colombier if (ds->dir) 331*63afb9a5SDavid du Colombier strncpy(ds->dir, conn->dir, NETPATHLEN); 332*63afb9a5SDavid du Colombier return dfd; 333*63afb9a5SDavid du Colombier } 334*63afb9a5SDavid du Colombier 335*63afb9a5SDavid du Colombier static int 336*63afb9a5SDavid du Colombier csdial(DS *ds) 337*63afb9a5SDavid du Colombier { 338*63afb9a5SDavid du Colombier int n, fd, dfd, addrs, bleft; 339*63afb9a5SDavid du Colombier char c; 340*63afb9a5SDavid du Colombier char *addrp, *clone2, *dest; 341*63afb9a5SDavid du Colombier char buf[Maxstring], clone[Maxpath], besterr[ERRMAX]; 342*63afb9a5SDavid du Colombier Conn lconn; 343*63afb9a5SDavid du Colombier Conn *conn; 344*63afb9a5SDavid du Colombier Dest *dp; 345*63afb9a5SDavid du Colombier 346*63afb9a5SDavid du Colombier dp = mallocz(sizeof *dp, 1); 347*63afb9a5SDavid du Colombier if(dp == nil) 348*63afb9a5SDavid du Colombier return -1; 349*63afb9a5SDavid du Colombier conn = &lconn; 350*63afb9a5SDavid du Colombier memset(conn, 0, sizeof *conn); 351*63afb9a5SDavid du Colombier dp->ds = ds; 352*63afb9a5SDavid du Colombier if (ds->cfdp) 353*63afb9a5SDavid du Colombier *ds->cfdp = -1; 354*63afb9a5SDavid du Colombier if (ds->dir) 355*63afb9a5SDavid du Colombier ds->dir[0] = '\0'; 356*63afb9a5SDavid du Colombier dp->oalarm = alarm(0); 357*63afb9a5SDavid du Colombier 358*63afb9a5SDavid du Colombier /* 359*63afb9a5SDavid du Colombier * open connection server 360*63afb9a5SDavid du Colombier */ 361*63afb9a5SDavid du Colombier snprint(buf, sizeof(buf), "%s/cs", ds->netdir); 362*63afb9a5SDavid du Colombier fd = open(buf, ORDWR); 363*63afb9a5SDavid du Colombier if(fd < 0){ 364*63afb9a5SDavid du Colombier /* no connection server, don't translate */ 365*63afb9a5SDavid du Colombier snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto); 366*63afb9a5SDavid du Colombier dfd = call1(clone, ds->rem, dp, conn); 367*63afb9a5SDavid du Colombier freedest(dp); 368*63afb9a5SDavid du Colombier return dfd; 369*63afb9a5SDavid du Colombier } 370*63afb9a5SDavid du Colombier 371*63afb9a5SDavid du Colombier /* 372*63afb9a5SDavid du Colombier * ask connection server to translate 373*63afb9a5SDavid du Colombier */ 374*63afb9a5SDavid du Colombier snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem); 375*63afb9a5SDavid du Colombier if(write(fd, buf, strlen(buf)) < 0){ 376*63afb9a5SDavid du Colombier close(fd); 377*63afb9a5SDavid du Colombier freedest(dp); 378*63afb9a5SDavid du Colombier return -1; 379*63afb9a5SDavid du Colombier } 380*63afb9a5SDavid du Colombier 381*63afb9a5SDavid du Colombier /* 382*63afb9a5SDavid du Colombier * read all addresses from the connection server. 383*63afb9a5SDavid du Colombier */ 384*63afb9a5SDavid du Colombier seek(fd, 0, 0); 385*63afb9a5SDavid du Colombier addrs = 0; 386*63afb9a5SDavid du Colombier addrp = dp->nextaddr = dp->addrlist; 387*63afb9a5SDavid du Colombier bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */ 388*63afb9a5SDavid du Colombier while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) { 389*63afb9a5SDavid du Colombier if (addrp[n-1] != '\n') 390*63afb9a5SDavid du Colombier addrp[n++] = '\n'; 391*63afb9a5SDavid du Colombier addrs++; 392*63afb9a5SDavid du Colombier addrp += n; 393*63afb9a5SDavid du Colombier bleft -= n; 394*63afb9a5SDavid du Colombier } 395*63afb9a5SDavid du Colombier /* 396*63afb9a5SDavid du Colombier * if we haven't read all of cs's output, assume the last line might 397*63afb9a5SDavid du Colombier * have been truncated and ignore it. we really don't expect this 398*63afb9a5SDavid du Colombier * to happen. 399*63afb9a5SDavid du Colombier */ 400*63afb9a5SDavid du Colombier if (addrs > 0 && bleft <= 0 && read(fd, &c, 1) == 1) 401*63afb9a5SDavid du Colombier addrs--; 402*63afb9a5SDavid du Colombier close(fd); 403*63afb9a5SDavid du Colombier 404*63afb9a5SDavid du Colombier *besterr = 0; 405*63afb9a5SDavid du Colombier dfd = -1; /* pessimistic default */ 406*63afb9a5SDavid du Colombier dp->naddrs = addrs; 407*63afb9a5SDavid du Colombier if (addrs == 0) 408*63afb9a5SDavid du Colombier werrstr("no address to dial"); 409*63afb9a5SDavid du Colombier else if (addrs == 1) { 410*63afb9a5SDavid du Colombier /* common case: dial one address without forking */ 411*63afb9a5SDavid du Colombier if (parsecs(dp, &clone2, &dest) >= 0 && 412*63afb9a5SDavid du Colombier (dfd = call1(clone2, dest, dp, conn)) < 0) { 413*63afb9a5SDavid du Colombier pickuperr(besterr); 414*63afb9a5SDavid du Colombier werrstr("%s", besterr); 415*63afb9a5SDavid du Colombier } 416*63afb9a5SDavid du Colombier } else 417*63afb9a5SDavid du Colombier dfd = dialmulti(dp); 418*63afb9a5SDavid du Colombier 419*63afb9a5SDavid du Colombier freedest(dp); 420*63afb9a5SDavid du Colombier return dfd; 421*63afb9a5SDavid du Colombier } 422*63afb9a5SDavid du Colombier 423*63afb9a5SDavid du Colombier /* returns dfd, stores cfd through cfdp */ 424*63afb9a5SDavid du Colombier static int 425*63afb9a5SDavid du Colombier call(char *clone, char *dest, Dest *dp, Conn *conn) 426*63afb9a5SDavid du Colombier { 427*63afb9a5SDavid du Colombier int fd, cfd, n, calleralarm, oalarm; 428*63afb9a5SDavid du Colombier char cname[Maxpath], name[Maxpath], data[Maxpath], *p; 429*63afb9a5SDavid du Colombier DS *ds; 430*63afb9a5SDavid du Colombier 431*63afb9a5SDavid du Colombier /* because cs is in a different name space, replace the mount point */ 432*63afb9a5SDavid du Colombier if(*clone == '/'){ 433*63afb9a5SDavid du Colombier p = strchr(clone+1, '/'); 434*63afb9a5SDavid du Colombier if(p == nil) 435*63afb9a5SDavid du Colombier p = clone; 436*63afb9a5SDavid du Colombier else 437*63afb9a5SDavid du Colombier p++; 438*63afb9a5SDavid du Colombier } else 439*63afb9a5SDavid du Colombier p = clone; 440*63afb9a5SDavid du Colombier ds = dp->ds; 441*63afb9a5SDavid du Colombier snprint(cname, sizeof cname, "%s/%s", ds->netdir, p); 442*63afb9a5SDavid du Colombier 443*63afb9a5SDavid du Colombier conn->cfd = cfd = open(cname, ORDWR); 444*63afb9a5SDavid du Colombier if(cfd < 0) 445*63afb9a5SDavid du Colombier return -1; 446*63afb9a5SDavid du Colombier 447*63afb9a5SDavid du Colombier /* get directory name */ 448*63afb9a5SDavid du Colombier n = read(cfd, name, sizeof(name)-1); 449*63afb9a5SDavid du Colombier if(n < 0){ 450*63afb9a5SDavid du Colombier closeopenfd(&conn->cfd); 451*63afb9a5SDavid du Colombier return -1; 452*63afb9a5SDavid du Colombier } 453*63afb9a5SDavid du Colombier name[n] = 0; 454*63afb9a5SDavid du Colombier for(p = name; *p == ' '; p++) 455*63afb9a5SDavid du Colombier ; 456*63afb9a5SDavid du Colombier snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0)); 457*63afb9a5SDavid du Colombier p = strrchr(cname, '/'); 458*63afb9a5SDavid du Colombier *p = 0; 459*63afb9a5SDavid du Colombier if(ds->dir) 460*63afb9a5SDavid du Colombier snprint(conn->dir, NETPATHLEN, "%s/%s", cname, name); 461*63afb9a5SDavid du Colombier snprint(data, sizeof(data), "%s/%s/data", cname, name); 462*63afb9a5SDavid du Colombier 463*63afb9a5SDavid du Colombier /* should be no alarm pending now; re-instate caller's alarm, if any */ 464*63afb9a5SDavid du Colombier calleralarm = dp->oalarm > 0; 465*63afb9a5SDavid du Colombier if (calleralarm) 466*63afb9a5SDavid du Colombier alarm(dp->oalarm); 467*63afb9a5SDavid du Colombier else if (dp->naddrs > 1) /* in a sub-process? */ 468*63afb9a5SDavid du Colombier alarm(Maxconnms); 469*63afb9a5SDavid du Colombier 470*63afb9a5SDavid du Colombier /* connect */ 471*63afb9a5SDavid du Colombier if(ds->local) 472*63afb9a5SDavid du Colombier snprint(name, sizeof(name), "connect %s %s", dest, ds->local); 473*63afb9a5SDavid du Colombier else 474*63afb9a5SDavid du Colombier snprint(name, sizeof(name), "connect %s", dest); 475*63afb9a5SDavid du Colombier if(write(cfd, name, strlen(name)) < 0){ 476*63afb9a5SDavid du Colombier closeopenfd(&conn->cfd); 477*63afb9a5SDavid du Colombier return -1; 478*63afb9a5SDavid du Colombier } 479*63afb9a5SDavid du Colombier 480*63afb9a5SDavid du Colombier oalarm = alarm(0); /* don't let alarm interrupt critical section */ 481*63afb9a5SDavid du Colombier if (calleralarm) 482*63afb9a5SDavid du Colombier dp->oalarm = oalarm; /* time has passed, so update user's */ 483*63afb9a5SDavid du Colombier 484*63afb9a5SDavid du Colombier /* open data connection */ 485*63afb9a5SDavid du Colombier fd = open(data, ORDWR); 486*63afb9a5SDavid du Colombier if(fd < 0){ 487*63afb9a5SDavid du Colombier closeopenfd(&conn->cfd); 488*63afb9a5SDavid du Colombier alarm(dp->oalarm); 489*63afb9a5SDavid du Colombier return -1; 490*63afb9a5SDavid du Colombier } 491*63afb9a5SDavid du Colombier if(ds->cfdp == nil) 492*63afb9a5SDavid du Colombier closeopenfd(&conn->cfd); 493*63afb9a5SDavid du Colombier 494*63afb9a5SDavid du Colombier alarm(calleralarm? dp->oalarm: 0); 495*63afb9a5SDavid du Colombier return fd; 496*63afb9a5SDavid du Colombier } 497*63afb9a5SDavid du Colombier 498*63afb9a5SDavid du Colombier /* 499*63afb9a5SDavid du Colombier * assume p points at first '!' in dial string. st is start of dial string. 500*63afb9a5SDavid du Colombier * there could be subdirs of the conn dirs (e.g., ssh/0) that must count as 501*63afb9a5SDavid du Colombier * part of the proto string, so skip numeric components. 502*63afb9a5SDavid du Colombier * returns pointer to delimiter after right-most non-numeric component. 503*63afb9a5SDavid du Colombier */ 504*63afb9a5SDavid du Colombier static char * 505*63afb9a5SDavid du Colombier backoverchans(char *st, char *p) 506*63afb9a5SDavid du Colombier { 507*63afb9a5SDavid du Colombier char *sl; 508*63afb9a5SDavid du Colombier 509*63afb9a5SDavid du Colombier for (sl = p; --p >= st && isascii(*p) && isdigit(*p); sl = p) { 510*63afb9a5SDavid du Colombier while (--p >= st && isascii(*p) && isdigit(*p)) 511*63afb9a5SDavid du Colombier ; 512*63afb9a5SDavid du Colombier if (p < st || *p != '/') 513*63afb9a5SDavid du Colombier break; /* "net.alt2" or ran off start */ 514*63afb9a5SDavid du Colombier while (p > st && p[-1] == '/') /* skip runs of slashes */ 515*63afb9a5SDavid du Colombier p--; 516*63afb9a5SDavid du Colombier } 517*63afb9a5SDavid du Colombier return sl; 518*63afb9a5SDavid du Colombier } 519*63afb9a5SDavid du Colombier 520*63afb9a5SDavid du Colombier /* 521*63afb9a5SDavid du Colombier * parse a dial string 522*63afb9a5SDavid du Colombier */ 523*63afb9a5SDavid du Colombier static void 524*63afb9a5SDavid du Colombier _dial_string_parse(char *str, DS *ds) 525*63afb9a5SDavid du Colombier { 526*63afb9a5SDavid du Colombier char *p, *p2; 527*63afb9a5SDavid du Colombier 528*63afb9a5SDavid du Colombier strncpy(ds->buf, str, Maxstring); 529*63afb9a5SDavid du Colombier ds->buf[Maxstring-1] = 0; 530*63afb9a5SDavid du Colombier 531*63afb9a5SDavid du Colombier p = strchr(ds->buf, '!'); 532*63afb9a5SDavid du Colombier if(p == 0) { 533*63afb9a5SDavid du Colombier ds->netdir = 0; 534*63afb9a5SDavid du Colombier ds->proto = "net"; 535*63afb9a5SDavid du Colombier ds->rem = ds->buf; 536*63afb9a5SDavid du Colombier } else { 537*63afb9a5SDavid du Colombier if(*ds->buf != '/' && *ds->buf != '#'){ 538*63afb9a5SDavid du Colombier ds->netdir = 0; 539*63afb9a5SDavid du Colombier ds->proto = ds->buf; 540*63afb9a5SDavid du Colombier } else { 541*63afb9a5SDavid du Colombier p2 = backoverchans(ds->buf, p); 542*63afb9a5SDavid du Colombier 543*63afb9a5SDavid du Colombier /* back over last component of netdir (proto) */ 544*63afb9a5SDavid du Colombier while (--p2 > ds->buf && *p2 != '/') 545*63afb9a5SDavid du Colombier ; 546*63afb9a5SDavid du Colombier *p2++ = 0; 547*63afb9a5SDavid du Colombier ds->netdir = ds->buf; 548*63afb9a5SDavid du Colombier ds->proto = p2; 549*63afb9a5SDavid du Colombier } 550*63afb9a5SDavid du Colombier *p = 0; 551*63afb9a5SDavid du Colombier ds->rem = p + 1; 552*63afb9a5SDavid du Colombier } 553*63afb9a5SDavid du Colombier } 554