plan9fox/sys/src/cmd/srvold9p/fcall.c
2011-03-30 19:35:09 +03:00

151 lines
2.5 KiB
C

#include <u.h>
#include <libc.h>
#include <auth.h>
#include <fcall.h>
#include "9p1.h"
#define MAXFDATA (8*1024)
#define MAXRPC (MAXFDATA+160)
/*
* reassemble 9P messages for stream based protocols
* interposed between devmnt and the network by srv for tcp connections
* fcall expects devmnt on fd0, network fd1
*/
uchar msglen[256] =
{
[Tnop9p1] 3,
[Rnop9p1] 3,
[Tsession9p1] 3+CHALLEN,
[Rsession9p1] 3+NAMEREC+DOMLEN+CHALLEN,
[Terror9p1] 0,
[Rerror9p1] 67,
[Tflush9p1] 5,
[Rflush9p1] 3,
[Tattach9p1] 5+2*NAMEREC+TICKETLEN+AUTHENTLEN,
[Rattach9p1] 13+AUTHENTLEN,
[Tclone9p1] 7,
[Rclone9p1] 5,
[Twalk9p1] 33,
[Rwalk9p1] 13,
[Topen9p1] 6,
[Ropen9p1] 13,
[Tcreate9p1] 38,
[Rcreate9p1] 13,
[Tread9p1] 15,
[Rread9p1] 8,
[Twrite9p1] 16,
[Rwrite9p1] 7,
[Tclunk9p1] 5,
[Rclunk9p1] 5,
[Tremove9p1] 5,
[Rremove9p1] 5,
[Tstat9p1] 5,
[Rstat9p1] 121,
[Twstat9p1] 121,
[Rwstat9p1] 5,
[Tclwalk9p1] 35,
[Rclwalk9p1] 13,
};
enum
{
Twritehdr = 16, /* Min bytes for Twrite */
Rreadhdr = 8, /* Min bytes for Rread */
Twritecnt = 13, /* Offset in byte stream of write count */
Rreadcnt = 5, /* Offset for Readcnt */
};
int
mntrpclen(uchar *d, int n)
{
uchar t;
int len, off;
if(n < 1)
return 0;
t = d[0];
switch(t) { /* This is the type */
default:
len = msglen[t];
if(len == 0) /* Illegal type so consume */
return n;
if(n < len)
return 0;
return len;
case Twrite9p1: /* Fmt: TGGFFOOOOOOOOCC */
len = Twritehdr; /* T = type, G = tag, F = fid */
off = Twritecnt; /* O = offset, C = count */
break;
case Rread9p1: /* Fmt: TGGFFCC */
len = Rreadhdr;
off = Rreadcnt;
break;
}
if(n < off+2)
return 0;
len += d[off]|(d[off+1]<<8);
if(n < len)
return 0;
return len;
}
int
fcall(int fd)
{
int i, r, n, l;
uchar *p, *buf;
int pipefd[2];
if(pipe(pipefd) < 0)
fatal("fcall pipe: %r");
buf = malloc(MAXRPC);
if(buf == nil)
fatal("fcall malloc");
switch(rfork(RFPROC|RFMEM|RFFDG|RFCNAMEG)){
default:
return pipefd[0]; /* parent returns fd */
case 0:
break; /* child builds buffers */
case -1:
fatal("fcall fork: %r");
}
/* close file descriptors */
for(i=0; i<20; i++)
if(i!=fd && i!=pipefd[1])
close(i);
l = MAXRPC;
p = buf;
for(;;) {
n = read(fd, p, l);
if(n < 0)
break;
p += n;
l -= n;
for(;;) {
r = mntrpclen(buf, p - buf);
if(r == 0)
break;
if(write(pipefd[1], buf, r) < 0)
break;
n = (p - buf) - r;
memmove(buf, buf+r, n);
p = buf+n;
l = MAXRPC - n;
}
}
close(pipefd[1]);
fatal(nil);
return -1;
}