]> git.ipfire.org Git - thirdparty/squid.git/blame - src/helper.cc
date: 2003/01/07 20:46:12; author: wessels; state: Exp; lines: +2 -1
[thirdparty/squid.git] / src / helper.cc
CommitLineData
f740a279 1
2/*
10f829b4 3 * $Id: helper.cc,v 1.54 2002/10/23 09:15:00 adrian Exp $
f740a279 4 *
17bb3486 5 * DEBUG: section 84 Helper process maintenance
f740a279 6 * AUTHOR: Harvest Derived?
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
f740a279 9 * ----------------------------------------------------------
10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
f740a279 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
74addf6c 36#include "squid.h"
e6ccf245 37#include "Store.h"
42679bd6 38#include "comm.h"
74addf6c 39
40#define HELPER_MAX_ARGS 64
41
c4b7a5a9 42static IOCB helperHandleRead;
43static IOCB helperStatefulHandleRead;
1f5f60dd 44static PF helperServerFree;
94439e4e 45static PF helperStatefulServerFree;
74addf6c 46static void Enqueue(helper * hlp, helper_request *);
47static helper_request *Dequeue(helper * hlp);
94439e4e 48static helper_stateful_request *StatefulDequeue(statefulhelper * hlp);
74addf6c 49static helper_server *GetFirstAvailable(helper * hlp);
94439e4e 50static helper_stateful_server *StatefulGetFirstAvailable(statefulhelper * hlp);
74addf6c 51static void helperDispatch(helper_server * srv, helper_request * r);
94439e4e 52static void helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r);
74addf6c 53static void helperKickQueue(helper * hlp);
94439e4e 54static void helperStatefulKickQueue(statefulhelper * hlp);
74addf6c 55static void helperRequestFree(helper_request * r);
94439e4e 56static void helperStatefulRequestFree(helper_stateful_request * r);
57static void StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r);
58static helper_stateful_request *StatefulServerDequeue(helper_stateful_server * srv);
59static void StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r);
60static void helperStatefulServerKickQueue(helper_stateful_server * srv);
74addf6c 61
62void
63helperOpenServers(helper * hlp)
64{
65 char *s;
66 char *progname;
67 char *shortname;
68 char *procname;
a2c963ae 69 const char *args[HELPER_MAX_ARGS];
74addf6c 70 char fd_note_buf[FD_DESC_SZ];
71 helper_server *srv;
72 int nargs = 0;
73 int k;
74 int x;
75 int rfd;
76 int wfd;
77 wordlist *w;
78 if (hlp->cmdline == NULL)
79 return;
80 progname = hlp->cmdline->key;
74addf6c 81 if ((s = strrchr(progname, '/')))
82 shortname = xstrdup(s + 1);
83 else
84 shortname = xstrdup(progname);
17bb3486 85 debug(84, 1) ("helperOpenServers: Starting %d '%s' processes\n",
74addf6c 86 hlp->n_to_start, shortname);
e6ccf245 87 procname = (char *)xmalloc(strlen(shortname) + 3);
74addf6c 88 snprintf(procname, strlen(shortname) + 3, "(%s)", shortname);
89 args[nargs++] = procname;
90 for (w = hlp->cmdline->next; w && nargs < HELPER_MAX_ARGS; w = w->next)
91 args[nargs++] = w->key;
92 args[nargs++] = NULL;
93 assert(nargs <= HELPER_MAX_ARGS);
94 for (k = 0; k < hlp->n_to_start; k++) {
c68e9c6b 95 getCurrentTime();
74addf6c 96 rfd = wfd = -1;
97 x = ipcCreate(hlp->ipc_type,
98 progname,
99 args,
100 shortname,
101 &rfd,
102 &wfd);
103 if (x < 0) {
17bb3486 104 debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
74addf6c 105 continue;
106 }
107 hlp->n_running++;
72711e31 108 srv = cbdataAlloc(helper_server);
7d2bd2b5 109 srv->pid = x;
74addf6c 110 srv->flags.alive = 1;
111 srv->index = k;
112 srv->rfd = rfd;
113 srv->wfd = wfd;
e6ccf245 114 srv->buf = (char *)memAllocate(MEM_8K_BUF);
74addf6c 115 srv->buf_sz = 8192;
116 srv->offset = 0;
fa80a8ef 117 srv->parent = cbdataReference(hlp);
74addf6c 118 dlinkAddTail(srv, &srv->link, &hlp->servers);
119 if (rfd == wfd) {
120 snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
121 fd_note(rfd, fd_note_buf);
122 } else {
123 snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
124 fd_note(rfd, fd_note_buf);
125 snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
126 fd_note(wfd, fd_note_buf);
127 }
128 commSetNonBlocking(rfd);
129 if (wfd != rfd)
130 commSetNonBlocking(wfd);
1f5f60dd 131 comm_add_close_handler(rfd, helperServerFree, srv);
74addf6c 132 }
133 safe_free(shortname);
134 safe_free(procname);
838b993c 135 helperKickQueue(hlp);
74addf6c 136}
137
94439e4e 138void
139helperStatefulOpenServers(statefulhelper * hlp)
140{
141 char *s;
142 char *progname;
143 char *shortname;
144 char *procname;
a2c963ae 145 const char *args[HELPER_MAX_ARGS];
94439e4e 146 char fd_note_buf[FD_DESC_SZ];
147 helper_stateful_server *srv;
148 int nargs = 0;
149 int k;
150 int x;
151 int rfd;
152 int wfd;
153 wordlist *w;
154 if (hlp->cmdline == NULL)
155 return;
156 progname = hlp->cmdline->key;
157 if ((s = strrchr(progname, '/')))
158 shortname = xstrdup(s + 1);
159 else
160 shortname = xstrdup(progname);
17bb3486 161 debug(84, 1) ("helperStatefulOpenServers: Starting %d '%s' processes\n",
94439e4e 162 hlp->n_to_start, shortname);
e6ccf245 163 procname = (char *)xmalloc(strlen(shortname) + 3);
94439e4e 164 snprintf(procname, strlen(shortname) + 3, "(%s)", shortname);
165 args[nargs++] = procname;
166 for (w = hlp->cmdline->next; w && nargs < HELPER_MAX_ARGS; w = w->next)
167 args[nargs++] = w->key;
168 args[nargs++] = NULL;
169 assert(nargs <= HELPER_MAX_ARGS);
170 for (k = 0; k < hlp->n_to_start; k++) {
171 getCurrentTime();
172 rfd = wfd = -1;
173 x = ipcCreate(hlp->ipc_type,
174 progname,
175 args,
176 shortname,
177 &rfd,
178 &wfd);
179 if (x < 0) {
17bb3486 180 debug(84, 1) ("WARNING: Cannot run '%s' process.\n", progname);
94439e4e 181 continue;
182 }
183 hlp->n_running++;
72711e31 184 srv = cbdataAlloc(helper_stateful_server);
5d146f7d 185 srv->pid = x;
94439e4e 186 srv->flags.alive = 1;
187 srv->flags.reserved = S_HELPER_FREE;
188 srv->deferred_requests = 0;
60d096f4 189 srv->stats.deferbyfunc = 0;
190 srv->stats.deferbycb = 0;
191 srv->stats.submits = 0;
192 srv->stats.releases = 0;
94439e4e 193 srv->index = k;
194 srv->rfd = rfd;
195 srv->wfd = wfd;
e6ccf245 196 srv->buf = (char *)memAllocate(MEM_8K_BUF);
94439e4e 197 srv->buf_sz = 8192;
198 srv->offset = 0;
fa80a8ef 199 srv->parent = cbdataReference(hlp);
94439e4e 200 if (hlp->datapool != NULL)
201 srv->data = memPoolAlloc(hlp->datapool);
94439e4e 202 dlinkAddTail(srv, &srv->link, &hlp->servers);
203 if (rfd == wfd) {
204 snprintf(fd_note_buf, FD_DESC_SZ, "%s #%d", shortname, k + 1);
205 fd_note(rfd, fd_note_buf);
206 } else {
207 snprintf(fd_note_buf, FD_DESC_SZ, "reading %s #%d", shortname, k + 1);
208 fd_note(rfd, fd_note_buf);
209 snprintf(fd_note_buf, FD_DESC_SZ, "writing %s #%d", shortname, k + 1);
210 fd_note(wfd, fd_note_buf);
211 }
212 commSetNonBlocking(rfd);
213 if (wfd != rfd)
214 commSetNonBlocking(wfd);
215 comm_add_close_handler(rfd, helperStatefulServerFree, srv);
216 }
217 safe_free(shortname);
218 safe_free(procname);
219 helperStatefulKickQueue(hlp);
220}
221
222
74addf6c 223void
224helperSubmit(helper * hlp, const char *buf, HLPCB * callback, void *data)
225{
e6ccf245 226 helper_request *r = (helper_request *)memAllocate(MEM_HELPER_REQUEST);
74addf6c 227 helper_server *srv;
5b5f9257 228 if (hlp == NULL) {
17bb3486 229 debug(84, 3) ("helperSubmit: hlp == NULL\n");
5b5f9257 230 callback(data, NULL);
231 return;
232 }
74addf6c 233 r->callback = callback;
fa80a8ef 234 r->data = cbdataReference(data);
74addf6c 235 r->buf = xstrdup(buf);
74addf6c 236 if ((srv = GetFirstAvailable(hlp)))
237 helperDispatch(srv, r);
238 else
239 Enqueue(hlp, r);
17bb3486 240 debug(84, 9) ("helperSubmit: %s\n", buf);
94439e4e 241}
242
721b0310 243/* lastserver = "server last used as part of a deferred or reserved
244 * request sequence"
245 */
94439e4e 246void
247helperStatefulSubmit(statefulhelper * hlp, const char *buf, HLPSCB * callback, void *data, helper_stateful_server * lastserver)
248{
e6ccf245 249 helper_stateful_request *r = (helper_stateful_request *)memAllocate(MEM_HELPER_STATEFUL_REQUEST);
94439e4e 250 helper_stateful_server *srv;
251 if (hlp == NULL) {
17bb3486 252 debug(84, 3) ("helperStatefulSubmit: hlp == NULL\n");
94439e4e 253 callback(data, 0, NULL);
254 return;
255 }
256 r->callback = callback;
fa80a8ef 257 r->data = cbdataReference(data);
721b0310 258 if (buf != NULL) {
94439e4e 259 r->buf = xstrdup(buf);
721b0310 260 r->placeholder = 0;
261 } else {
262 r->buf = NULL;
94439e4e 263 r->placeholder = 1;
721b0310 264 }
94439e4e 265 if ((buf != NULL) && lastserver) {
17bb3486 266 debug(84, 5) ("StatefulSubmit with lastserver %p\n", lastserver);
60d096f4 267 /* the queue doesn't count for this assert because queued requests
268 * have already gone through here and been tested.
269 * It's legal to have deferred_requests == 0 and queue entries
270 * and status of S_HELPEER_DEFERRED.
271 * BUT: It's not legal to submit a new request w/lastserver in
272 * that state.
273 */
274 assert(!(lastserver->deferred_requests == 0 &&
275 lastserver->flags.reserved == S_HELPER_DEFERRED));
276 if (lastserver->flags.reserved != S_HELPER_RESERVED) {
277 lastserver->stats.submits++;
94439e4e 278 lastserver->deferred_requests--;
60d096f4 279 }
94439e4e 280 if (!(lastserver->request)) {
17bb3486 281 debug(84, 5) ("StatefulSubmit dispatching\n");
94439e4e 282 helperStatefulDispatch(lastserver, r);
283 } else {
17bb3486 284 debug(84, 5) ("StatefulSubmit queuing\n");
94439e4e 285 StatefulServerEnqueue(lastserver, r);
286 }
287 } else {
288 if ((srv = StatefulGetFirstAvailable(hlp))) {
289 helperStatefulDispatch(srv, r);
290 } else
291 StatefulEnqueue(hlp, r);
292 }
17bb3486 293 debug(84, 9) ("helperStatefulSubmit: placeholder: '%d', buf '%s'.\n", r->placeholder, buf);
94439e4e 294}
295
296helper_stateful_server *
297helperStatefulDefer(statefulhelper * hlp)
298/* find and add a deferred request to a server */
299{
300 dlink_node *n;
301 helper_stateful_server *srv = NULL, *rv = NULL;
302 if (hlp == NULL) {
17bb3486 303 debug(84, 3) ("helperStatefulReserve: hlp == NULL\n");
94439e4e 304 return NULL;
305 }
17bb3486 306 debug(84, 5) ("helperStatefulDefer: Running servers %d.\n", hlp->n_running);
94439e4e 307 if (hlp->n_running == 0) {
17bb3486 308 debug(84, 1) ("helperStatefulDefer: No running servers!. \n");
94439e4e 309 return NULL;
310 }
311 srv = StatefulGetFirstAvailable(hlp);
312 /* all currently busy:loop through servers and find server with the shortest queue */
313 rv = srv;
314 if (rv == NULL)
315 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 316 srv = (helper_stateful_server *)n->data;
94439e4e 317 if (srv->flags.reserved == S_HELPER_RESERVED)
318 continue;
319 if (!srv->flags.alive)
320 continue;
321 if ((hlp->IsAvailable != NULL) && (srv->data != NULL) &&
322 !(hlp->IsAvailable(srv->data)))
323 continue;
324 if ((rv != NULL) && (rv->deferred_requests < srv->deferred_requests))
325 continue;
326 rv = srv;
327 }
328 if (rv == NULL) {
17bb3486 329 debug(84, 1) ("helperStatefulDefer: None available.\n");
94439e4e 330 return NULL;
331 }
60d096f4 332 /* consistency check:
333 * when the deferred count is 0,
334 * submits + releases == deferbyfunc + deferbycb
335 * Or in english, when there are no deferred requests, the amount
336 * we have submitted to the queue or cancelled must equal the amount
337 * we have said we wanted to be able to submit or cancel
338 */
339 if (rv->deferred_requests == 0)
340 assert(rv->stats.submits + rv->stats.releases ==
341 rv->stats.deferbyfunc + rv->stats.deferbycb);
342
94439e4e 343 rv->flags.reserved = S_HELPER_DEFERRED;
344 rv->deferred_requests++;
60d096f4 345 rv->stats.deferbyfunc++;
94439e4e 346 return rv;
347}
348
349void
350helperStatefulReset(helper_stateful_server * srv)
351/* puts this helper back in the queue. the calling app is required to
352 * manage the state in the helper.
353 */
354{
355 statefulhelper *hlp = srv->parent;
356 helper_stateful_request *r;
357 r = srv->request;
358 if (r != NULL) {
359 /* reset attempt DURING an outstaning request */
17bb3486 360 debug(84, 1) ("helperStatefulReset: RESET During request %s \n",
94439e4e 361 hlp->id_name);
362 srv->flags.busy = 0;
363 srv->offset = 0;
364 helperStatefulRequestFree(r);
365 srv->request = NULL;
366 }
94439e4e 367 srv->flags.busy = 0;
368 if (srv->queue.head) {
369 srv->flags.reserved = S_HELPER_DEFERRED;
370 helperStatefulServerKickQueue(srv);
371 } else {
372 srv->flags.reserved = S_HELPER_FREE;
373 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
374 srv->parent->OnEmptyQueue(srv->data);
375 helperStatefulKickQueue(hlp);
376 }
377}
378
379void
380helperStatefulReleaseServer(helper_stateful_server * srv)
381/*decrease the number of 'waiting' clients that set the helper to be DEFERRED */
382{
60d096f4 383 srv->stats.releases++;
384 if (srv->flags.reserved == S_HELPER_DEFERRED) {
385 assert(srv->deferred_requests);
94439e4e 386 srv->deferred_requests--;
60d096f4 387 }
94439e4e 388 if (!(srv->deferred_requests) && (srv->flags.reserved == S_HELPER_DEFERRED) && !(srv->queue.head)) {
389 srv->flags.reserved = S_HELPER_FREE;
390 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
391 srv->parent->OnEmptyQueue(srv->data);
392 }
393}
394
395void *
396helperStatefulServerGetData(helper_stateful_server * srv)
397/* return a pointer to the stateful routines data area */
398{
399 return srv->data;
74addf6c 400}
401
402void
403helperStats(StoreEntry * sentry, helper * hlp)
404{
405 helper_server *srv;
406 dlink_node *link;
f4ae18d0 407 double tt;
74addf6c 408 storeAppendPrintf(sentry, "number running: %d of %d\n",
409 hlp->n_running, hlp->n_to_start);
410 storeAppendPrintf(sentry, "requests sent: %d\n",
411 hlp->stats.requests);
412 storeAppendPrintf(sentry, "replies received: %d\n",
413 hlp->stats.replies);
414 storeAppendPrintf(sentry, "queue length: %d\n",
415 hlp->stats.queue_size);
a15d85ea 416 storeAppendPrintf(sentry, "avg service time: %.2f msec\n",
417 (double) hlp->stats.avg_svc_time / 1000.0);
74addf6c 418 storeAppendPrintf(sentry, "\n");
09c1ece1 419 storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\n",
74addf6c 420 "#",
421 "FD",
f0b7ed32 422 "PID",
74addf6c 423 "# Requests",
424 "Flags",
425 "Time",
592da4ec 426 "Offset",
427 "Request");
74addf6c 428 for (link = hlp->servers.head; link; link = link->next) {
e6ccf245 429 srv = (helper_server*)link->data;
a15d85ea 430 tt = 0.001 * tvSubMsec(srv->dispatch_time,
431 srv->flags.busy ? current_time : srv->answer_time);
09c1ece1 432 storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%c%c%c%c\t%7.3f\t%7d\t%s\n",
74addf6c 433 srv->index + 1,
434 srv->rfd,
a1be6c8c 435 srv->pid,
74addf6c 436 srv->stats.uses,
437 srv->flags.alive ? 'A' : ' ',
438 srv->flags.busy ? 'B' : ' ',
439 srv->flags.closing ? 'C' : ' ',
440 srv->flags.shutdown ? 'S' : ' ',
f4ae18d0 441 tt < 0.0 ? 0.0 : tt,
592da4ec 442 (int) srv->offset,
443 srv->request ? log_quote(srv->request->buf) : "(none)");
74addf6c 444 }
445 storeAppendPrintf(sentry, "\nFlags key:\n\n");
446 storeAppendPrintf(sentry, " A = ALIVE\n");
447 storeAppendPrintf(sentry, " B = BUSY\n");
448 storeAppendPrintf(sentry, " C = CLOSING\n");
449 storeAppendPrintf(sentry, " S = SHUTDOWN\n");
450}
451
94439e4e 452void
453helperStatefulStats(StoreEntry * sentry, statefulhelper * hlp)
454{
455 helper_stateful_server *srv;
456 dlink_node *link;
457 double tt;
458 storeAppendPrintf(sentry, "number running: %d of %d\n",
459 hlp->n_running, hlp->n_to_start);
460 storeAppendPrintf(sentry, "requests sent: %d\n",
461 hlp->stats.requests);
462 storeAppendPrintf(sentry, "replies received: %d\n",
463 hlp->stats.replies);
464 storeAppendPrintf(sentry, "queue length: %d\n",
465 hlp->stats.queue_size);
466 storeAppendPrintf(sentry, "avg service time: %d msec\n",
467 hlp->stats.avg_svc_time);
468 storeAppendPrintf(sentry, "\n");
38650cc8 469 storeAppendPrintf(sentry, "%7s\t%7s\t%7s\t%11s\t%s\t%7s\t%7s\t%7s\t%7s\n",
94439e4e 470 "#",
471 "FD",
5d146f7d 472 "PID",
94439e4e 473 "# Requests",
474 "# Deferred Requests",
475 "Flags",
476 "Time",
477 "Offset",
478 "Request");
479 for (link = hlp->servers.head; link; link = link->next) {
e6ccf245 480 srv = (helper_stateful_server *)link->data;
94439e4e 481 tt = 0.001 * tvSubMsec(srv->dispatch_time, current_time);
5d146f7d 482 storeAppendPrintf(sentry, "%7d\t%7d\t%7d\t%11d\t%11d\t%c%c%c%c%c%c\t%7.3f\t%7d\t%s\n",
94439e4e 483 srv->index + 1,
484 srv->rfd,
5d146f7d 485 srv->pid,
94439e4e 486 srv->stats.uses,
32754419 487 (int) srv->deferred_requests,
94439e4e 488 srv->flags.alive ? 'A' : ' ',
489 srv->flags.busy ? 'B' : ' ',
490 srv->flags.closing ? 'C' : ' ',
491 srv->flags.reserved != S_HELPER_FREE ? 'R' : ' ',
492 srv->flags.shutdown ? 'S' : ' ',
5d146f7d 493 srv->request ? (srv->request->placeholder ? 'P' : ' ') : ' ',
94439e4e 494 tt < 0.0 ? 0.0 : tt,
495 (int) srv->offset,
496 srv->request ? log_quote(srv->request->buf) : "(none)");
497 }
498 storeAppendPrintf(sentry, "\nFlags key:\n\n");
499 storeAppendPrintf(sentry, " A = ALIVE\n");
500 storeAppendPrintf(sentry, " B = BUSY\n");
501 storeAppendPrintf(sentry, " C = CLOSING\n");
502 storeAppendPrintf(sentry, " R = RESERVED or DEFERRED\n");
503 storeAppendPrintf(sentry, " S = SHUTDOWN\n");
5d146f7d 504 storeAppendPrintf(sentry, " P = PLACEHOLDER\n");
94439e4e 505}
506
74addf6c 507void
508helperShutdown(helper * hlp)
509{
c68e9c6b 510 dlink_node *link = hlp->servers.head;
c68e9c6b 511 while (link) {
70160b49 512 helper_server *srv;
e6ccf245 513 srv = (helper_server *)link->data;
c68e9c6b 514 link = link->next;
74addf6c 515 if (!srv->flags.alive) {
c273ac49 516 debug(84, 3) ("helperShutdown: %s #%d is NOT ALIVE.\n",
74addf6c 517 hlp->id_name, srv->index + 1);
518 continue;
519 }
1f5f60dd 520 srv->flags.shutdown = 1; /* request it to shut itself down */
74addf6c 521 if (srv->flags.busy) {
c273ac49 522 debug(84, 3) ("helperShutdown: %s #%d is BUSY.\n",
74addf6c 523 hlp->id_name, srv->index + 1);
74addf6c 524 continue;
525 }
526 if (srv->flags.closing) {
c273ac49 527 debug(84, 3) ("helperShutdown: %s #%d is CLOSING.\n",
74addf6c 528 hlp->id_name, srv->index + 1);
529 continue;
530 }
74addf6c 531 srv->flags.closing = 1;
357099e5 532 /* the rest of the details is dealt with in the helperServerFree
533 * close handler
534 */
535 comm_close(srv->rfd);
74addf6c 536 }
537}
538
94439e4e 539void
540helperStatefulShutdown(statefulhelper * hlp)
541{
542 dlink_node *link = hlp->servers.head;
543 helper_stateful_server *srv;
544 while (link) {
e6ccf245 545 srv = (helper_stateful_server *)link->data;
94439e4e 546 link = link->next;
547 if (!srv->flags.alive) {
c273ac49 548 debug(84, 3) ("helperStatefulShutdown: %s #%d is NOT ALIVE.\n",
94439e4e 549 hlp->id_name, srv->index + 1);
550 continue;
551 }
552 srv->flags.shutdown = 1; /* request it to shut itself down */
553 if (srv->flags.busy) {
c273ac49 554 debug(84, 3) ("helperStatefulShutdown: %s #%d is BUSY.\n",
94439e4e 555 hlp->id_name, srv->index + 1);
556 continue;
557 }
558 if (srv->flags.closing) {
c273ac49 559 debug(84, 3) ("helperStatefulShutdown: %s #%d is CLOSING.\n",
94439e4e 560 hlp->id_name, srv->index + 1);
561 continue;
562 }
563 if (srv->flags.reserved != S_HELPER_FREE) {
c273ac49 564 debug(84, 3) ("helperStatefulShutdown: %s #%d is RESERVED.\n",
94439e4e 565 hlp->id_name, srv->index + 1);
566 continue;
567 }
568 if (srv->deferred_requests) {
c273ac49 569 debug(84, 3) ("helperStatefulShutdown: %s #%d has DEFERRED requests.\n",
94439e4e 570 hlp->id_name, srv->index + 1);
571 continue;
572 }
573 srv->flags.closing = 1;
357099e5 574 /* the rest of the details is dealt with in the helperStatefulServerFree
575 * close handler
576 */
577 comm_close(srv->rfd);
94439e4e 578 }
579}
580
581
1f5f60dd 582helper *
583helperCreate(const char *name)
584{
28c60158 585 helper *hlp;
72711e31 586 hlp = cbdataAlloc(helper);
1f5f60dd 587 hlp->id_name = name;
588 return hlp;
589}
590
94439e4e 591statefulhelper *
592helperStatefulCreate(const char *name)
593{
594 statefulhelper *hlp;
72711e31 595 hlp = cbdataAlloc(statefulhelper);
94439e4e 596 hlp->id_name = name;
597 return hlp;
598}
599
600
1f5f60dd 601void
602helperFree(helper * hlp)
603{
5dae8514 604 if (!hlp)
605 return;
1f5f60dd 606 /* note, don't free hlp->name, it probably points to static memory */
fe73896c 607 if (hlp->queue.head)
17bb3486 608 debug(84, 0) ("WARNING: freeing %s helper with %d requests queued\n",
fe73896c 609 hlp->id_name, hlp->stats.queue_size);
1f5f60dd 610 cbdataFree(hlp);
611}
612
94439e4e 613void
614helperStatefulFree(statefulhelper * hlp)
615{
5dae8514 616 if (!hlp)
617 return;
94439e4e 618 /* note, don't free hlp->name, it probably points to static memory */
619 if (hlp->queue.head)
17bb3486 620 debug(84, 0) ("WARNING: freeing %s helper with %d requests queued\n",
94439e4e 621 hlp->id_name, hlp->stats.queue_size);
622 cbdataFree(hlp);
623}
624
625
74addf6c 626/* ====================================================================== */
627/* LOCAL FUNCTIONS */
628/* ====================================================================== */
629
630static void
1f5f60dd 631helperServerFree(int fd, void *data)
74addf6c 632{
e6ccf245 633 helper_server *srv = (helper_server *)data;
74addf6c 634 helper *hlp = srv->parent;
ac750329 635 helper_request *r;
74addf6c 636 assert(srv->rfd == fd);
637 if (srv->buf) {
db1cd23c 638 memFree(srv->buf, MEM_8K_BUF);
74addf6c 639 srv->buf = NULL;
640 }
ac750329 641 if ((r = srv->request)) {
fa80a8ef 642 void *cbdata;
643 if (cbdataReferenceValidDone(r->data, &cbdata))
644 r->callback(cbdata, srv->buf);
ac750329 645 helperRequestFree(r);
63758217 646 srv->request = NULL;
ac750329 647 }
3cdb7cd0 648 if (srv->wfd != srv->rfd && srv->wfd != -1)
74addf6c 649 comm_close(srv->wfd);
650 dlinkDelete(&srv->link, &hlp->servers);
74addf6c 651 hlp->n_running--;
652 assert(hlp->n_running >= 0);
1f5f60dd 653 if (!srv->flags.shutdown) {
c273ac49 654 debug(84, 0) ("WARNING: %s #%d (FD %d) exited\n",
14e87a44 655 hlp->id_name, srv->index + 1, fd);
1f5f60dd 656 if (hlp->n_running < hlp->n_to_start / 2)
14e87a44 657 fatalf("Too few %s processes are running", hlp->id_name);
658 }
fa80a8ef 659 cbdataReferenceDone(srv->parent);
14e87a44 660 cbdataFree(srv);
74addf6c 661}
662
94439e4e 663static void
664helperStatefulServerFree(int fd, void *data)
665{
e6ccf245 666 helper_stateful_server *srv = (helper_stateful_server *)data;
94439e4e 667 statefulhelper *hlp = srv->parent;
668 helper_stateful_request *r;
669 assert(srv->rfd == fd);
670 if (srv->buf) {
671 memFree(srv->buf, MEM_8K_BUF);
672 srv->buf = NULL;
673 }
674 if ((r = srv->request)) {
fa80a8ef 675 void *cbdata;
676 if (cbdataReferenceValidDone(r->data, &cbdata))
677 r->callback(cbdata, srv, srv->buf);
94439e4e 678 helperStatefulRequestFree(r);
679 srv->request = NULL;
680 }
3c641669 681 /* TODO: walk the local queue of requests and carry them all out */
94439e4e 682 if (srv->wfd != srv->rfd && srv->wfd != -1)
683 comm_close(srv->wfd);
684 dlinkDelete(&srv->link, &hlp->servers);
685 hlp->n_running--;
686 assert(hlp->n_running >= 0);
687 if (!srv->flags.shutdown) {
c273ac49 688 debug(84, 0) ("WARNING: %s #%d (FD %d) exited\n",
94439e4e 689 hlp->id_name, srv->index + 1, fd);
690 if (hlp->n_running < hlp->n_to_start / 2)
691 fatalf("Too few %s processes are running", hlp->id_name);
692 }
693 if (srv->data != NULL)
694 memPoolFree(hlp->datapool, srv->data);
fa80a8ef 695 cbdataReferenceDone(srv->parent);
94439e4e 696 cbdataFree(srv);
697}
698
699
74addf6c 700static void
c4b7a5a9 701helperHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
74addf6c 702{
74addf6c 703 char *t = NULL;
e6ccf245 704 helper_server *srv = (helper_server *)data;
74addf6c 705 helper_request *r;
706 helper *hlp = srv->parent;
707 assert(fd == srv->rfd);
fa80a8ef 708 assert(cbdataReferenceValid(data));
c4b7a5a9 709
710 /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
711 if (flag == COMM_ERR_CLOSING) {
712 return;
713 }
714
17bb3486 715 debug(84, 5) ("helperHandleRead: %d bytes from %s #%d.\n",
c4b7a5a9 716 (int)len, hlp->id_name, srv->index + 1);
717 if (flag != COMM_OK || len <= 0) {
74addf6c 718 if (len < 0)
c273ac49 719 debug(84, 1) ("helperHandleRead: FD %d read: %s\n", fd, xstrerror());
74addf6c 720 comm_close(fd);
721 return;
722 }
723 srv->offset += len;
724 srv->buf[srv->offset] = '\0';
10f829b4 725 debug(84, 9) ("helperHandleRead: '%s'\n", srv->buf);
74addf6c 726 r = srv->request;
727 if (r == NULL) {
728 /* someone spoke without being spoken to */
17bb3486 729 debug(84, 1) ("helperHandleRead: unexpected read from %s #%d, %d bytes\n",
c4b7a5a9 730 hlp->id_name, srv->index + 1, (int)len);
74addf6c 731 srv->offset = 0;
732 } else if ((t = strchr(srv->buf, '\n'))) {
733 /* end of reply found */
fa80a8ef 734 HLPCB *callback;
735 void *cbdata;
17bb3486 736 debug(84, 3) ("helperHandleRead: end of reply found\n");
74addf6c 737 *t = '\0';
fa80a8ef 738 callback = r->callback;
739 r->callback = NULL;
740 if (cbdataReferenceValidDone(r->data, &cbdata))
741 callback(cbdata, srv->buf);
74addf6c 742 srv->flags.busy = 0;
743 srv->offset = 0;
744 helperRequestFree(r);
63758217 745 srv->request = NULL;
74addf6c 746 hlp->stats.replies++;
a15d85ea 747 srv->answer_time = current_time;
74addf6c 748 hlp->stats.avg_svc_time =
749 intAverage(hlp->stats.avg_svc_time,
a15d85ea 750 tvSubUsec(srv->dispatch_time, current_time),
74addf6c 751 hlp->stats.replies, REDIRECT_AV_FACTOR);
3cdb7cd0 752 if (srv->flags.shutdown) {
70160b49 753 int wfd = srv->wfd;
3cdb7cd0 754 srv->wfd = -1;
70160b49 755 comm_close(wfd);
3cdb7cd0 756 } else
c68e9c6b 757 helperKickQueue(hlp);
74addf6c 758 } else {
c4b7a5a9 759 comm_read(fd, srv->buf + srv->offset, srv->buf_sz - srv->offset, helperHandleRead, data);
74addf6c 760 }
74addf6c 761}
762
94439e4e 763static void
c4b7a5a9 764helperStatefulHandleRead(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
94439e4e 765{
94439e4e 766 char *t = NULL;
e6ccf245 767 helper_stateful_server *srv = (helper_stateful_server *)data;
94439e4e 768 helper_stateful_request *r;
769 statefulhelper *hlp = srv->parent;
770 assert(fd == srv->rfd);
fa80a8ef 771 assert(cbdataReferenceValid(data));
c4b7a5a9 772
773 /* Bail out early on COMM_ERR_CLOSING - close handlers will tidy up for us */
774 if (flag == COMM_ERR_CLOSING) {
775 return;
776 }
777
17bb3486 778 debug(84, 5) ("helperStatefulHandleRead: %d bytes from %s #%d.\n",
c4b7a5a9 779 (int)len, hlp->id_name, srv->index + 1);
780 if (flag != COMM_OK || len <= 0) {
94439e4e 781 if (len < 0)
c273ac49 782 debug(84, 1) ("helperStatefulHandleRead: FD %d read: %s\n", fd, xstrerror());
94439e4e 783 comm_close(fd);
784 return;
785 }
786 srv->offset += len;
787 srv->buf[srv->offset] = '\0';
788 r = srv->request;
789 if (r == NULL) {
790 /* someone spoke without being spoken to */
17bb3486 791 debug(84, 1) ("helperStatefulHandleRead: unexpected read from %s #%d, %d bytes\n",
c4b7a5a9 792 hlp->id_name, srv->index + 1, (int)len);
94439e4e 793 srv->offset = 0;
794 } else if ((t = strchr(srv->buf, '\n'))) {
795 /* end of reply found */
17bb3486 796 debug(84, 3) ("helperStatefulHandleRead: end of reply found\n");
94439e4e 797 *t = '\0';
fa80a8ef 798 if (cbdataReferenceValid(r->data)) {
94439e4e 799 switch ((r->callback(r->data, srv, srv->buf))) { /*if non-zero reserve helper */
800 case S_HELPER_UNKNOWN:
801 fatal("helperStatefulHandleRead: either a non-state aware callback was give to the stateful helper routines, or an uninitialised callback response was recieved.\n");
802 break;
803 case S_HELPER_RELEASE: /* helper finished with */
60d096f4 804 if (!srv->deferred_requests && !srv->queue.head) {
94439e4e 805 srv->flags.reserved = S_HELPER_FREE;
806 if ((srv->parent->OnEmptyQueue != NULL) && (srv->data))
807 srv->parent->OnEmptyQueue(srv->data);
17bb3486 808 debug(84, 5) ("StatefulHandleRead: releasing %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 809 } else {
810 srv->flags.reserved = S_HELPER_DEFERRED;
17bb3486 811 debug(84, 5) ("StatefulHandleRead: outstanding deferred requests on %s #%d. reserving for deferred requests.\n", hlp->id_name, srv->index + 1);
94439e4e 812 }
813 break;
814 case S_HELPER_RESERVE: /* 'pin' this helper for the caller */
815 if (!srv->queue.head) {
60d096f4 816 assert(srv->deferred_requests == 0);
94439e4e 817 srv->flags.reserved = S_HELPER_RESERVED;
17bb3486 818 debug(84, 5) ("StatefulHandleRead: reserving %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 819 } else {
820 fatal("StatefulHandleRead: Callback routine attempted to reserve a stateful helper with deferred requests. This can lead to deadlock.\n");
821 }
822 break;
823 case S_HELPER_DEFER:
824 /* the helper is still needed, but can
825 * be used for other requests in the meantime.
826 */
827 srv->flags.reserved = S_HELPER_DEFERRED;
828 srv->deferred_requests++;
60d096f4 829 srv->stats.deferbycb++;
17bb3486 830 debug(84, 5) ("StatefulHandleRead: reserving %s #%d for deferred requests.\n", hlp->id_name, srv->index + 1);
94439e4e 831 break;
832 default:
833 fatal("helperStatefulHandleRead: unknown stateful helper callback result.\n");
834 }
835
836 } else {
17bb3486 837 debug(84, 1) ("StatefulHandleRead: no callback data registered\n");
94439e4e 838 }
839 srv->flags.busy = 0;
840 srv->offset = 0;
841 helperStatefulRequestFree(r);
842 srv->request = NULL;
843 hlp->stats.replies++;
844 hlp->stats.avg_svc_time =
845 intAverage(hlp->stats.avg_svc_time,
846 tvSubMsec(srv->dispatch_time, current_time),
847 hlp->stats.replies, REDIRECT_AV_FACTOR);
5d146f7d 848 if (srv->flags.shutdown
849 && srv->flags.reserved == S_HELPER_FREE
850 && !srv->deferred_requests) {
70160b49 851 int wfd = srv->wfd;
94439e4e 852 srv->wfd = -1;
70160b49 853 comm_close(wfd);
94439e4e 854 } else {
855 if (srv->queue.head)
856 helperStatefulServerKickQueue(srv);
857 else
858 helperStatefulKickQueue(hlp);
859 }
860 } else {
c4b7a5a9 861 comm_read(srv->rfd, srv->buf + srv->offset, srv->buf_sz - srv->offset,
862 helperStatefulHandleRead, srv);
94439e4e 863 }
864}
865
74addf6c 866static void
867Enqueue(helper * hlp, helper_request * r)
868{
e6ccf245 869 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
74addf6c 870 dlinkAddTail(r, link, &hlp->queue);
871 hlp->stats.queue_size++;
872 if (hlp->stats.queue_size < hlp->n_running)
873 return;
874 if (squid_curtime - hlp->last_queue_warn < 600)
875 return;
fe73896c 876 if (shutting_down || reconfiguring)
877 return;
74addf6c 878 hlp->last_queue_warn = squid_curtime;
c916b75b 879 debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
880 debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
74addf6c 881 if (hlp->stats.queue_size > hlp->n_running * 2)
882 fatalf("Too many queued %s requests", hlp->id_name);
c916b75b 883 debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
74addf6c 884}
885
94439e4e 886static void
887StatefulEnqueue(statefulhelper * hlp, helper_stateful_request * r)
888{
e6ccf245 889 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
94439e4e 890 dlinkAddTail(r, link, &hlp->queue);
891 hlp->stats.queue_size++;
892 if (hlp->stats.queue_size < hlp->n_running)
893 return;
893cbac6 894 if (hlp->stats.queue_size > hlp->n_running * 2)
895 fatalf("Too many queued %s requests", hlp->id_name);
94439e4e 896 if (squid_curtime - hlp->last_queue_warn < 600)
897 return;
898 if (shutting_down || reconfiguring)
899 return;
900 hlp->last_queue_warn = squid_curtime;
c916b75b 901 debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
902 debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
903 debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name);
94439e4e 904}
905
906static void
907StatefulServerEnqueue(helper_stateful_server * srv, helper_stateful_request * r)
908{
e6ccf245 909 dlink_node *link = (dlink_node *)memAllocate(MEM_DLINK_NODE);
94439e4e 910 dlinkAddTail(r, link, &srv->queue);
2d70df72 911/* TODO: warning if the queue on this server is more than X
912 * We don't check the queue size at the moment, because
913 * requests hitting here are deferrable
914 */
915/* hlp->stats.queue_size++;
916 * if (hlp->stats.queue_size < hlp->n_running)
917 * return;
918 * if (squid_curtime - hlp->last_queue_warn < 600)
919 * return;
920 * if (shutting_down || reconfiguring)
921 * return;
922 * hlp->last_queue_warn = squid_curtime;
c916b75b 923 * debug(84, 0) ("WARNING: All %s processes are busy.\n", hlp->id_name);
924 * debug(84, 0) ("WARNING: %d pending requests queued\n", hlp->stats.queue_size);
2d70df72 925 * if (hlp->stats.queue_size > hlp->n_running * 2)
926 * fatalf("Too many queued %s requests", hlp->id_name);
c916b75b 927 * debug(84, 1) ("Consider increasing the number of %s processes in your config file.\n", hlp->id_name); */
94439e4e 928}
929
930
74addf6c 931static helper_request *
932Dequeue(helper * hlp)
933{
934 dlink_node *link;
935 helper_request *r = NULL;
936 if ((link = hlp->queue.head)) {
e6ccf245 937 r = (helper_request *)link->data;
74addf6c 938 dlinkDelete(link, &hlp->queue);
db1cd23c 939 memFree(link, MEM_DLINK_NODE);
74addf6c 940 hlp->stats.queue_size--;
941 }
942 return r;
943}
944
94439e4e 945static helper_stateful_request *
946StatefulServerDequeue(helper_stateful_server * srv)
947{
948 dlink_node *link;
949 helper_stateful_request *r = NULL;
950 if ((link = srv->queue.head)) {
e6ccf245 951 r = (helper_stateful_request *)link->data;
94439e4e 952 dlinkDelete(link, &srv->queue);
953 memFree(link, MEM_DLINK_NODE);
954 }
955 return r;
956}
957
958static helper_stateful_request *
959StatefulDequeue(statefulhelper * hlp)
960{
961 dlink_node *link;
962 helper_stateful_request *r = NULL;
963 if ((link = hlp->queue.head)) {
e6ccf245 964 r = (helper_stateful_request *)link->data;
94439e4e 965 dlinkDelete(link, &hlp->queue);
966 memFree(link, MEM_DLINK_NODE);
967 hlp->stats.queue_size--;
968 }
969 return r;
970}
971
74addf6c 972static helper_server *
973GetFirstAvailable(helper * hlp)
974{
975 dlink_node *n;
976 helper_server *srv = NULL;
fe73896c 977 if (hlp->n_running == 0)
978 return NULL;
74addf6c 979 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 980 srv = (helper_server *)n->data;
74addf6c 981 if (srv->flags.busy)
982 continue;
983 if (!srv->flags.alive)
984 continue;
985 return srv;
986 }
987 return NULL;
988}
989
94439e4e 990static helper_stateful_server *
991StatefulGetFirstAvailable(statefulhelper * hlp)
992{
993 dlink_node *n;
994 helper_stateful_server *srv = NULL;
17bb3486 995 debug(84, 5) ("StatefulGetFirstAvailable: Running servers %d.\n", hlp->n_running);
94439e4e 996 if (hlp->n_running == 0)
997 return NULL;
998 for (n = hlp->servers.head; n != NULL; n = n->next) {
e6ccf245 999 srv = (helper_stateful_server *)n->data;
94439e4e 1000 if (srv->flags.busy)
1001 continue;
1002 if (srv->flags.reserved == S_HELPER_RESERVED)
1003 continue;
1004 if (!srv->flags.alive)
1005 continue;
1006 if ((hlp->IsAvailable != NULL) && (srv->data != NULL) && !(hlp->IsAvailable(srv->data)))
1007 continue;
1008 return srv;
1009 }
17bb3486 1010 debug(84, 5) ("StatefulGetFirstAvailable: None available.\n");
94439e4e 1011 return NULL;
1012}
1013
1014
42679bd6 1015static void
1016helperDispatchWriteDone(int fd, char *buf, size_t len, comm_err_t flag, int xerrno, void *data)
1017{
1018 /* nothing! */
1019}
1020
74addf6c 1021static void
1022helperDispatch(helper_server * srv, helper_request * r)
1023{
1024 helper *hlp = srv->parent;
fa80a8ef 1025 if (!cbdataReferenceValid(r->data)) {
17bb3486 1026 debug(84, 1) ("helperDispatch: invalid callback data\n");
74addf6c 1027 helperRequestFree(r);
1028 return;
1029 }
1030 assert(!srv->flags.busy);
1031 srv->flags.busy = 1;
1032 srv->request = r;
1033 srv->dispatch_time = current_time;
42679bd6 1034 comm_write(srv->wfd,
74addf6c 1035 r->buf,
1036 strlen(r->buf),
42679bd6 1037 helperDispatchWriteDone, /* Handler */
1038 hlp); /* Handler-data */
c4b7a5a9 1039 comm_read(srv->rfd, srv->buf + srv->offset, srv->buf_sz - srv->offset, helperHandleRead, srv);
17bb3486 1040 debug(84, 5) ("helperDispatch: Request sent to %s #%d, %d bytes\n",
32754419 1041 hlp->id_name, srv->index + 1, (int) strlen(r->buf));
74addf6c 1042 srv->stats.uses++;
1043 hlp->stats.requests++;
1044}
1045
42679bd6 1046static void
1047helperStatefulDispatchWriteDone(int fd, char *buf, size_t len, comm_err_t flag,
1048 int xerrno, void *data)
1049{
1050 /* nothing! */
1051}
1052
1053
94439e4e 1054static void
1055helperStatefulDispatch(helper_stateful_server * srv, helper_stateful_request * r)
1056{
1057 statefulhelper *hlp = srv->parent;
fa80a8ef 1058 if (!cbdataReferenceValid(r->data)) {
17bb3486 1059 debug(84, 1) ("helperStatefulDispatch: invalid callback data\n");
94439e4e 1060 helperStatefulRequestFree(r);
1061 return;
1062 }
17bb3486 1063 debug(84, 9) ("helperStatefulDispatch busying helper %s #%d\n", hlp->id_name, srv->index + 1);
94439e4e 1064 if (r->placeholder == 1) {
1065 /* a callback is needed before this request can _use_ a helper. */
721b0310 1066 /* we don't care about releasing/deferring this helper. The request NEVER
1067 * gets to the helper. So we throw away the return code */
1068 r->callback(r->data, srv, NULL);
1069 /* throw away the placeholder */
1070 helperStatefulRequestFree(r);
1071 /* and push the queue. Note that the callback may have submitted a new
1072 * request to the helper which is why we test for the request*/
1073 if (srv->request == NULL) {
5d146f7d 1074 if (srv->flags.shutdown
1075 && srv->flags.reserved == S_HELPER_FREE
1076 && !srv->deferred_requests) {
9272e015 1077 int wfd = srv->wfd;
721b0310 1078 srv->wfd = -1;
9272e015 1079 comm_close(wfd);
721b0310 1080 } else {
1081 if (srv->queue.head)
1082 helperStatefulServerKickQueue(srv);
1083 else
1084 helperStatefulKickQueue(hlp);
94439e4e 1085 }
1086 }
1087 return;
1088 }
1089 srv->flags.busy = 1;
1090 srv->request = r;
1091 srv->dispatch_time = current_time;
42679bd6 1092 comm_write(srv->wfd,
94439e4e 1093 r->buf,
1094 strlen(r->buf),
42679bd6 1095 helperStatefulDispatchWriteDone, /* Handler */
1096 hlp); /* Handler-data */
c4b7a5a9 1097 comm_read(srv->rfd, srv->buf + srv->offset, srv->buf_sz - srv->offset,
1098 helperStatefulHandleRead, srv);
17bb3486 1099 debug(84, 5) ("helperStatefulDispatch: Request sent to %s #%d, %d bytes\n",
32754419 1100 hlp->id_name, srv->index + 1, (int) strlen(r->buf));
94439e4e 1101 srv->stats.uses++;
1102 hlp->stats.requests++;
1103}
1104
1105
74addf6c 1106static void
1107helperKickQueue(helper * hlp)
1108{
1109 helper_request *r;
1110 helper_server *srv;
1111 while ((srv = GetFirstAvailable(hlp)) && (r = Dequeue(hlp)))
1112 helperDispatch(srv, r);
1113}
1114
94439e4e 1115static void
1116helperStatefulKickQueue(statefulhelper * hlp)
1117{
1118 helper_stateful_request *r;
1119 helper_stateful_server *srv;
1120 while ((srv = StatefulGetFirstAvailable(hlp)) && (r = StatefulDequeue(hlp)))
1121 helperStatefulDispatch(srv, r);
1122}
1123
1124static void
1125helperStatefulServerKickQueue(helper_stateful_server * srv)
1126{
1127 helper_stateful_request *r;
1128 if ((r = StatefulServerDequeue(srv)))
1129 helperStatefulDispatch(srv, r);
1130}
1131
74addf6c 1132static void
1133helperRequestFree(helper_request * r)
1134{
fa80a8ef 1135 cbdataReferenceDone(r->data);
74addf6c 1136 xfree(r->buf);
db1cd23c 1137 memFree(r, MEM_HELPER_REQUEST);
74addf6c 1138}
94439e4e 1139
1140static void
1141helperStatefulRequestFree(helper_stateful_request * r)
1142{
fa80a8ef 1143 cbdataReferenceDone(r->data);
94439e4e 1144 xfree(r->buf);
1145 memFree(r, MEM_HELPER_STATEFUL_REQUEST);
1146}