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