]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/cwfs/srv.c
merge
[plan9front.git] / sys / src / cmd / cwfs / srv.c
1 #include "all.h"
2 #include "io.h"
3 #include <fcall.h>              /* 9p2000 */
4 #include <thread.h>
5
6 enum {
7         Maxfdata        = 8192,
8         Nqueue  = 200,          /* queue size (tunable) */
9         Nsrvo   = 8,                    /* number of write workers */
10 };
11
12 typedef struct Srv Srv;
13 struct Srv
14 {
15         Ref;
16         char            *name;
17         Chan    *chan;
18         int             fd;
19         char            buf[64];
20 };
21
22 static struct {
23         Lock;
24         Chan *hd;
25 } freechans;
26
27 static Queue *srvoq;
28
29 void
30 chanhangup(Chan *chan, char *msg, int dolock)
31 {
32         Srv *srv;
33
34         USED(dolock);
35         USED(msg);
36
37         fileinit(chan);
38         if(chan->type != Devsrv)
39                 return;
40         srv = chan->pdata;
41         if(srv == nil || srv->chan != chan)
42                 return;
43         close(srv->fd);
44         srv->fd = -1;
45 }
46
47 static void
48 srvput(Srv *srv)
49 {
50         Chan *chan;
51
52         if(decref(srv))
53                 return;
54
55         if(chatty)
56                 print("%s closed\n", srv->name);
57
58         chanhangup(srv->chan, "", 0);
59         memset(srv->buf, 0, sizeof(srv->buf));
60         chan = srv->chan;
61         lock(&freechans);
62         srv->chan = freechans.hd;
63         freechans.hd = chan;
64         unlock(&freechans);
65 }
66
67 static void
68 srvo(void *)
69 {
70         Srv *srv;
71         Msgbuf *mb;
72         char buf[ERRMAX];
73
74         for(;;){
75                 mb = fs_recv(srvoq, 0);
76                 if(mb == nil)
77                         continue;
78                 if(mb->data == nil){
79                         if(!(mb->flags & FREE))
80                                 mbfree(mb);
81                         continue;
82                 }
83                 srv = (Srv*)mb->param;
84                 while((srv->fd >= 0) && (write(srv->fd, mb->data, mb->count) != mb->count)){
85                         rerrstr(buf, sizeof(buf));
86                         if(strstr(buf, "interrupt"))
87                                 continue;
88
89                         if(buf[0] && chatty)
90                                 print("srvo %s: %s\n", srv->name, buf);
91                         chanhangup(srv->chan, buf, 0);
92                         break;
93                 }
94                 mbfree(mb);
95                 srvput(srv);
96         }
97 }
98
99 static void
100 srvi(void *aux)
101 {
102         Srv *srv = aux;
103         Msgbuf *mb, *ms;
104         uchar *b, *p, *e;
105         int n, m;
106         char buf[ERRMAX];
107
108         if((mb = mballoc(IOHDRSZ+Maxfdata, srv->chan, Mbeth1)) == nil)
109                 panic("srvi %s: mballoc failed", srv->name);
110         b = mb->data;
111         p = b;
112         e = b + mb->count;
113
114 Read:
115         while((srv->fd >= 0) && ((n = read(srv->fd, p, e - p)) >= 0)){
116                 p += n;
117                 while((p - b) >= BIT32SZ){
118                         m = GBIT32(b);
119                         if((m < BIT32SZ) || (m > mb->count)){
120                                 werrstr("bad length in 9P2000 message header");
121                                 goto Error;
122                         }
123                         if((n = (p - b) - m) < 0){
124                                 e = b + m;
125                                 goto Read;
126                         }
127                         if(m <= SMALLBUF){
128                                 if((ms = mballoc(m, srv->chan, Mbeth1)) == nil)
129                                         panic("srvi %s: mballoc failed", srv->name);
130                                 memmove(ms->data, b, m);
131                         } else {
132                                 ms = mb;
133                                 if((mb = mballoc(mb->count, srv->chan, Mbeth1)) == nil)
134                                         panic("srvi %s: mballoc failed", srv->name);
135                                 ms->count = m;
136                         }
137                         if(n > 0)
138                                 memmove(mb->data, b + m, n);
139                         b = mb->data;
140                         p = b + n;
141
142                         incref(srv);
143                         ms->param = (uint)srv;
144                         fs_send(serveq, ms);
145                 }
146                 e = b + mb->count;
147         }
148
149 Error:
150         rerrstr(buf, sizeof(buf));
151         if(strstr(buf, "interrupt"))
152                 goto Read;
153
154         if(buf[0] && chatty)
155                 print("srvi %s: %s\n", srv->name, buf);
156         chanhangup(srv->chan, buf, 0);
157         srvput(srv);
158
159         mbfree(mb);
160 }
161
162 Chan*
163 srvchan(int fd, char *name)
164 {
165         Chan *chan;
166         Srv *srv;
167
168         lock(&freechans);
169         if(chan = freechans.hd){
170                 srv = chan->pdata;
171                 freechans.hd = srv->chan;
172                 unlock(&freechans);
173         } else {
174                 unlock(&freechans);
175                 chan = fs_chaninit(Devsrv, 1, sizeof(*srv));
176                 srv = chan->pdata;
177         }
178         chan->reply = srvoq;
179         if(chan->send == nil)
180                 chan->send = serveq;
181         chan->protocol = nil;
182         chan->msize = 0;
183         chan->whotime = 0;
184
185         incref(srv);
186         srv->chan = chan;
187         srv->fd = fd;
188         snprint(srv->buf, sizeof(srv->buf), "srvi %s", name);
189         srv->name = strchr(srv->buf, ' ')+1;
190         newproc(srvi, srv, srv->buf);
191
192         return chan;
193 }
194
195 void
196 srvinit(void)
197 {
198         int i;
199
200         if(srvoq != nil)
201                 return;
202
203         srvoq = newqueue(Nqueue, "srvoq");
204         for(i=0; i<Nsrvo; i++)
205                 newproc(srvo, nil, "srvo");
206 }