text: #include <u.h>
  #include <libc.h>
  #include <thread.h>
  #include <sunrpc.h>
  
  enum
  {
  	MaxRead = 17000
  };
  
  typedef struct SunMsgFd SunMsgFd;
  struct SunMsgFd
  {
  	SunMsg msg;
  	int fd;
  };
  
  typedef struct Arg Arg;
  struct Arg
  {
  	SunSrv *srv;
  	Channel *creply;
  	Channel *csync;
  	int fd;
  };
  
  static void
  sunfdread(void *v)
  {
  	uint n, tot;
  	int done;
  	uchar buf[4], *p;
  	Arg arg = *(Arg*)v;
  	SunMsgFd *msg;
  
  	sendp(arg.csync, 0);
  
  	p = nil;
  	tot = 0;
  	for(;;){
  		n = readn(arg.fd, buf, 4);
  		if(n != 4)
  			break;
  		n = (buf[0]<<24)|(buf[1]<<16)|(buf[2]<<8)|buf[3];
  if(arg.srv->chatty) fprint(2, "%.8ux...", n);
  		done = n&0x80000000;
  		n &= ~0x80000000;
  		p = erealloc(p, tot+n);
  		if(readn(arg.fd, p+tot, n) != n)
  			break;
  		tot += n;
  		if(done){
  			msg = emalloc(sizeof(SunMsgFd));
  			msg->msg.data = p;
  			msg->msg.count = tot;
  			msg->msg.creply = arg.creply;
  			sendp(arg.srv->crequest, msg);
  			p = nil;
  			tot = 0;
  		}
  	}
  }
  
  static void
  sunfdwrite(void *v)
  {
  	uchar buf[4];
  	u32int n;
  	Arg arg = *(Arg*)v;
  	SunMsgFd *msg;
  
  	sendp(arg.csync, 0);
  
  	while((msg = recvp(arg.creply)) != nil){
  		n = msg->msg.count;
  		buf[0] = (n>>24)|0x80;
  		buf[1] = n>>16;
  		buf[2] = n>>8;
  		buf[3] = n;
  		if(write(arg.fd, buf, 4) != 4
  		|| write(arg.fd, msg->msg.data, msg->msg.count) != msg->msg.count)
  			fprint(2, "sunfdwrite: %r\n");
  		free(msg->msg.data);
  		free(msg);
  	}
  }
  
  int
  sunsrvfd(SunSrv *srv, int fd)
  {
  	Arg *arg;
  
  	arg = emalloc(sizeof(Arg));
  	arg->fd = fd;
  	arg->srv = srv;
  	arg->csync = chancreate(sizeof(void*), 0);
  	arg->creply = chancreate(sizeof(SunMsg*), 10);
  
  	proccreate(sunfdread, arg, SunStackSize);
  	proccreate(sunfdwrite, arg, SunStackSize);
  	recvp(arg->csync);
  	recvp(arg->csync);
  
  	chanfree(arg->csync);
  	free(arg);
  	return 0;
  }
  