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