/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h>#include <libc.h>#include <auth.h>#include <fcall.h>#include <bio.h>#include <ctype.h>#include <ndb.h>#include <ip.h>#include <String.h> enum{ Nreply= 20, Maxreply= 256, Maxrequest= 128, Maxpath= 128, Maxfdata= 8192, Maxhost= 64, /* maximum host name size */ Maxservice= 64, /* maximum service name size */ Qdir= 0, Qcs= 1,}; typedef struct Mfile Mfile;typedef struct Mlist Mlist;typedef struct Network Network;typedef struct Flushreq Flushreq;typedef struct Job Job; int vers; /* incremented each clone/attach */ struct Mfile{ int busy; char *user; Qid qid; int fid; /* * current request */ char *net; char *host; char *serv; char *rem; /* * result of the last lookup */ Network *nextnet; int nreply; char *reply[Nreply]; int replylen[Nreply];}; struct Mlist{ Mlist *next; Mfile mf;}; /* * active requests */struct Job{ Job *next; int flushed; Fcall request; Fcall reply;};Lock joblock;Job *joblist; Mlist *mlist;int mfd[2];int debug;int paranoia;int ipv6lookups = 1;jmp_buf masterjmp; /* return through here after a slave process has been created */int *isslave; /* *isslave non-zero means this is a slave process */char *dbfile;Ndb *db, *netdb; void rversion(Job*);void rflush(Job*);void rattach(Job*, Mfile*);char* rwalk(Job*, Mfile*);void ropen(Job*, Mfile*);void rcreate(Job*, Mfile*);void rread(Job*, Mfile*);void rwrite(Job*, Mfile*);void rclunk(Job*, Mfile*);void rremove(Job*, Mfile*);void rstat(Job*, Mfile*);void rwstat(Job*, Mfile*);void rauth(Job*);void sendmsg(Job*, char*);void error(char*);void mountinit(char*, char*);void io(void);void ndbinit(void);void netinit(int);void netadd(char*);char *genquery(Mfile*, char*);char* ipinfoquery(Mfile*, char**, int);int needproto(Network*, Ndbtuple*);int lookup(Mfile*);Ndbtuple* reorder(Ndbtuple*, Ndbtuple*);void ipid(void);void readipinterfaces(void);void* emalloc(int);char* estrdup(char*);Job* newjob(void);void freejob(Job*);void setext(char*, int, char*);void cleanmf(Mfile*); extern void paralloc(void); Lock dblock; /* mutex on database operations */Lock netlock; /* mutex for netinit() */ char *logfile = "cs";char *paranoiafile = "cs.paranoia"; char mntpt[Maxpath];char netndb[Maxpath]; /* * Network specific translators */Ndbtuple* iplookup(Network*, char*, char*, int);char* iptrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple* telcolookup(Network*, char*, char*, int);char* telcotrans(Ndbtuple*, Network*, char*, char*, int);Ndbtuple* dnsiplookup(char*, Ndbs*); struct Network{ char *net; Ndbtuple *(*lookup)(Network*, char*, char*, int); char *(*trans)(Ndbtuple*, Network*, char*, char*, int); int considered; /* flag: ignored for "net!"? */ int fasttimeouthack; /* flag. was for IL */ Network *next;}; enum{ Ntcp = 0,}; /* * net doesn't apply to (r)udp, icmp(v6), or telco (for speed). */Network network[] = {[Ntcp] { "tcp", iplookup, iptrans, 0 }, { "udp", iplookup, iptrans, 1 }, { "icmp", iplookup, iptrans, 1 }, { "icmpv6", iplookup, iptrans, 1 }, { "rudp", iplookup, iptrans, 1 }, { "ssh", iplookup, iptrans, 1 }, { "telco", telcolookup, telcotrans, 1 }, { 0 },}; Lock ipifclock;Ipifc *ipifcs; char eaddr[16]; /* ascii ethernet address */char ipaddr[64]; /* ascii internet address */uchar ipa[IPaddrlen]; /* binary internet address */char *mysysname; Network *netlist; /* networks ordered by preference */Network *last; static voidnstrcpy(char *to, char *from, int len){ strncpy(to, from, len); to[len-1] = 0;} voidusage(void){ fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0); exits("usage");} /* * based on libthread's threadsetname, but drags in less library code. * actually just sets the arguments displayed. */voidprocsetname(char *fmt, ...){ int fd; char *cmdname; char buf[128]; va_list arg; va_start(arg, fmt); cmdname = vsmprint(fmt, arg); va_end(arg); if (cmdname == nil) return; snprint(buf, sizeof buf, "#p/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, cmdname, strlen(cmdname)+1); close(fd); } free(cmdname);} voidmain(int argc, char *argv[]){ int justsetname; char ext[Maxpath], servefile[Maxpath]; justsetname = 0; setnetmtpt(mntpt, sizeof(mntpt), nil); ext[0] = 0; ARGBEGIN{ case '4': ipv6lookups = 0; break; case 'd': debug = 1; break; case 'f': dbfile = EARGF(usage()); break; case 'n': justsetname = 1; break; case 'x': setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage())); setext(ext, sizeof(ext), mntpt); break; }ARGEND USED(argc); USED(argv); rfork(RFREND|RFNOTEG); snprint(servefile, sizeof(servefile), "#s/cs%s", ext); snprint(netndb, sizeof(netndb), "%s/ndb", mntpt); unmount(servefile, mntpt); remove(servefile); fmtinstall('E', eipfmt); fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); fmtinstall('F', fcallfmt); ndbinit(); netinit(0); if(!justsetname){ mountinit(servefile, mntpt); io(); } exits(0);} /* * if a mount point is specified, set the cs extention to be the mount point * with '_'s replacing '/'s */voidsetext(char *ext, int n, char *p){ int i, c; n--; for(i = 0; i < n; i++){ c = p[i]; if(c == 0) break; if(c == '/') c = '_'; ext[i] = c; } ext[i] = 0;} voidmountinit(char *service, char *mntpt){ int f; int p[2]; char buf[32]; if(pipe(p) < 0) error("pipe failed"); /* * make a /srv/cs */ f = create(service, OWRITE|ORCLOSE, 0666); if(f < 0) error(service); snprint(buf, sizeof(buf), "%d", p[1]); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write /srv/cs"); switch(rfork(RFFDG|RFPROC|RFNAMEG)){ case 0: close(p[1]); procsetname("%s", mntpt); break; case -1: error("fork failed\n"); default: /* * put ourselves into the file system */ close(p[0]); if(mount(p[1], -1, mntpt, MAFTER, "") < 0) error("mount failed\n"); _exits(0); } mfd[0] = mfd[1] = p[0];} voidndbinit(void){ db = ndbopen(dbfile); if(db == nil) error("can't open network database"); netdb = ndbopen(netndb); if(netdb != nil){ netdb->nohash = 1; db = ndbcat(netdb, db); }} Mfile*newfid(int fid){ Mlist *f, *ff; Mfile *mf; ff = 0; for(f = mlist; f; f = f->next) if(f->mf.busy && f->mf.fid == fid) return &f->mf; else if(!ff && !f->mf.busy) ff = f; if(ff == 0){ ff = emalloc(sizeof *f); ff->next = mlist; mlist = ff; } mf = &ff->mf; memset(mf, 0, sizeof *mf); mf->fid = fid; return mf;} Job*newjob(void){ Job *job; job = mallocz(sizeof(Job), 1); lock(&joblock); job->next = joblist; joblist = job; job->request.tag = -1; unlock(&joblock); return job;} voidfreejob(Job *job){ Job **l; lock(&joblock); for(l = &joblist; *l; l = &(*l)->next){ if((*l) == job){ *l = job->next; free(job); break; } } unlock(&joblock);} voidflushjob(int tag){ Job *job; lock(&joblock); for(job = joblist; job; job = job->next){ if(job->request.tag == tag && job->request.type != Tflush){ job->flushed = 1; break; } } unlock(&joblock);} voidio(void){ long n; Mfile *mf; int slaveflag; uchar mdata[IOHDRSZ + Maxfdata]; Job *job; /* * if we ask dns to fulfill requests, * a slave process is created to wait for replies. The * master process returns immediately via a longjmp * through 'masterjmp'. * * *isslave is a pointer into the call stack to a variable * that tells whether or not the current process is a slave. */ slaveflag = 0; /* init slave variable */ isslave = &slaveflag; setjmp(masterjmp); for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0) error("mount read"); job = newjob(); if(convM2S(mdata, n, &job->request) != n){ syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); freejob(job); continue; } lock(&dblock); mf = newfid(job->request.fid); if(debug) syslog(0, logfile, "%F", &job->request); switch(job->request.type){ default: syslog(1, logfile, "unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat:Lines 1–500 of 1914. Load more
/* * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #include <u.h> #include <libc.h> #include <auth.h> #include <fcall.h> #include <bio.h> #include <ctype.h> #include <ndb.h> #include <ip.h> #include <String.h> enum { Nreply= 20, Maxreply= 256, Maxrequest= 128, Maxpath= 128, Maxfdata= 8192, Maxhost= 64, /* maximum host name size */ Maxservice= 64, /* maximum service name size */ Qdir= 0, Qcs= 1, }; typedef struct Mfile Mfile; typedef struct Mlist Mlist; typedef struct Network Network; typedef struct Flushreq Flushreq; typedef struct Job Job; int vers; /* incremented each clone/attach */ struct Mfile { int busy; char *user; Qid qid; int fid; /* * current request */ char *net; char *host; char *serv; char *rem; /* * result of the last lookup */ Network *nextnet; int nreply; char *reply[Nreply]; int replylen[Nreply]; }; struct Mlist { Mlist *next; Mfile mf; }; /* * active requests */ struct Job { Job *next; int flushed; Fcall request; Fcall reply; }; Lock joblock; Job *joblist; Mlist *mlist; int mfd[2]; int debug; int paranoia; int ipv6lookups = 1; jmp_buf masterjmp; /* return through here after a slave process has been created */ int *isslave; /* *isslave non-zero means this is a slave process */ char *dbfile; Ndb *db, *netdb; void rversion(Job*); void rflush(Job*); void rattach(Job*, Mfile*); char* rwalk(Job*, Mfile*); void ropen(Job*, Mfile*); void rcreate(Job*, Mfile*); void rread(Job*, Mfile*); void rwrite(Job*, Mfile*); void rclunk(Job*, Mfile*); void rremove(Job*, Mfile*); void rstat(Job*, Mfile*); void rwstat(Job*, Mfile*); void rauth(Job*); void sendmsg(Job*, char*); void error(char*); void mountinit(char*, char*); void io(void); void ndbinit(void); void netinit(int); void netadd(char*); char *genquery(Mfile*, char*); char* ipinfoquery(Mfile*, char**, int); int needproto(Network*, Ndbtuple*); int lookup(Mfile*); Ndbtuple* reorder(Ndbtuple*, Ndbtuple*); void ipid(void); void readipinterfaces(void); void* emalloc(int); char* estrdup(char*); Job* newjob(void); void freejob(Job*); void setext(char*, int, char*); void cleanmf(Mfile*); extern void paralloc(void); Lock dblock; /* mutex on database operations */ Lock netlock; /* mutex for netinit() */ char *logfile = "cs"; char *paranoiafile = "cs.paranoia"; char mntpt[Maxpath]; char netndb[Maxpath]; /* * Network specific translators */ Ndbtuple* iplookup(Network*, char*, char*, int); char* iptrans(Ndbtuple*, Network*, char*, char*, int); Ndbtuple* telcolookup(Network*, char*, char*, int); char* telcotrans(Ndbtuple*, Network*, char*, char*, int); Ndbtuple* dnsiplookup(char*, Ndbs*); struct Network { char *net; Ndbtuple *(*lookup)(Network*, char*, char*, int); char *(*trans)(Ndbtuple*, Network*, char*, char*, int); int considered; /* flag: ignored for "net!"? */ int fasttimeouthack; /* flag. was for IL */ Network *next; }; enum { Ntcp = 0, }; /* * net doesn't apply to (r)udp, icmp(v6), or telco (for speed). */ Network network[] = { [Ntcp] { "tcp", iplookup, iptrans, 0 }, { "udp", iplookup, iptrans, 1 }, { "icmp", iplookup, iptrans, 1 }, { "icmpv6", iplookup, iptrans, 1 }, { "rudp", iplookup, iptrans, 1 }, { "ssh", iplookup, iptrans, 1 }, { "telco", telcolookup, telcotrans, 1 }, { 0 }, }; Lock ipifclock; Ipifc *ipifcs; char eaddr[16]; /* ascii ethernet address */ char ipaddr[64]; /* ascii internet address */ uchar ipa[IPaddrlen]; /* binary internet address */ char *mysysname; Network *netlist; /* networks ordered by preference */ Network *last; static void nstrcpy(char *to, char *from, int len) { strncpy(to, from, len); to[len-1] = 0; } void usage(void) { fprint(2, "usage: %s [-dn] [-f ndb-file] [-x netmtpt]\n", argv0); exits("usage"); } /* * based on libthread's threadsetname, but drags in less library code. * actually just sets the arguments displayed. */ void procsetname(char *fmt, ...) { int fd; char *cmdname; char buf[128]; va_list arg; va_start(arg, fmt); cmdname = vsmprint(fmt, arg); va_end(arg); if (cmdname == nil) return; snprint(buf, sizeof buf, "#p/%d/args", getpid()); if((fd = open(buf, OWRITE)) >= 0){ write(fd, cmdname, strlen(cmdname)+1); close(fd); } free(cmdname); } void main(int argc, char *argv[]) { int justsetname; char ext[Maxpath], servefile[Maxpath]; justsetname = 0; setnetmtpt(mntpt, sizeof(mntpt), nil); ext[0] = 0; ARGBEGIN{ case '4': ipv6lookups = 0; break; case 'd': debug = 1; break; case 'f': dbfile = EARGF(usage()); break; case 'n': justsetname = 1; break; case 'x': setnetmtpt(mntpt, sizeof(mntpt), EARGF(usage())); setext(ext, sizeof(ext), mntpt); break; }ARGEND USED(argc); USED(argv); rfork(RFREND|RFNOTEG); snprint(servefile, sizeof(servefile), "#s/cs%s", ext); snprint(netndb, sizeof(netndb), "%s/ndb", mntpt); unmount(servefile, mntpt); remove(servefile); fmtinstall('E', eipfmt); fmtinstall('I', eipfmt); fmtinstall('M', eipfmt); fmtinstall('F', fcallfmt); ndbinit(); netinit(0); if(!justsetname){ mountinit(servefile, mntpt); io(); } exits(0); } /* * if a mount point is specified, set the cs extention to be the mount point * with '_'s replacing '/'s */ void setext(char *ext, int n, char *p) { int i, c; n--; for(i = 0; i < n; i++){ c = p[i]; if(c == 0) break; if(c == '/') c = '_'; ext[i] = c; } ext[i] = 0; } void mountinit(char *service, char *mntpt) { int f; int p[2]; char buf[32]; if(pipe(p) < 0) error("pipe failed"); /* * make a /srv/cs */ f = create(service, OWRITE|ORCLOSE, 0666); if(f < 0) error(service); snprint(buf, sizeof(buf), "%d", p[1]); if(write(f, buf, strlen(buf)) != strlen(buf)) error("write /srv/cs"); switch(rfork(RFFDG|RFPROC|RFNAMEG)){ case 0: close(p[1]); procsetname("%s", mntpt); break; case -1: error("fork failed\n"); default: /* * put ourselves into the file system */ close(p[0]); if(mount(p[1], -1, mntpt, MAFTER, "") < 0) error("mount failed\n"); _exits(0); } mfd[0] = mfd[1] = p[0]; } void ndbinit(void) { db = ndbopen(dbfile); if(db == nil) error("can't open network database"); netdb = ndbopen(netndb); if(netdb != nil){ netdb->nohash = 1; db = ndbcat(netdb, db); } } Mfile* newfid(int fid) { Mlist *f, *ff; Mfile *mf; ff = 0; for(f = mlist; f; f = f->next) if(f->mf.busy && f->mf.fid == fid) return &f->mf; else if(!ff && !f->mf.busy) ff = f; if(ff == 0){ ff = emalloc(sizeof *f); ff->next = mlist; mlist = ff; } mf = &ff->mf; memset(mf, 0, sizeof *mf); mf->fid = fid; return mf; } Job* newjob(void) { Job *job; job = mallocz(sizeof(Job), 1); lock(&joblock); job->next = joblist; joblist = job; job->request.tag = -1; unlock(&joblock); return job; } void freejob(Job *job) { Job **l; lock(&joblock); for(l = &joblist; *l; l = &(*l)->next){ if((*l) == job){ *l = job->next; free(job); break; } } unlock(&joblock); } void flushjob(int tag) { Job *job; lock(&joblock); for(job = joblist; job; job = job->next){ if(job->request.tag == tag && job->request.type != Tflush){ job->flushed = 1; break; } } unlock(&joblock); } void io(void) { long n; Mfile *mf; int slaveflag; uchar mdata[IOHDRSZ + Maxfdata]; Job *job; /* * if we ask dns to fulfill requests, * a slave process is created to wait for replies. The * master process returns immediately via a longjmp * through 'masterjmp'. * * *isslave is a pointer into the call stack to a variable * that tells whether or not the current process is a slave. */ slaveflag = 0; /* init slave variable */ isslave = &slaveflag; setjmp(masterjmp); for(;;){ n = read9pmsg(mfd[0], mdata, sizeof mdata); if(n<=0) error("mount read"); job = newjob(); if(convM2S(mdata, n, &job->request) != n){ syslog(1, logfile, "format error %ux %ux %ux %ux %ux", mdata[0], mdata[1], mdata[2], mdata[3], mdata[4]); freejob(job); continue; } lock(&dblock); mf = newfid(job->request.fid); if(debug) syslog(0, logfile, "%F", &job->request); switch(job->request.type){ default: syslog(1, logfile, "unknown request type %d", job->request.type); break; case Tversion: rversion(job); break; case Tauth: rauth(job); break; case Tflush: rflush(job); break; case Tattach: rattach(job, mf); break; case Twalk: rwalk(job, mf); break; case Topen: ropen(job, mf); break; case Tcreate: rcreate(job, mf); break; case Tread: rread(job, mf); break; case Twrite: rwrite(job, mf); break; case Tclunk: rclunk(job, mf); break; case Tremove: rremove(job, mf); break; case Tstat: