1 #include "all.h"
2
3 static int
readmsg(Chan * c,void * abuf,int n,int * ninep)4 readmsg(Chan *c, void *abuf, int n, int *ninep)
5 {
6 int fd, len;
7 uchar *buf;
8
9 buf = abuf;
10 fd = c->chan;
11 qlock(&c->rlock);
12 if(readn(fd, buf, 3) != 3){
13 qunlock(&c->rlock);
14 print("readn(3) fails: %r\n");
15 return -1;
16 }
17 if((50 <= buf[0] && buf[0] <= 87 && (buf[0]&1)==0 && GBIT16(buf+1) == 0xFFFF)
18 || buf[0] == 86 /* Tattach */){
19 *ninep = 1;
20 /* assume message boundaries */
21 n = read(fd, buf+3, n-3);
22 if(n < 0){
23 qunlock(&c->rlock);
24 return -1;
25 }
26 return n+3;
27 }
28
29 *ninep = 2;
30 if(read(fd, buf+3, 1) != 1){
31 qunlock(&c->rlock);
32 print("read(1) fails: %r\n");
33 return -1;
34 }
35 len = GBIT32(buf);
36 if(len > n){
37 print("msg too large\n");
38 qunlock(&c->rlock);
39 return -1;
40 }
41 if(readn(fd, buf+4, len-4) != len-4){
42 print("readn(%d) fails: %r\n", len-4);
43 qunlock(&c->rlock);
44 return -1;
45 }
46 qunlock(&c->rlock);
47 return len;
48 }
49
50 int
startserveproc(void (* f)(Chan *,uchar *,int),char * name,Chan * c,uchar * b,int nb)51 startserveproc(void (*f)(Chan*, uchar*, int), char *name, Chan *c, uchar *b, int nb)
52 {
53 int pid;
54
55 switch(pid = rfork(RFMEM|RFPROC)){
56 case -1:
57 panic("can't fork");
58 case 0:
59 break;
60 default:
61 return pid;
62 }
63 procname = name;
64 f(c, b, nb);
65 _exits(nil);
66 return -1; /* can't happen */
67 }
68
69 void
serve(Chan * chan)70 serve(Chan *chan)
71 {
72 int i, nin, p9, npid;
73 uchar inbuf[1024];
74 void (*s)(Chan*, uchar*, int);
75 int *pid;
76 Waitmsg *w;
77
78 p9 = 0;
79 if((nin = readmsg(chan, inbuf, sizeof inbuf, &p9)) < 0)
80 return;
81
82 switch(p9){
83 default:
84 print("unknown 9P type\n");
85 return;
86 case 1:
87 s = serve9p1;
88 break;
89 case 2:
90 s = serve9p2;
91 break;
92 }
93
94 pid = malloc(sizeof(pid)*(conf.nserve-1));
95 if(pid == nil)
96 return;
97 for(i=1; i<conf.nserve; i++)
98 pid[i-1] = startserveproc(s, "srv", chan, nil, 0);
99
100 (*s)(chan, inbuf, nin);
101
102 /* wait till all other servers for this chan are done */
103 for(npid = conf.nserve-1; npid > 0;){
104 w = wait();
105 if(w == 0)
106 break;
107 for(i = 0; i < conf.nserve-1; i++)
108 if(pid[i] == w->pid)
109 npid--;
110 free(w);
111 }
112 free(pid);
113 }
114
115