Line data Source code
1 : #include "burp.h"
2 : #include "alloc.h"
3 : #include "asfd.h"
4 : #include "async.h"
5 : #include "handy.h"
6 : #include "iobuf.h"
7 : #include "log.h"
8 :
9 137 : void async_free(struct async **as)
10 : {
11 287 : if(!as || !*as) return;
12 147 : free_v((void **)as);
13 : }
14 :
15 0 : static void async_settimers(struct async *as, int sec, int usec)
16 : {
17 0 : as->setsec=sec;
18 0 : as->setusec=usec;
19 0 : }
20 :
21 : // The normal server and client processes will just exit on error within
22 : // async_io, but the champ chooser server needs to manage client fds and
23 : // remove them from its list if one of them had a problem.
24 : static int asfd_problem(struct asfd *asfd)
25 : {
26 0 : asfd->want_to_remove++;
27 0 : asfd->as->last_time=asfd->as->now;
28 : return -1;
29 : }
30 :
31 : #ifdef HAVE_WIN32
32 : // Jesus H. Christ. How does anybody ever get anything done with windows?
33 : // The normal async stuff does not work for the client monitor, because the
34 : // windows select() only supports sockets, and windows stdin/stdout are not
35 : // sockets.
36 : // It seems to be impossible to do non-blocking i/o on windows stdin.
37 : // If you have a windows console, you can use PeekConsoleInput to look at
38 : // events in order to look ahead. This is not looking at stdin, which means
39 : // that this does not work for ssh via cygwin.
40 : static int windows_stupidity_hacks(struct asfd *asfd,
41 : fd_set *fsr, fd_set *fsw)
42 : {
43 : if(asfd->do_read && asfd->fd==fileno(stdin))
44 : {
45 : DWORD len=0;
46 : INPUT_RECORD irec;
47 : HANDLE han=GetStdHandle(STD_INPUT_HANDLE);
48 :
49 : switch(WaitForSingleObject(han, 0))
50 : {
51 : case WAIT_OBJECT_0:
52 : if(!PeekConsoleInput(han, &irec, 1, &len))
53 : break;
54 : if(irec.EventType==KEY_EVENT
55 : && irec.Event.KeyEvent.bKeyDown)
56 : {
57 : // This will block until the user hits
58 : // the return key.
59 : if(asfd->do_read(asfd)
60 : || asfd->parse_readbuf(asfd))
61 : return asfd_problem(asfd);
62 : }
63 : else
64 : {
65 : // Purge event we are not interested in.
66 : ReadConsoleInput(han, &irec, 1, &len);
67 : }
68 : break;
69 : default:
70 : break;
71 : }
72 : }
73 : if(asfd->do_write && asfd->fd==fileno(stdout))
74 : {
75 : // This is saying that we think that stdout is always OK to
76 : // write to. Maybe this will not work all the time.
77 : FD_SET((unsigned int)asfd->fd, fsw);
78 : }
79 : return 0;
80 : }
81 : #endif
82 :
83 0 : static int async_io(struct async *as, int doread)
84 : {
85 0 : int mfd=-1;
86 : fd_set fsr;
87 : fd_set fsw;
88 : fd_set fse;
89 0 : int dosomething=0;
90 : struct timeval tval;
91 0 : struct asfd *asfd;
92 : static int s=0;
93 :
94 0 : as->now=time(NULL);
95 0 : if(!as->last_time) as->last_time=as->now;
96 :
97 0 : if(as->doing_estimate) goto end;
98 :
99 0 : FD_ZERO(&fsr);
100 0 : FD_ZERO(&fsw);
101 0 : FD_ZERO(&fse);
102 :
103 0 : tval.tv_sec=as->setsec;
104 0 : tval.tv_usec=as->setusec;
105 :
106 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
107 : {
108 0 : if(asfd->attempt_reads)
109 0 : asfd->doread=doread;
110 : else
111 0 : asfd->doread=0;
112 :
113 0 : asfd->dowrite=0;
114 :
115 0 : if(doread)
116 : {
117 0 : if(asfd->parse_readbuf(asfd))
118 0 : return asfd_problem(asfd);
119 0 : if(asfd->rbuf->buf || asfd->read_blocked_on_write)
120 0 : asfd->doread=0;
121 : }
122 :
123 0 : if(asfd->writebuflen && !asfd->write_blocked_on_read)
124 0 : asfd->dowrite++; // The write buffer is not yet empty.
125 :
126 0 : if(!asfd->doread && !asfd->dowrite) continue;
127 :
128 : #ifdef HAVE_WIN32
129 : if(asfd->fd==fileno(stdin)
130 : || asfd->fd==fileno(stdout))
131 : {
132 : dosomething++;
133 : continue;
134 : }
135 : #endif
136 :
137 0 : add_fd_to_sets(asfd->fd, asfd->doread?&fsr:NULL,
138 0 : asfd->dowrite?&fsw:NULL, &fse, &mfd);
139 :
140 0 : dosomething++;
141 : }
142 0 : if(!dosomething) goto end;
143 : /*
144 : for(asfd=as->asfd; asfd; asfd=asfd->next)
145 : {
146 : printf("%s: %d %d %d %d\n", asfd->desc,
147 : asfd->doread, asfd->dowrite,
148 : asfd->readbuflen, asfd->writebuflen);
149 : }
150 : */
151 :
152 0 : if(mfd>0)
153 : {
154 0 : errno=0;
155 0 : s=select(mfd+1, &fsr, &fsw, &fse, &tval);
156 0 : if(errno==EAGAIN || errno==EINTR) goto end;
157 :
158 0 : if(s<0)
159 : {
160 0 : logp("select error in %s: %s\n", __func__,
161 : strerror(errno));
162 0 : as->last_time=as->now;
163 0 : return -1;
164 : }
165 : }
166 :
167 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
168 : {
169 : #ifdef HAVE_WIN32
170 : if(windows_stupidity_hacks(asfd, &fsr, &fsw))
171 : return -1;
172 : #endif
173 0 : if(FD_ISSET(asfd->fd, &fse))
174 : {
175 0 : switch(asfd->fdtype)
176 : {
177 : case ASFD_FD_SERVER_LISTEN_MAIN:
178 : case ASFD_FD_SERVER_LISTEN_STATUS:
179 0 : as->last_time=as->now;
180 0 : return -1;
181 : default:
182 : #ifdef _AIX
183 : /* On AIX, for some weird reason,
184 : * writing the stats file makes the
185 : * socket show up in fse, despite
186 : * everything being fine. We ignore
187 : * it.
188 : */
189 : if(strncmp(asfd->desc, "stats file",
190 : sizeof("stats file")))
191 : {
192 : logp("%s: had an exception\n",
193 : asfd->desc);
194 : return asfd_problem(asfd);
195 : }
196 : #else
197 0 : logp("%s: had an exception\n",
198 : asfd->desc);
199 0 : return asfd_problem(asfd);
200 : #endif /* _AIX */
201 : }
202 : }
203 :
204 0 : if(asfd->doread && FD_ISSET(asfd->fd, &fsr)) // Able to read.
205 : {
206 0 : asfd->network_timeout=asfd->max_network_timeout;
207 0 : switch(asfd->fdtype)
208 : {
209 : case ASFD_FD_SERVER_LISTEN_MAIN:
210 : case ASFD_FD_SERVER_LISTEN_STATUS:
211 : // Indicate to the caller that we have
212 : // a new incoming client.
213 0 : asfd->new_client++;
214 0 : break;
215 : default:
216 0 : if(asfd->do_read(asfd)
217 0 : || asfd->parse_readbuf(asfd))
218 0 : return asfd_problem(asfd);
219 : break;
220 : }
221 : }
222 :
223 0 : if(asfd->dowrite && FD_ISSET(asfd->fd, &fsw)) // Able to write.
224 : {
225 0 : asfd->network_timeout=asfd->max_network_timeout;
226 0 : if(asfd->do_write(asfd))
227 0 : return asfd_problem(asfd);
228 : }
229 :
230 0 : if((!asfd->doread || !FD_ISSET(asfd->fd, &fsr))
231 0 : && (!asfd->dowrite || !FD_ISSET(asfd->fd, &fsw)))
232 : {
233 : // Be careful to avoid 'read quick' mode.
234 0 : if((as->setsec || as->setusec)
235 0 : && asfd->max_network_timeout>0
236 0 : && as->now-as->last_time>0
237 0 : && asfd->network_timeout--<=0)
238 : {
239 0 : logp("%s: no activity for %d seconds.\n",
240 : asfd->desc, asfd->max_network_timeout);
241 0 : return asfd_problem(asfd);
242 : }
243 : }
244 : }
245 :
246 : end:
247 0 : as->last_time=as->now;
248 0 : return 0;
249 : }
250 :
251 0 : static int async_read_write(struct async *as)
252 : {
253 0 : return async_io(as, 1 /* Read too. */);
254 : }
255 :
256 0 : static int async_write(struct async *as)
257 : {
258 0 : return async_io(as, 0 /* No read. */);
259 : }
260 :
261 0 : static int async_read_quick(struct async *as)
262 : {
263 : int r;
264 0 : int savesec=as->setsec;
265 0 : int saveusec=as->setusec;
266 0 : as->setsec=0;
267 0 : as->setusec=0;
268 0 : r=as->read_write(as); // Maybe make an as->read(as) function some time.
269 0 : as->setsec=savesec;
270 0 : as->setusec=saveusec;
271 0 : return r;
272 : }
273 :
274 195 : static void async_asfd_add(struct async *as, struct asfd *asfd)
275 : {
276 : struct asfd *x;
277 195 : if(!as->asfd)
278 : {
279 138 : as->asfd=asfd;
280 333 : return;
281 : }
282 : // Add to the end;
283 88 : for(x=as->asfd; x->next; x=x->next) { }
284 57 : x->next=asfd;
285 : }
286 :
287 0 : static void async_asfd_remove(struct async *as, struct asfd *asfd)
288 : {
289 : struct asfd *l;
290 0 : if(!asfd) return;
291 0 : if(as->asfd==asfd)
292 : {
293 0 : as->asfd=as->asfd->next;
294 0 : return;
295 : }
296 0 : for(l=as->asfd; l; l=l->next)
297 : {
298 0 : if(l->next!=asfd) continue;
299 0 : l->next=asfd->next;
300 0 : return;
301 : }
302 : }
303 :
304 13 : void async_asfd_free_all(struct async **as)
305 : {
306 13 : struct asfd *a=NULL;
307 13 : struct asfd *asfd=NULL;
308 13 : if(!as || !*as) return;
309 26 : for(asfd=(*as)->asfd; asfd; asfd=a)
310 : {
311 13 : a=asfd->next;
312 13 : asfd_free(&asfd);
313 : }
314 : async_free(as);
315 : }
316 :
317 147 : static int async_init(struct async *as, int estimate)
318 : {
319 147 : as->setsec=1;
320 147 : as->setusec=0;
321 147 : as->last_time=0;
322 147 : as->doing_estimate=estimate;
323 :
324 147 : as->read_write=async_read_write;
325 147 : as->write=async_write;
326 147 : as->read_quick=async_read_quick;
327 :
328 147 : as->settimers=async_settimers;
329 147 : as->asfd_add=async_asfd_add;
330 147 : as->asfd_remove=async_asfd_remove;
331 :
332 147 : return 0;
333 : }
334 :
335 147 : struct async *async_alloc(void)
336 : {
337 : struct async *as;
338 147 : if(!(as=(struct async *)calloc_w(1, sizeof(struct async), __func__)))
339 : return NULL;
340 147 : as->init=async_init;
341 147 : return as;
342 : }
|