/* ** @(#) isofs.c - (for RDP) ISO protocol ** @(#) $Id: isofs.c,v 1.1.1.1 2003/11/10 10:34:00 lucio Exp $ */ /* ** ================================================================== ** ** $Logfile:$ ** $RCSfile: isofs.c,v $ ** $Revision: 1.1.1.1 $ ** $Date: 2003/11/10 10:34:00 $ ** $Author: lucio $ ** ** ================================================================== ** ** $Log: isofs.c,v $ ** Revision 1.1.1.1 2003/11/10 10:34:00 lucio ** ASN.1 developments. ** ** ================================================================== */ #include #include #include #include #include #include <9p.h> #define NAMELEN (40) #define MSGLEN (80) typedef unsigned char uint8; enum ISO_PDU_CODE { ISO_PDU_CR = 0xE0, /* Connection Request */ ISO_PDU_CC = 0xD0, /* Connection Confirm */ ISO_PDU_DR = 0x80, /* Disconnect Request */ ISO_PDU_DT = 0xF0, /* Data */ ISO_PDU_ER = 0x70 /* Error */ }; static char *ident = "@(#) $Id: isofs.c,v 1.1.1.1 2003/11/10 10:34:00 lucio Exp $"; static void copyright (void) { print ("isofs: ISO network protocol for RDP\n"); print ("Copyright (C) 2003 Lucio De Re.\n"); } static char *use[] = { "usage: %s [-h|H] [-N] [-m mtpt] [-p srv]\n", "\n", "opts: -h|H: this message\n", " -N: show copyright notice\n", "\n", " -m mtpt: mountpoint (default /net/iso)\n", " -p srv: service name\n", nil }; static void usage (char *argv0, char *use) { fprint (2, use, argv0); exits ("usage"); } static void help (char *argv0, char **use) { print (*use++, argv0); while (*use) { print (*use++); } } static void isoopen (Req *r); static void isoread (Req *r); static void isowrite (Req *r); static void isoclose (Req *r); static void isoterm (Srv *s); static Tree *iso; static char *EAgain = "Not available, may be transient"; static Srv isosrv = { .open = isoopen, .read = isoread, .write = isowrite, .remove = isoclose, .end = isoterm, }; enum qtype { Qctl, Qdata, Qstats, Qroot, Qrclone, Qrctl, Qrstats, Qdir, }; typedef struct root root; struct root { int count; char *owner; File *root, *clone, *ctl, *stats; }; typedef struct select select; struct select { int type; // file type identifier select *dir; // pointer to directory union { struct { // stats, ctl int ndata; char *data; }; struct { // dir long inbytes; long outbytes; }; struct { // data int fd; // channel long len, lsz; char *lbuf; }; }; }; typedef struct pkthdr pkthdr; struct pkthdr { uint8 version; uint8 reserved; uint8 length[2]; uint8 hdrlen; uint8 code; }; #define HDRSZ (6) typedef struct cmdpkt cmdpkt; struct cmdpkt { uint8 dst[2]; uint8 src[2]; uint8 class; }; #define CMDSZ (5) typedef struct dtapkt dtapkt; struct dtapkt { uint8 eot; char data[1]; }; #define DATSZ (1) static long isocmd (int fd, uint8 op) { pkthdr hdr; cmdpkt cmd; long count; int len = HDRSZ + CMDSZ; char buf[HDRSZ + CMDSZ]; hdr.version = 3; hdr.reserved = 0; hdr.length[0] = (len >> 8) & 0xFF; hdr.length[1] = len & 0xFF; hdr.hdrlen = 6; hdr.code = op; memcpy (buf, &hdr, HDRSZ); cmd.dst[0] = cmd.dst[1] = 0; cmd.src[0] = cmd.src[1] = 0; cmd.class = 0; memcpy (buf + HDRSZ, &cmd, CMDSZ); count = write (fd, buf, len); print ("isofs: %d of %ld bytes copied (%r)\n", len, count); if (count == len) return count; else return -1; } static long isorsp (int fd, int exp) { char buf[HDRSZ]; pkthdr *hp = (pkthdr *) buf; long len; if ((len = read (fd, buf, HDRSZ)) != HDRSZ) { print ("wrong read length: %ld (%r)\n", len); return -1; } if (hp->version != 3) { print ("wrong protocol version: %d\n", hp->version); return -1; } len = (((hp->length[0] & 0xFF) << 8) | (hp->length[1] & 0xFF)) - HDRSZ; if (len <= 0) { print ("too little data: %ld", len); return -1; } if (hp->code != exp || hp->hdrlen != HDRSZ) { print ("wrong code or header length\n"); return -1; } return len; } static long isoout (int fd, char *data, long count) { pkthdr hdr; dtapkt pkt; long len = HDRSZ + DATSZ + count; char *buf = emalloc9p (len); hdr.version = 3; hdr.reserved = 0; hdr.length[0] = (len >> 8) & 0xFF; hdr.length[1] = len & 0xFF; hdr.hdrlen = 2; hdr.code = ISO_PDU_DT; memcpy (buf, &hdr, HDRSZ); pkt.eot = 0x80; memcpy (buf + HDRSZ, &pkt, DATSZ); memcpy (buf + HDRSZ + DATSZ, data, count); if (write (fd, buf, len) != len) count = -1; free (buf); return count; } /* r->fid points to the pertinent Fid structure */ static void isoopen (Req *r) { char ch[8], msg[MSGLEN]; root *rt = (root *)(isosrv.aux); File *d, *f; select *dd, *ff = (select *)(r->fid->file->aux); switch (ff->type) { case Qrclone: // root clone snprint (ch, 8, "%d", rt->count++); d = createfile (rt->root, ch, rt->owner, DMDIR|0775, nil); if (!d) { --rt->count; respond (r, "Can't create new channel"); return; } d->aux = emalloc9p (sizeof (select)); ff = (select *)(d->aux); ff->type = Qdir; ff->dir = nil; ff->inbytes = ff->outbytes = 0; f = createfile (d, "ctl", rt->owner, 0664, nil); f->aux = emalloc9p (sizeof (select)); ff = (select *)(f->aux); ff->type = Qctl; ff->dir = (select *)(d->aux); ff->data = estrdup9p (ch); ff->ndata = strlen (ff->data); r->fid->file = f; r->fid->file->length = ff->ndata; r->ofcall.qid = f->qid; f = createfile (d, "data", rt->owner, 0664, nil); f->aux = emalloc9p (sizeof (select)); ((select *)(f->aux))->type = Qdata; ((select *)(f->aux))->dir = (select *)(d->aux); f = createfile (d, "stats", rt->owner, 0444, nil); f->aux = emalloc9p (sizeof (select)); ff->dir = (select *)(d->aux); ff = (select *)(f->aux); ff->type = Qstats; ff->dir = (select *)(d->aux); break; case Qrctl: // root control case Qrstats: // root stats case Qctl: // channel control case Qdata: // channel data break; case Qstats: // channel stats dd = ff->dir; if (ff->data) free (ff->data); snprint (msg, MSGLEN, "Bytes in: %ld\tout: %ld\n", dd->inbytes, dd->outbytes); ff->data = estrdup9p (msg); r->fid->file->length = ff->ndata = strlen (ff->data); break; case Qroot: // root node case Qdir: // channel dir node break; default: snprint (msg, MSGLEN, "File of undefined type: %d", ff->type); respond (r, msg); return; } respond (r, nil); return; } static void isoread (Req *r) { vlong offset = r->ifcall.offset; long count = r->ifcall.count; char msg[MSGLEN]; select *ff = (select *)(r->fid->file->aux); select *df = ff->dir; int fd = df->fd; print ("isofs: read %ld %lld\n", count, offset); switch (ff->type) { case Qrclone: // root clone break; case Qrctl: // root control case Qrstats: // root stats break; case Qctl: // channel control case Qstats: // channel stats if (offset >= ff->ndata) { r->ofcall.count = 0; respond (r, nil); return; } if (offset + count >= ff->ndata) count = ff->ndata - offset; memmove (r->ofcall.data, ff->data + offset, count); r->ofcall.count = count; break; case Qdata: // channel data print ("FF(1): len = %ld - lsz = %ld\n", df->len, df->lsz); if (df->len == 0) { if ((df->len = isorsp (fd, ISO_PDU_DT)) <= 0) { print ("out of sync\n"); df->len = 0; respond (r, "read out of sync"); return; } while (df->len > df->lsz) { print ("buffer too small\n"); df->lsz *= 2; df->lbuf = erealloc9p (df->lbuf, df->lsz); } if (read (fd, df->lbuf, df->len) != df->len) { print ("wrong length on read\n"); respond (r, "read error"); return; } } print ("FF(2): len = %ld - lsz = %ld\n", df->len, df->lsz); if (df->len < count) count = df->len; memcpy (r->ofcall.data, df->lbuf, count); if ((df->len -= count) > 0) memmove (df->lbuf, df->lbuf + count, df->len); r->ofcall.count = count; ff->inbytes += count; break; default: snprint (msg, MSGLEN, "File of undefined type: %d", ff->type); respond (r, msg); return; } respond (r, nil); return; } static void isowrite (Req *r) { vlong offset = r->ifcall.offset; long count = r->ifcall.count; select *df, *ff = (select *)(r->fid->file->aux); int fd, n; char *argv[2]; char msg[MSGLEN]; print ("isofs: write %ld %lld\n", count, offset); switch (ff->type) { case Qctl: /* use /srv/svc close */ n = tokenize (r->ifcall.data, argv, 2); if (strncmp (argv[0], "use", 3) == 0) { print ("isofs: cmd = '%s', arg = '%s'\n", argv[0], argv[1]); if (n != 2 || (fd = open (argv[1], ORDWR)) < 0) { snprint (msg, MSGLEN, "Can't use service: %r"); respond (r, msg); return; } else { df = ff->dir; ff->fd = df->fd = fd; if (fd < 0 || isocmd (fd, ISO_PDU_CR) < 0) { respond (r, EAgain); return; } if (isorsp (fd, ISO_PDU_CC) < 0) { respond (r, "Connection not established"); return; } df->lbuf = emalloc9p (df->lsz = 256); read (fd, df->lbuf, df->lsz); df->len = 0; } } else if (strncmp (argv[0], "close", 5) == 0) { print ("isofs: cmd = '%s'\n", argv[0]); df = ff->dir; fd = df->fd; if (fd >= 0 && isocmd (fd, ISO_PDU_DR) < 0) { snprint (msg, MSGLEN, "Problem - %d", fd); respond (r, msg); return; } df->fd = -1; } else { respond (r, "Undefined control"); return; } r->ofcall.count = count; // r->ofcall.offset = offset + count; // print ("isofs: written %ld %lld\n", count, offset); break; case Qdata: df = ff->dir; fd = df->fd; if ((count = isoout (fd, r->ifcall.data, count)) < 0) { respond (r, EAgain); return; } r->ofcall.count = count; ff->outbytes += count; print ("isofs: written %ld %lld\n", count, offset); break; case Qrctl: break; case Qrclone: case Qroot: case Qstats: case Qrstats: case Qdir: respond (r, "not writable"); return; default: respond (r, "write not yet implemented"); return; } respond (r, nil); return; } static void isoclose (Req *r) { select *df, *ff = (select *)(r->fid->file->aux); int fd; switch (ff->type) { case Qdata: df = ff->dir; fd = df->fd; if (fd < 0) { respond (r, nil); return; } else if (isocmd (fd, ISO_PDU_DR) < 0) { df->fd = -1; respond (r, EAgain); return; } break; default: respond (r, "close not implemented"); return; } respond (r, nil); return; } static void isoterm (Srv *srv) { return; } static void isodest (File *f) { return; } void main(int argc, char **argv) { char *u, user[NAMELEN]; char *srvpt = nil; char *mtpt = "/net"; root *r; u = getuser (); if(u == nil) u = "none"; strncpy (user, u, NAMELEN - 1); user[NAMELEN - 1] = 0; ARGBEGIN { case 'm': mtpt = EARGF (usage (argv0, use[0])); break; case 'p': srvpt = EARGF (usage (argv0, use[0])); break; case 'v': chatty9p++; break; case 'h': case 'H': case '?': help (argv0, use); exits (0); default: usage (argv0, use[0]); } ARGEND; if (argc != 0) usage (argv0, use[0]); iso = alloctree (user, user, DMDIR|0775, isodest); iso->root->aux = emalloc9p (sizeof (select)); ((select *)(iso->root->aux))->type = Qroot; isosrv.tree = iso; isosrv.aux = emalloc9p (sizeof (root)); r = (root *)(isosrv.aux); r->owner = estrdup9p (user); r->count = 0; r->root = createfile (iso->root, "iso", user, DMDIR|0775, nil); r->root->aux = emalloc9p (sizeof (select)); ((select *)(r->root->aux))->type = Qdir; r->clone = createfile (r->root, "clone", user, 0666, nil); r->clone->aux = emalloc9p (sizeof (select)); ((select *)(r->clone->aux))->type = Qrclone; r->ctl = createfile (r->root, "ctl", user, 0666, nil); r->ctl->aux = emalloc9p (sizeof (select)); ((select *)(r->ctl->aux))->type = Qrctl; r->stats = createfile (r->root, "stats", user, 0444, nil); r->stats->aux = emalloc9p (sizeof (select)); ((select *)(r->stats->aux))->type = Qrstats; postmountsrv (&isosrv, srvpt, mtpt, MAFTER); exits (0); }