<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv=Content-Type content="text/html; charset=utf8">
<title>/usr/web/sources/contrib/cinap_lenrek/dial.c - Plan 9 from Bell Labs</title>
<!-- THIS FILE IS AUTOMATICALLY GENERATED. -->
<!-- EDIT sources.tr INSTEAD. -->
</meta>
</head>
<body>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"><a href="/plan9/">Plan 9 from Bell Labs</a>&rsquo;s /usr/web/sources/contrib/cinap_lenrek/dial.c</span></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
Copyright © 2009 Alcatel-Lucent.<br />
Distributed under the
<a href="/plan9/license.html">Lucent Public License version 1.02</a>.
<br />
<a href="/plan9/download.html">Download the Plan 9 distribution.</a>
</font>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<table width="100%" cellspacing=0 border=0><tr><td align="center">
<table cellspacing=0 cellpadding=5 bgcolor="#eeeeff"><tr><td align="left">
<pre>
<!-- END HEADER -->
#include &lt;u.h&gt;
#include &lt;libc.h&gt;

enum
{
       Maxconcurr      = 4,
       Maxstring       = 128,
};

typedef struct DS DS;
typedef struct Conn Conn;

struct DS {
       /* dist string */
       char    *netdir;
       char    *proto;
       char    *rem;

       /* other args */
       char    *local;
       char    *dir;
       int     *cfdp;
};

struct Conn {
       Conn    *next;

       int     pid;

       int     cfd;
       int     dfd;

       char    dest[Maxstring];
       char    dir[NETPATHLEN];
};

static Conn*
openconn(char *clone, char *dest, char *netdir)
{
       char *x, *p, *e;
       Conn *c;
       int n;

       if((c = malloc(sizeof(Conn))) == nil)
               return nil;

       c-&gt;next = nil;
       c-&gt;pid = 0;
       c-&gt;cfd = -1;
       c-&gt;dfd = -1;

       snprint(c-&gt;dest, sizeof c-&gt;dest, "%s", dest);

       if(netdir){
               if(*clone == '/' &amp;&amp; (p = strchr(clone+1, '/')))
                       clone = ++p;
               snprint(c-&gt;dir, sizeof c-&gt;dir, "%s/%s", netdir, clone);
       } else
               snprint(c-&gt;dir, sizeof c-&gt;dir, "%s", clone);

       e = c-&gt;dir + sizeof c-&gt;dir;
       if((p = strrchr(c-&gt;dir, '/')) == nil)
               goto err;
       if((c-&gt;cfd = open(c-&gt;dir, ORDWR)) &lt; 0)
               goto err;
       if((n = (e - p)-1) &lt;= 0)
               goto err;
       if((n = read(c-&gt;cfd, p, n)) &lt;= 0)
               goto err;
       p[n] = 0;
       for(x = p; *x == ' '; x++)
               ;
       snprint(p, e - p, "/%ld/data", strtoul(x, 0, 0));

       if((c-&gt;dfd = open(c-&gt;dir, ORDWR)) &lt; 0)
               goto err;
       if(p = strrchr(c-&gt;dir, '/'))
               *p = 0;
       return c;

err:
       if(c-&gt;cfd &gt;= 0)
               close(c-&gt;cfd);
       if(c-&gt;dfd &gt;= 0)
               close(c-&gt;dfd);
       free(c);
       return nil;
}

static char*
readcs(int cs, char *buf, int nbuf, char **destp)
{
       char *p;
       int n;

       if((n = read(cs, buf, nbuf-1)) &lt;= 0)
               return nil;
       if(buf[n-1] == '\n')
               n--;
       buf[n] = 0;
       if((p = strchr(buf, ' ')) == nil)
               return nil;
       *p++ = 0;
       if(destp)
               *destp = p;
       return buf;
}

static Conn*
getconn(int cs, char *buf, int nbuf, char *netdir)
{
       char *clone, *dest;

       if(clone = readcs(cs, buf, nbuf, &amp;dest))
               return openconn(clone, dest, netdir);
       return nil;
}


static int
connect(Conn *c, char *local)
{
       if(local)
               return fprint(c-&gt;cfd, "connect %s %s", c-&gt;dest, local) &gt; 0;
       else
               return fprint(c-&gt;cfd, "connect %s", c-&gt;dest) &gt; 0;
}

static int
aconnect(Conn *c, char *local)
{
       if((c-&gt;pid = rfork(RFPROC)) &lt; 0)
               return 0;
       else if(c-&gt;pid &gt; 0)
               return 1;

       notify(nil);
       if(connect(c, local))
               _exits(nil);
       _exits("%r");
       return -1;
}

static int
canfork(char *buf, int nbuf)
{
       int fd;

       snprint(buf, nbuf, "/proc/%d/note", getpid());
       if((fd = open(buf, OWRITE)) &gt;= 0)
               close(fd);
       return fd &gt;= 0;
}

static int
csdial(DS *ds)
{
       char buf[Maxstring+NETPATHLEN+4];
       Conn *conns, *winner, *c;
       int cs, ret, kids, more;

       conns = winner = nil;
       snprint(buf, sizeof buf, "%s/cs", ds-&gt;netdir);
       if((cs = open(buf, ORDWR)) &lt; 0){
               snprint(buf, sizeof buf, "%s/%s/clone", ds-&gt;netdir, ds-&gt;proto);
               if((conns = openconn(buf, ds-&gt;rem, nil)) == nil)
                       goto out;
               if(connect(conns, ds-&gt;local))
                       winner = conns;
               goto out;
       }

       if(fprint(cs, "%s!%s", ds-&gt;proto, ds-&gt;rem) &lt; 0)
               goto out;

       seek(cs, 0, 0);
       if((conns = getconn(cs, buf, sizeof buf, ds-&gt;netdir)) == nil){
               werrstr("no address to dial");
               goto out;
       }
       conns-&gt;next = getconn(cs, buf, sizeof buf, ds-&gt;netdir);
       if(conns-&gt;next == nil || !canfork(buf, sizeof buf)){
               if(connect(c = conns, ds-&gt;local)){
                       winner = c;
                       goto out;
               }
               if((c = c-&gt;next) == nil)
                       goto out;
               if(connect(c, ds-&gt;local)){
                       winner = c;
                       goto out;
               }
               while(c-&gt;next = getconn(cs, buf, sizeof buf, ds-&gt;netdir)){
                       if(connect(c = c-&gt;next, ds-&gt;local)){
                               winner = c;
                               goto out;
                       }
               }
               goto out;
       }

       more = 1;
       kids = 0;
       if(aconnect(conns, ds-&gt;local))
               kids++;
       if(aconnect(conns-&gt;next, ds-&gt;local))
               kids++;
       for(;;){
               Waitmsg *m;

               while(more &amp;&amp; kids &lt; Maxconcurr){
                       if((c = getconn(cs, buf, sizeof buf, ds-&gt;netdir)) == nil){
                               more = 0;
                               break;
                       }
                       c-&gt;next = conns;
                       conns = c;
                       if(aconnect(c, ds-&gt;local))
                               kids++;
               }

               if(kids == 0)
                       break;

               if(m = wait()){
                       for(c = conns; c; c = c-&gt;next){
                               if(c-&gt;pid != m-&gt;pid)
                                       continue;
                               c-&gt;pid = 0;
                               --kids;
                               if(m-&gt;msg[0]){
                                       char *p;

                                       if(p = strchr(m-&gt;msg, ':'))
                                               p++;
                                       else
                                               p = m-&gt;msg;
                                       while(*p == ' ')
                                               p++;
                                       werrstr("%s", p);
                               } else if(winner)
                                       fprint(c-&gt;cfd, "hangup");
                               else
                                       winner = c;
                               break;
                       }
                       free(m);
               }

               if(winner || m == nil){
                       more = 0;
                       for(c = conns; c; c = c-&gt;next)
                               if(c-&gt;pid)
                                       postnote(PNPROC, c-&gt;pid, "die");
               }
       }

out:
       if(cs &gt;= 0)
               close(cs);
       if(c = winner){
               if(ds-&gt;dir)
                       strncpy(ds-&gt;dir, c-&gt;dir, NETPATHLEN);
               if(ds-&gt;cfdp)
                       *ds-&gt;cfdp = c-&gt;cfd;
               else
                       close(c-&gt;cfd);
               ret = c-&gt;dfd;
       } else
               ret = -1;
       while(c = conns){
               conns = c-&gt;next;
               if(c != winner){
                       close(c-&gt;cfd);
                       close(c-&gt;dfd);
               }
               free(c);
       }
       return ret;
}

int
dial(char *dest, char *local, char *dir, int *cfdp)
{
       char buf[Maxstring], *p, *x;
       int ret;
       DS ds;

       ds.local = local;
       ds.dir = dir;
       ds.cfdp = cfdp;

       snprint(buf, sizeof buf, "%s", dest);

       if((p = strchr(buf, '!')) == 0) {
               ds.netdir = 0;
               ds.proto = "net";
               ds.rem = buf;
       } else {
               if(buf[0] != '/' &amp;&amp; buf[0] != '#'){
                       ds.netdir = 0;
                       ds.proto = buf;
               } else {
                       for(x = p; *x != '/'; x--)
                               ;
                       *x++ = 0;
                       ds.netdir = buf;
                       ds.proto = x;
               }
               *p++ = 0;
               ds.rem = p;
       }

       if(ds.netdir)
               return csdial(&amp;ds);

       ds.netdir = "/net";
       if((ret = csdial(&amp;ds)) &lt; 0){
               char err[ERRMAX];

               rerrstr(err, sizeof err);
               if(strstr(err, "refused"))
                       return ret;

               ds.netdir = "/net.alt";
               if((ret = csdial(&amp;ds)) &lt; 0){
                       char alterr[ERRMAX];

                       /* use previous error if /net.alt was not available */
                       rerrstr(alterr, sizeof alterr);
                       if(strstr(alterr, "translate") || strstr(alterr, "does not exist"))
                               werrstr("%s", err);
               }
       }
       return ret;
}
<!-- BEGIN TAIL -->
</pre>
</td></tr></table>
</td></tr></table>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<p style="line-height: 1.2em; margin-left: 1.00in; text-indent: 0.00in; margin-right: 1.00in; margin-top: 0; margin-bottom: 0; text-align: center;">
<span style="font-size: 10pt"></span></p>
<p style="margin-top: 0; margin-bottom: 0.50in"></p>
<p style="margin-top: 0; margin-bottom: 0.33in"></p>
<center><table border="0"><tr>
<td valign="middle"><a href="http://www.alcatel-lucent.com/"><img border="0" src="/plan9/img/logo_ft.gif" alt="Bell Labs" />
</a></td>
<td valign="middle"><a href="http://www.opensource.org"><img border="0" alt="OSI certified" src="/plan9/img/osi-certified-60x50.gif" />
</a></td>
<td><img style="padding-right: 45px;" alt="Powered by Plan 9" src="/plan9/img/power36.gif" />
</td>
</tr></table></center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center>
<span style="font-size: 10pt">(<a href="/plan9/">Return to Plan 9 Home Page</a>)</span>
</center>
<p style="margin-top: 0; margin-bottom: 0.17in"></p>
<center><font size=-1>
<span style="font-size: 10pt"><a href="http://www.lucent.com/copyright.html">Copyright</a></span>
<span style="font-size: 10pt">© 2009 Alcatel-Lucent.</span>
<span style="font-size: 10pt">All Rights Reserved.</span>
<br />
<span style="font-size: 10pt">Comments to</span>
<span style="font-size: 10pt"><a href="mailto:[email protected]">[email protected]</a>.</span>
</font></center>
</body>
</html>