#include <u.h>
#include <libc.h>
#include <bio.h>
#include <ip.h>
#include <ndb.h>

void    pip(char*, char*);
void    pdk(char*, char*);
void    nstat(char*, void (*)(char*, char*));

Ndb     *ndb;
Biobuf  out;

void
main(void)
{
       ndb = ndbopen(0);

       Binit(&out, 1, OWRITE);

       nstat("tcp", pip);
       nstat("udp", pip);
       nstat("il", pip);
       nstat("dk", pdk);
       exits(0);
}

void
nstat(char *net, void (*f)(char*, char*))
{
       int fdir, i, n, tot;
       char dir[500*DIRLEN], *mem;

       sprint(dir, "/net/%s", net);
       fdir = open(dir, OREAD);
       if(fdir < 0)
               return;

       mem = sbrk(0);
       tot = 0;
       while((n = read(fdir, dir, sizeof dir)) > 0){
               if(brk((void*)(mem + tot + n)) == -1) {
                       fprint(2, "netstat: out of memory");
                       return;
               }
               memmove(mem+tot, dir, n);
               tot += n;
       }
       for(i = 0; i < tot; i += DIRLEN) {
               (*f)(net, mem+i);
               Bflush(&out);
       }
       close(fdir);
}

void
pdk(char *net, char *entry)
{
       Dir db;
       int n, fd;
       char buf[128], *p, *t;

       if(strcmp(entry, "clone") == 0)
               return;

       sprint(buf, "/net/%s/%s/ctl", net, entry);
       if(dirstat(buf, &db) < 0)
               return;

       sprint(buf, "/net/%s/%s/status", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0)
               return;
       n = read(fd, buf, sizeof(buf));
       if(n < 0)
               return;
       buf[n] = 0;
       close(fd);

       p = strchr(buf, ' ');
       if(p == 0)
               return;
       p = strchr(p+1, ' ');
       if(p == 0)
               return;
       t = strchr(p+1, ' ');
       if(t == 0)
               return;
       *t = 0;
       Bprint(&out, "%-4s %-4s %-10s %-12s ", net, entry, db.uid, p);

       sprint(buf, "/net/%s/%s/local", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0) {
               Bprint(&out, "\n");
               return;
       }
       n = read(fd, buf, sizeof(buf));
       if(n < 0) {
               Bprint(&out, "\n");
               return;
       }
       buf[n-1] = 0;
       p = strchr(buf, '!');
       if(p == 0) {
               Bprint(&out, "\n");
               return;
       }
       Bprint(&out, "%-10s ", p+1);

       sprint(buf, "/net/%s/%s/remote", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0) {
               Bprint(&out, "\n", buf);
               return;
       }
       n = read(fd, buf, sizeof(buf));
       if(n < 0) {
               Bprint(&out, "\n");
               return;
       }
       buf[n-1] = 0;
       Bprint(&out, "%s\n", buf);
}

char*
getport(char *net, char *p)
{
       Ndbs s;
       static Ndbtuple *t;
       static Ndbtuple *nt;

       t = ndbsearch(ndb, &s, "port", p);
       while(t){
               for(nt = t; nt; nt = nt->entry) {
                       if(strcmp(nt->attr, net) == 0)
                               return nt->val;
               }
               ndbfree(t);
               t = ndbsnext(&s, "port", p);
       }
       return p;
}

void
pip(char *net, char *entry)
{
       Dir db;
       Ipinfo ipi;
       int n, fd;
       char buf[128], *p, *t;

       if(strcmp(entry, "clone") == 0)
               return;

       sprint(buf, "/net/%s/%s/ctl", net, entry);
       if(dirstat(buf, &db) < 0)
               return;

       sprint(buf, "/net/%s/%s/status", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0)
               return;
       n = read(fd, buf, sizeof(buf));
       if(n < 0)
               return;
       buf[n] = 0;
       close(fd);

       p = " Dgram";
       if(strcmp(net, "udp") != 0) {
               p = strchr(buf, ' ');
               if(p == 0)
                       return;
               p = strchr(p+1, ' ');
               if(p == 0)
                       return;
               t = strchr(p+1, ' ');
               if(t == 0)
                       return;
               *t = 0;
       }
       Bprint(&out, "%-4s %-4s %-10s %-12s ", net, entry, db.uid, p);

       sprint(buf, "/net/%s/%s/local", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0) {
               Bprint(&out, "\n");
               return;
       }
       n = read(fd, buf, sizeof(buf));
       if(n < 0) {
               Bprint(&out, "\n");
               return;
       }
       buf[n-1] = 0;
       close(fd);
       p = strchr(buf, '!');
       if(p == 0) {
               Bprint(&out, "\n");
               return;
       }
       *p = '\0';
       Bprint(&out, "%-10s ", getport(net, p+1));

       sprint(buf, "/net/%s/%s/remote", net, entry);
       fd = open(buf, OREAD);
       if(fd < 0) {
               print("\n");
               return;
       }
       n = read(fd, buf, sizeof(buf));
       if(n < 0) {
               print("\n");
               return;
       }
       buf[n-1] = 0;
       close(fd);
       p = strchr(buf, '!');
       *p++ = '\0';

       n = ipinfo(ndb, 0, buf, 0, &ipi);
       if(n < 0) {
               Bprint(&out, "%-10s %s\n", getport(net, p), buf);
               return;
       }
       Bprint(&out, "%-10s %s\n", getport(net, p), ipi.domain);
}