libc: restoring simple sequential version of dial()
This commit is contained in:
parent
76918f348f
commit
62fb4f9717
4 changed files with 41 additions and 541 deletions
|
@ -1,24 +1,16 @@
|
||||||
/*
|
|
||||||
* dial - connect to a service (parallel version)
|
|
||||||
*/
|
|
||||||
#include <u.h>
|
#include <u.h>
|
||||||
#include <libc.h>
|
#include <libc.h>
|
||||||
|
|
||||||
typedef struct Conn Conn;
|
|
||||||
typedef struct Dest Dest;
|
|
||||||
typedef struct DS DS;
|
typedef struct DS DS;
|
||||||
|
|
||||||
|
static int call(char*, char*, DS*);
|
||||||
|
static int csdial(DS*);
|
||||||
|
static void _dial_string_parse(char*, DS*);
|
||||||
|
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
Maxstring = 128,
|
Maxstring = 128,
|
||||||
Maxpath = 256,
|
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 {
|
struct DS {
|
||||||
|
@ -34,42 +26,12 @@ struct DS {
|
||||||
int *cfdp;
|
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'
|
* the dialstring is of the form '[/net/]proto!dest'
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
dialimpl(char *dest, char *local, char *dir, int *cfdp)
|
dial(char *dest, char *local, char *dir, int *cfdp)
|
||||||
{
|
{
|
||||||
DS ds;
|
DS ds;
|
||||||
int rv;
|
int rv;
|
||||||
|
@ -107,224 +69,11 @@ dialimpl(char *dest, char *local, char *dir, int *cfdp)
|
||||||
return rv;
|
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
|
static int
|
||||||
csdial(DS *ds)
|
csdial(DS *ds)
|
||||||
{
|
{
|
||||||
int n, fd, rv, addrs, bleft;
|
int n, fd, rv;
|
||||||
char c;
|
char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* open connection server
|
* open connection server
|
||||||
|
@ -334,10 +83,7 @@ csdial(DS *ds)
|
||||||
if(fd < 0){
|
if(fd < 0){
|
||||||
/* no connection server, don't translate */
|
/* no connection server, don't translate */
|
||||||
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
|
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
|
||||||
rv = call(clone, ds->rem, ds, dp, &dp->conn[0]);
|
return call(clone, ds->rem, ds);
|
||||||
fillinds(ds, dp);
|
|
||||||
freedest(dp);
|
|
||||||
return rv;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -346,57 +92,41 @@ csdial(DS *ds)
|
||||||
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
||||||
if(write(fd, buf, strlen(buf)) < 0){
|
if(write(fd, buf, strlen(buf)) < 0){
|
||||||
close(fd);
|
close(fd);
|
||||||
freedest(dp);
|
|
||||||
return -1;
|
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);
|
seek(fd, 0, 0);
|
||||||
addrs = 0;
|
while((n = read(fd, buf, sizeof(buf) - 1)) > 0){
|
||||||
addrp = dp->nextaddr = dp->addrlist;
|
buf[n] = 0;
|
||||||
bleft = sizeof dp->addrlist - 2; /* 2 is room for \n\0 */
|
p = strchr(buf, ' ');
|
||||||
while(bleft > 0 && (n = read(fd, addrp, bleft)) > 0) {
|
if(p == 0)
|
||||||
if (addrp[n-1] != '\n')
|
continue;
|
||||||
addrp[n++] = '\n';
|
*p++ = 0;
|
||||||
addrs++;
|
rv = call(buf, p, ds);
|
||||||
addrp += n;
|
if(rv >= 0)
|
||||||
bleft -= n;
|
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);
|
close(fd);
|
||||||
|
|
||||||
*besterr = 0;
|
if(rv < 0 && *besterr)
|
||||||
rv = -1; /* pessimistic default */
|
werrstr("%s", besterr);
|
||||||
if (addrs == 0)
|
else
|
||||||
werrstr("no address to dial");
|
werrstr("%s", err);
|
||||||
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);
|
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
|
call(char *clone, char *dest, DS *ds)
|
||||||
{
|
{
|
||||||
int fd, cfd, n;
|
int fd, cfd, n;
|
||||||
char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
|
char cname[Maxpath], name[Maxpath], data[Maxpath], *p;
|
||||||
|
@ -412,15 +142,14 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
|
||||||
p = clone;
|
p = clone;
|
||||||
snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
|
snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
|
||||||
|
|
||||||
conn->pid = getpid();
|
cfd = open(cname, ORDWR);
|
||||||
conn->cfd = cfd = open(cname, ORDWR);
|
|
||||||
if(cfd < 0)
|
if(cfd < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
/* get directory name */
|
/* get directory name */
|
||||||
n = read(cfd, name, sizeof(name)-1);
|
n = read(cfd, name, sizeof(name)-1);
|
||||||
if(n < 0){
|
if(n < 0){
|
||||||
closeopenfd(&conn->cfd);
|
close(cfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
name[n] = 0;
|
name[n] = 0;
|
||||||
|
@ -430,7 +159,7 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
|
||||||
p = strrchr(cname, '/');
|
p = strrchr(cname, '/');
|
||||||
*p = 0;
|
*p = 0;
|
||||||
if(ds->dir)
|
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);
|
snprint(data, sizeof(data), "%s/%s/data", cname, name);
|
||||||
|
|
||||||
/* connect */
|
/* connect */
|
||||||
|
@ -439,23 +168,20 @@ call(char *clone, char *dest, DS *ds, Dest *dp, Conn *conn)
|
||||||
else
|
else
|
||||||
snprint(name, sizeof(name), "connect %s", dest);
|
snprint(name, sizeof(name), "connect %s", dest);
|
||||||
if(write(cfd, name, strlen(name)) < 0){
|
if(write(cfd, name, strlen(name)) < 0){
|
||||||
closeopenfd(&conn->cfd);
|
close(cfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* open data connection */
|
/* open data connection */
|
||||||
conn->dfd = fd = open(data, ORDWR);
|
fd = open(data, ORDWR);
|
||||||
if(fd < 0){
|
if(fd < 0){
|
||||||
closeopenfd(&conn->cfd);
|
close(cfd);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if(ds->cfdp == nil)
|
if(ds->cfdp)
|
||||||
closeopenfd(&conn->cfd);
|
*ds->cfdp = cfd;
|
||||||
|
else
|
||||||
qlock(&dp->winlck);
|
close(cfd);
|
||||||
if (dp->winner < 0 && conn < dp->connend)
|
|
||||||
dp->winner = conn - dp->conn;
|
|
||||||
qunlock(&dp->winlck);
|
|
||||||
return fd;
|
return fd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,221 +0,0 @@
|
||||||
/*
|
|
||||||
* old single-process version of dial that libthread can cope with
|
|
||||||
*/
|
|
||||||
#include <u.h>
|
|
||||||
#include <libc.h>
|
|
||||||
|
|
||||||
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,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct DS {
|
|
||||||
/* dist string */
|
|
||||||
char buf[Maxstring];
|
|
||||||
char *netdir;
|
|
||||||
char *proto;
|
|
||||||
char *rem;
|
|
||||||
|
|
||||||
/* other args */
|
|
||||||
char *local;
|
|
||||||
char *dir;
|
|
||||||
int *cfdp;
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* the dialstring is of the form '[/net/]proto!dest'
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
_threaddial(char *dest, char *local, char *dir, int *cfdp)
|
|
||||||
{
|
|
||||||
DS ds;
|
|
||||||
int rv;
|
|
||||||
char err[ERRMAX], alterr[ERRMAX];
|
|
||||||
|
|
||||||
ds.local = local;
|
|
||||||
ds.dir = dir;
|
|
||||||
ds.cfdp = cfdp;
|
|
||||||
|
|
||||||
_dial_string_parse(dest, &ds);
|
|
||||||
if(ds.netdir)
|
|
||||||
return csdial(&ds);
|
|
||||||
|
|
||||||
ds.netdir = "/net";
|
|
||||||
rv = csdial(&ds);
|
|
||||||
if(rv >= 0)
|
|
||||||
return rv;
|
|
||||||
err[0] = '\0';
|
|
||||||
errstr(err, sizeof err);
|
|
||||||
if(strstr(err, "refused") != 0){
|
|
||||||
werrstr("%s", err);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
ds.netdir = "/net.alt";
|
|
||||||
rv = csdial(&ds);
|
|
||||||
if(rv >= 0)
|
|
||||||
return rv;
|
|
||||||
|
|
||||||
alterr[0] = 0;
|
|
||||||
errstr(alterr, sizeof alterr);
|
|
||||||
if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
|
|
||||||
werrstr("%s", err);
|
|
||||||
else
|
|
||||||
werrstr("%s", alterr);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
csdial(DS *ds)
|
|
||||||
{
|
|
||||||
int n, fd, rv;
|
|
||||||
char *p, buf[Maxstring], clone[Maxpath], err[ERRMAX], besterr[ERRMAX];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* open connection server
|
|
||||||
*/
|
|
||||||
snprint(buf, sizeof(buf), "%s/cs", ds->netdir);
|
|
||||||
fd = open(buf, ORDWR);
|
|
||||||
if(fd < 0){
|
|
||||||
/* no connection server, don't translate */
|
|
||||||
snprint(clone, sizeof(clone), "%s/%s/clone", ds->netdir, ds->proto);
|
|
||||||
return call(clone, ds->rem, ds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* ask connection server to translate
|
|
||||||
*/
|
|
||||||
snprint(buf, sizeof(buf), "%s!%s", ds->proto, ds->rem);
|
|
||||||
if(write(fd, buf, strlen(buf)) < 0){
|
|
||||||
close(fd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* loop through each address from the connection server till
|
|
||||||
* we get one that works.
|
|
||||||
*/
|
|
||||||
*besterr = 0;
|
|
||||||
rv = -1;
|
|
||||||
seek(fd, 0, 0);
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
|
|
||||||
if(rv < 0 && *besterr)
|
|
||||||
werrstr("%s", besterr);
|
|
||||||
else
|
|
||||||
werrstr("%s", err);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int
|
|
||||||
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 == '/'){
|
|
||||||
p = strchr(clone+1, '/');
|
|
||||||
if(p == nil)
|
|
||||||
p = clone;
|
|
||||||
else
|
|
||||||
p++;
|
|
||||||
} else
|
|
||||||
p = clone;
|
|
||||||
snprint(cname, sizeof cname, "%s/%s", ds->netdir, p);
|
|
||||||
|
|
||||||
cfd = open(cname, ORDWR);
|
|
||||||
if(cfd < 0)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
/* get directory name */
|
|
||||||
n = read(cfd, name, sizeof(name)-1);
|
|
||||||
if(n < 0){
|
|
||||||
close(cfd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
name[n] = 0;
|
|
||||||
for(p = name; *p == ' '; p++)
|
|
||||||
;
|
|
||||||
snprint(name, sizeof(name), "%ld", strtoul(p, 0, 0));
|
|
||||||
p = strrchr(cname, '/');
|
|
||||||
*p = 0;
|
|
||||||
if(ds->dir)
|
|
||||||
snprint(ds->dir, NETPATHLEN, "%s/%s", cname, name);
|
|
||||||
snprint(data, sizeof(data), "%s/%s/data", cname, name);
|
|
||||||
|
|
||||||
/* connect */
|
|
||||||
if(ds->local)
|
|
||||||
snprint(name, sizeof(name), "connect %s %s", dest, ds->local);
|
|
||||||
else
|
|
||||||
snprint(name, sizeof(name), "connect %s", dest);
|
|
||||||
if(write(cfd, name, strlen(name)) < 0){
|
|
||||||
close(cfd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* open data connection */
|
|
||||||
fd = open(data, ORDWR);
|
|
||||||
if(fd < 0){
|
|
||||||
close(cfd);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
if(ds->cfdp)
|
|
||||||
*ds->cfdp = cfd;
|
|
||||||
else
|
|
||||||
close(cfd);
|
|
||||||
return fd;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse a dial string
|
|
||||||
*/
|
|
||||||
static void
|
|
||||||
_dial_string_parse(char *str, DS *ds)
|
|
||||||
{
|
|
||||||
char *p, *p2;
|
|
||||||
|
|
||||||
strncpy(ds->buf, str, Maxstring);
|
|
||||||
ds->buf[Maxstring-1] = 0;
|
|
||||||
|
|
||||||
p = strchr(ds->buf, '!');
|
|
||||||
if(p == 0) {
|
|
||||||
ds->netdir = 0;
|
|
||||||
ds->proto = "net";
|
|
||||||
ds->rem = ds->buf;
|
|
||||||
} else {
|
|
||||||
if(*ds->buf != '/' && *ds->buf != '#'){
|
|
||||||
ds->netdir = 0;
|
|
||||||
ds->proto = ds->buf;
|
|
||||||
} else {
|
|
||||||
for(p2 = p; *p2 != '/'; p2--)
|
|
||||||
;
|
|
||||||
*p2++ = 0;
|
|
||||||
ds->netdir = ds->buf;
|
|
||||||
ds->proto = p2;
|
|
||||||
}
|
|
||||||
*p = 0;
|
|
||||||
ds->rem = p + 1;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -17,9 +17,6 @@ static jmp_buf _mainjmp;
|
||||||
static void mainlauncher(void*);
|
static void mainlauncher(void*);
|
||||||
extern void (*_sysfatal)(char*, va_list);
|
extern void (*_sysfatal)(char*, va_list);
|
||||||
extern void (*__assert)(char*);
|
extern void (*__assert)(char*);
|
||||||
extern int (*_dial)(char*, char*, char*, int*);
|
|
||||||
|
|
||||||
extern int _threaddial(char*, char*, char*, int*);
|
|
||||||
|
|
||||||
static Proc **mainp;
|
static Proc **mainp;
|
||||||
|
|
||||||
|
@ -38,7 +35,6 @@ main(int argc, char **argv)
|
||||||
_systhreadinit();
|
_systhreadinit();
|
||||||
_qlockinit(_threadrendezvous);
|
_qlockinit(_threadrendezvous);
|
||||||
_sysfatal = _threadsysfatal;
|
_sysfatal = _threadsysfatal;
|
||||||
_dial = _threaddial;
|
|
||||||
__assert = _threadassert;
|
__assert = _threadassert;
|
||||||
notify(_threadnote);
|
notify(_threadnote);
|
||||||
if(mainstacksize == 0)
|
if(mainstacksize == 0)
|
||||||
|
|
|
@ -8,7 +8,6 @@ OFILES=\
|
||||||
chanprint.$O\
|
chanprint.$O\
|
||||||
create.$O\
|
create.$O\
|
||||||
debug.$O\
|
debug.$O\
|
||||||
dial.$O\
|
|
||||||
exec.$O\
|
exec.$O\
|
||||||
exit.$O\
|
exit.$O\
|
||||||
id.$O\
|
id.$O\
|
||||||
|
|
Loading…
Reference in a new issue