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 49 : void async_free(struct async **as)
10 : {
11 102 : if(!as || !*as) return;
12 50 : 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 0 : static int async_io(struct async *as, int doread)
32 : {
33 0 : int mfd=-1;
34 : fd_set fsr;
35 : fd_set fsw;
36 : fd_set fse;
37 0 : int dosomething=0;
38 : struct timeval tval;
39 0 : struct asfd *asfd;
40 : static int s=0;
41 :
42 0 : as->now=time(NULL);
43 0 : if(!as->last_time) as->last_time=as->now;
44 :
45 0 : if(as->doing_estimate) goto end;
46 :
47 0 : FD_ZERO(&fsr);
48 0 : FD_ZERO(&fsw);
49 0 : FD_ZERO(&fse);
50 :
51 0 : tval.tv_sec=as->setsec;
52 0 : tval.tv_usec=as->setusec;
53 :
54 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
55 : {
56 0 : if(asfd->fdtype==ASFD_FD_SERVER_PIPE_WRITE
57 0 : || asfd->fdtype==ASFD_FD_CHILD_PIPE_WRITE
58 0 : || asfd->fdtype==ASFD_FD_CLIENT_MONITOR_WRITE)
59 0 : asfd->doread=0;
60 : else
61 0 : asfd->doread=doread;
62 0 : asfd->dowrite=0;
63 :
64 0 : if(doread)
65 : {
66 0 : if(asfd->parse_readbuf(asfd))
67 0 : return asfd_problem(asfd);
68 0 : if(asfd->rbuf->buf || asfd->read_blocked_on_write)
69 0 : asfd->doread=0;
70 : }
71 :
72 0 : if(asfd->writebuflen && !asfd->write_blocked_on_read)
73 0 : asfd->dowrite++; // The write buffer is not yet empty.
74 :
75 0 : if(!asfd->doread && !asfd->dowrite) continue;
76 :
77 : add_fd_to_sets(asfd->fd, asfd->doread?&fsr:NULL,
78 0 : asfd->dowrite?&fsw:NULL, &fse, &mfd);
79 :
80 0 : dosomething++;
81 : }
82 0 : if(!dosomething) goto end;
83 : /*
84 : for(asfd=as->asfd; asfd; asfd=asfd->next)
85 : {
86 : printf("%s: %d %d %d %d\n", asfd->desc,
87 : asfd->doread, asfd->dowrite,
88 : asfd->readbuflen, asfd->writebuflen);
89 : }
90 : */
91 :
92 0 : errno=0;
93 0 : s=select(mfd+1, &fsr, &fsw, &fse, &tval);
94 0 : if(errno==EAGAIN || errno==EINTR) goto end;
95 :
96 0 : if(s<0)
97 : {
98 : logp("select error in %s: %s\n", __func__,
99 0 : strerror(errno));
100 0 : as->last_time=as->now;
101 0 : return -1;
102 : }
103 :
104 0 : for(asfd=as->asfd; asfd; asfd=asfd->next)
105 : {
106 0 : if(FD_ISSET(asfd->fd, &fse))
107 : {
108 0 : switch(asfd->fdtype)
109 : {
110 : case ASFD_FD_SERVER_LISTEN_MAIN:
111 : case ASFD_FD_SERVER_LISTEN_STATUS:
112 0 : as->last_time=as->now;
113 0 : return -1;
114 : default:
115 : logp("%s: had an exception\n",
116 0 : asfd->desc);
117 0 : return asfd_problem(asfd);
118 : }
119 : }
120 :
121 0 : if(asfd->doread && FD_ISSET(asfd->fd, &fsr)) // Able to read.
122 : {
123 0 : asfd->network_timeout=asfd->max_network_timeout;
124 0 : switch(asfd->fdtype)
125 : {
126 : case ASFD_FD_SERVER_LISTEN_MAIN:
127 : case ASFD_FD_SERVER_LISTEN_STATUS:
128 : // Indicate to the caller that we have
129 : // a new incoming client.
130 0 : asfd->new_client++;
131 0 : break;
132 : default:
133 0 : if(asfd->do_read(asfd)
134 0 : || asfd->parse_readbuf(asfd))
135 0 : return asfd_problem(asfd);
136 : break;
137 : }
138 : }
139 :
140 0 : if(asfd->dowrite && FD_ISSET(asfd->fd, &fsw)) // Able to write.
141 : {
142 0 : asfd->network_timeout=asfd->max_network_timeout;
143 0 : if(asfd->do_write(asfd))
144 0 : return asfd_problem(asfd);
145 : }
146 :
147 0 : if((!asfd->doread || !FD_ISSET(asfd->fd, &fsr))
148 0 : && (!asfd->dowrite || !FD_ISSET(asfd->fd, &fsw)))
149 : {
150 : // Be careful to avoid 'read quick' mode.
151 0 : if((as->setsec || as->setusec)
152 0 : && asfd->fdtype!=ASFD_FD_SERVER_LISTEN_MAIN
153 0 : && asfd->fdtype!=ASFD_FD_SERVER_LISTEN_STATUS
154 0 : && asfd->fdtype!=ASFD_FD_CHILD_PIPE_WRITE
155 0 : && as->now-as->last_time>0
156 0 : && as->now-as->last_time>0
157 0 : && asfd->max_network_timeout>0
158 0 : && asfd->network_timeout--<=0)
159 : {
160 : logp("%s: no activity for %d seconds.\n",
161 0 : asfd->desc, asfd->max_network_timeout);
162 0 : return asfd_problem(asfd);
163 : }
164 : }
165 : }
166 :
167 : end:
168 0 : as->last_time=as->now;
169 0 : return 0;
170 : }
171 :
172 0 : static int async_read_write(struct async *as)
173 : {
174 0 : return async_io(as, 1 /* Read too. */);
175 : }
176 :
177 0 : static int async_write(struct async *as)
178 : {
179 0 : return async_io(as, 0 /* No read. */);
180 : }
181 :
182 0 : static int async_read_quick(struct async *as)
183 : {
184 : int r;
185 0 : int savesec=as->setsec;
186 0 : int saveusec=as->setusec;
187 0 : as->setsec=0;
188 0 : as->setusec=0;
189 0 : r=as->read_write(as); // Maybe make an as->read(as) function some time.
190 0 : as->setsec=savesec;
191 0 : as->setusec=saveusec;
192 0 : return r;
193 : }
194 :
195 60 : static void async_asfd_add(struct async *as, struct asfd *asfd)
196 : {
197 : struct asfd *x;
198 60 : if(!as->asfd)
199 : {
200 42 : as->asfd=asfd;
201 102 : return;
202 : }
203 : // Add to the end;
204 18 : for(x=as->asfd; x->next; x=x->next) { }
205 18 : x->next=asfd;
206 : }
207 :
208 0 : static void async_asfd_remove(struct async *as, struct asfd *asfd)
209 : {
210 : struct asfd *l;
211 0 : if(!asfd) return;
212 0 : if(as->asfd==asfd)
213 : {
214 0 : as->asfd=as->asfd->next;
215 0 : return;
216 : }
217 0 : for(l=as->asfd; l; l=l->next)
218 : {
219 0 : if(l->next!=asfd) continue;
220 0 : l->next=asfd->next;
221 0 : return;
222 : }
223 : }
224 :
225 4 : void async_asfd_free_all(struct async **as)
226 : {
227 4 : struct asfd *a=NULL;
228 4 : struct asfd *asfd=NULL;
229 4 : if(!as || !*as) return;
230 8 : for(asfd=(*as)->asfd; asfd; asfd=a)
231 : {
232 4 : a=asfd->next;
233 4 : asfd_free(&asfd);
234 : }
235 : async_free(as);
236 : }
237 :
238 50 : static int async_init(struct async *as, int estimate)
239 : {
240 50 : as->setsec=1;
241 50 : as->setusec=0;
242 50 : as->last_time=0;
243 50 : as->doing_estimate=estimate;
244 :
245 50 : as->read_write=async_read_write;
246 50 : as->write=async_write;
247 50 : as->read_quick=async_read_quick;
248 :
249 50 : as->settimers=async_settimers;
250 50 : as->asfd_add=async_asfd_add;
251 50 : as->asfd_remove=async_asfd_remove;
252 :
253 50 : return 0;
254 : }
255 :
256 50 : struct async *async_alloc(void)
257 : {
258 : struct async *as;
259 50 : if(!(as=(struct async *)calloc_w(1, sizeof(struct async), __func__)))
260 : return NULL;
261 50 : as->init=async_init;
262 50 : return as;
263 : }
|