Plan 9 from Bell Labs’s /usr/web/sources/contrib/lucio/asn1/devel/isofs.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
**	@(#) 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 <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include <thread.h>
#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);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.