/src/httpd/server/scoreboard.c
Line | Count | Source (jump to first uncovered line) |
1 | | /* Licensed to the Apache Software Foundation (ASF) under one or more |
2 | | * contributor license agreements. See the NOTICE file distributed with |
3 | | * this work for additional information regarding copyright ownership. |
4 | | * The ASF licenses this file to You under the Apache License, Version 2.0 |
5 | | * (the "License"); you may not use this file except in compliance with |
6 | | * the License. You may obtain a copy of the License at |
7 | | * |
8 | | * http://www.apache.org/licenses/LICENSE-2.0 |
9 | | * |
10 | | * Unless required by applicable law or agreed to in writing, software |
11 | | * distributed under the License is distributed on an "AS IS" BASIS, |
12 | | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 | | * See the License for the specific language governing permissions and |
14 | | * limitations under the License. |
15 | | */ |
16 | | |
17 | | #include "apr.h" |
18 | | #include "apr_strings.h" |
19 | | #include "apr_portable.h" |
20 | | #include "apr_lib.h" |
21 | | |
22 | | #define APR_WANT_STRFUNC |
23 | | #include "apr_want.h" |
24 | | |
25 | | #if APR_HAVE_SYS_TYPES_H |
26 | | #include <sys/types.h> |
27 | | #endif |
28 | | |
29 | | #include "ap_config.h" |
30 | | #include "httpd.h" |
31 | | #include "http_log.h" |
32 | | #include "http_main.h" |
33 | | #include "http_core.h" |
34 | | #include "http_config.h" |
35 | | #include "http_protocol.h" |
36 | | #include "ap_mpm.h" |
37 | | |
38 | | #include "scoreboard.h" |
39 | | |
40 | | /* we know core's module_index is 0 */ |
41 | | #undef APLOG_MODULE_INDEX |
42 | | #define APLOG_MODULE_INDEX AP_CORE_MODULE_INDEX |
43 | | |
44 | | AP_DECLARE_DATA scoreboard *ap_scoreboard_image = NULL; |
45 | | AP_DECLARE_DATA const char *ap_scoreboard_fname = NULL; |
46 | | static ap_scoreboard_e scoreboard_type; |
47 | | |
48 | | const char * ap_set_scoreboard(cmd_parms *cmd, void *dummy, |
49 | | const char *arg) |
50 | 0 | { |
51 | 0 | const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); |
52 | 0 | if (err != NULL) { |
53 | 0 | return err; |
54 | 0 | } |
55 | | |
56 | 0 | ap_scoreboard_fname = arg; |
57 | 0 | return NULL; |
58 | 0 | } |
59 | | |
60 | | /* Default to false when mod_status is not loaded */ |
61 | | AP_DECLARE_DATA int ap_extended_status = 0; |
62 | | |
63 | | const char *ap_set_extended_status(cmd_parms *cmd, void *dummy, int arg) |
64 | 0 | { |
65 | 0 | const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); |
66 | 0 | if (err != NULL) { |
67 | 0 | return err; |
68 | 0 | } |
69 | 0 | ap_extended_status = arg; |
70 | 0 | return NULL; |
71 | 0 | } |
72 | | |
73 | | AP_DECLARE_DATA int ap_mod_status_reqtail = 0; |
74 | | |
75 | | const char *ap_set_reqtail(cmd_parms *cmd, void *dummy, int arg) |
76 | 0 | { |
77 | 0 | const char *err = ap_check_cmd_context(cmd, GLOBAL_ONLY); |
78 | 0 | if (err != NULL) { |
79 | 0 | return err; |
80 | 0 | } |
81 | 0 | ap_mod_status_reqtail = arg; |
82 | 0 | return NULL; |
83 | 0 | } |
84 | | |
85 | | #if APR_HAS_SHARED_MEMORY |
86 | | |
87 | | #include "apr_shm.h" |
88 | | |
89 | | #ifndef WIN32 |
90 | | static /* but must be exported to mpm_winnt */ |
91 | | #endif |
92 | | apr_shm_t *ap_scoreboard_shm = NULL; |
93 | | |
94 | | #endif |
95 | | |
96 | | APR_HOOK_STRUCT( |
97 | | APR_HOOK_LINK(pre_mpm) |
98 | | ) |
99 | | |
100 | | AP_IMPLEMENT_HOOK_RUN_ALL(int,pre_mpm, |
101 | | (apr_pool_t *p, ap_scoreboard_e sb_type), |
102 | | (p, sb_type),OK,DECLINED) |
103 | | |
104 | | static APR_OPTIONAL_FN_TYPE(ap_logio_get_last_bytes) |
105 | | *pfn_ap_logio_get_last_bytes; |
106 | | |
107 | | struct ap_sb_handle_t { |
108 | | int child_num; |
109 | | int thread_num; |
110 | | }; |
111 | | |
112 | | static int server_limit, thread_limit; |
113 | | static apr_size_t scoreboard_size; |
114 | | |
115 | | /* |
116 | | * ToDo: |
117 | | * This function should be renamed to cleanup_shared |
118 | | * and it should handle cleaning up a scoreboard shared |
119 | | * between processes using any form of IPC (file, shared memory |
120 | | * segment, etc.). Leave it as is now because it is being used |
121 | | * by various MPMs. |
122 | | */ |
123 | | static apr_status_t ap_cleanup_shared_mem(void *d) |
124 | 0 | { |
125 | 0 | #if APR_HAS_SHARED_MEMORY |
126 | 0 | free(ap_scoreboard_image); |
127 | 0 | ap_scoreboard_image = NULL; |
128 | 0 | apr_shm_destroy(ap_scoreboard_shm); |
129 | 0 | #endif |
130 | 0 | return APR_SUCCESS; |
131 | 0 | } |
132 | | |
133 | 0 | #define SIZE_OF_scoreboard APR_ALIGN_DEFAULT(sizeof(scoreboard)) |
134 | 0 | #define SIZE_OF_global_score APR_ALIGN_DEFAULT(sizeof(global_score)) |
135 | 0 | #define SIZE_OF_process_score APR_ALIGN_DEFAULT(sizeof(process_score)) |
136 | 0 | #define SIZE_OF_worker_score APR_ALIGN_DEFAULT(sizeof(worker_score)) |
137 | | |
138 | | AP_DECLARE(int) ap_calc_scoreboard_size(void) |
139 | 0 | { |
140 | 0 | ap_mpm_query(AP_MPMQ_HARD_LIMIT_THREADS, &thread_limit); |
141 | 0 | ap_mpm_query(AP_MPMQ_HARD_LIMIT_DAEMONS, &server_limit); |
142 | |
|
143 | 0 | scoreboard_size = SIZE_OF_global_score; |
144 | 0 | scoreboard_size += SIZE_OF_process_score * server_limit; |
145 | 0 | scoreboard_size += SIZE_OF_worker_score * server_limit * thread_limit; |
146 | |
|
147 | 0 | return scoreboard_size; |
148 | 0 | } |
149 | | |
150 | | AP_DECLARE(void) ap_init_scoreboard(void *shared_score) |
151 | 0 | { |
152 | 0 | char *more_storage; |
153 | 0 | int i; |
154 | |
|
155 | 0 | pfn_ap_logio_get_last_bytes = APR_RETRIEVE_OPTIONAL_FN(ap_logio_get_last_bytes); |
156 | 0 | if (!shared_score) { |
157 | 0 | return; |
158 | 0 | } |
159 | | |
160 | 0 | ap_calc_scoreboard_size(); |
161 | 0 | ap_scoreboard_image = |
162 | 0 | ap_calloc(1, SIZE_OF_scoreboard + server_limit * sizeof(worker_score *)); |
163 | 0 | more_storage = shared_score; |
164 | 0 | ap_scoreboard_image->global = (global_score *)more_storage; |
165 | 0 | more_storage += SIZE_OF_global_score; |
166 | 0 | ap_scoreboard_image->parent = (process_score *)more_storage; |
167 | 0 | more_storage += SIZE_OF_process_score * server_limit; |
168 | 0 | ap_scoreboard_image->servers = |
169 | 0 | (worker_score **)((char*)ap_scoreboard_image + SIZE_OF_scoreboard); |
170 | 0 | for (i = 0; i < server_limit; i++) { |
171 | 0 | ap_scoreboard_image->servers[i] = (worker_score *)more_storage; |
172 | 0 | more_storage += thread_limit * SIZE_OF_worker_score; |
173 | 0 | } |
174 | 0 | ap_assert(more_storage == (char*)shared_score + scoreboard_size); |
175 | 0 | ap_scoreboard_image->global->server_limit = server_limit; |
176 | 0 | ap_scoreboard_image->global->thread_limit = thread_limit; |
177 | 0 | } |
178 | | |
179 | | /** |
180 | | * Create a name-based scoreboard in the given pool using the |
181 | | * given filename. |
182 | | */ |
183 | | static apr_status_t create_namebased_scoreboard(apr_pool_t *pool, |
184 | | const char *fname) |
185 | 0 | { |
186 | 0 | #if APR_HAS_SHARED_MEMORY |
187 | 0 | apr_status_t rv; |
188 | | |
189 | | /* The shared memory file must not exist before we create the |
190 | | * segment. */ |
191 | 0 | apr_shm_remove(fname, pool); /* ignore errors */ |
192 | |
|
193 | 0 | rv = apr_shm_create(&ap_scoreboard_shm, scoreboard_size, fname, pool); |
194 | 0 | if (rv != APR_SUCCESS) { |
195 | 0 | ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00001) |
196 | 0 | "unable to create or access scoreboard \"%s\" " |
197 | 0 | "(name-based shared memory failure)", fname); |
198 | 0 | return rv; |
199 | 0 | } |
200 | 0 | #endif /* APR_HAS_SHARED_MEMORY */ |
201 | 0 | return APR_SUCCESS; |
202 | 0 | } |
203 | | |
204 | | /* ToDo: This function should be made to handle setting up |
205 | | * a scoreboard shared between processes using any IPC technique, |
206 | | * not just a shared memory segment |
207 | | */ |
208 | | static apr_status_t open_scoreboard(apr_pool_t *pconf) |
209 | 0 | { |
210 | 0 | #if APR_HAS_SHARED_MEMORY |
211 | 0 | apr_status_t rv; |
212 | 0 | char *fname = NULL; |
213 | 0 | apr_pool_t *global_pool = apr_pool_parent_get(pconf); |
214 | | |
215 | | /* If this is not passed pconf, or pconf is no longer a direct |
216 | | * child of a global pool, this should change... */ |
217 | 0 | AP_DEBUG_ASSERT(apr_pool_parent_get(global_pool) == NULL); |
218 | | |
219 | | /* The config says to create a name-based shmem */ |
220 | 0 | if (ap_scoreboard_fname) { |
221 | | /* make sure it's an absolute pathname */ |
222 | 0 | fname = ap_runtime_dir_relative(pconf, ap_scoreboard_fname); |
223 | 0 | if (!fname) { |
224 | 0 | ap_log_error(APLOG_MARK, APLOG_CRIT, APR_EBADPATH, ap_server_conf, APLOGNO(00003) |
225 | 0 | "Fatal error: Invalid Scoreboard path %s", |
226 | 0 | ap_scoreboard_fname); |
227 | 0 | return APR_EBADPATH; |
228 | 0 | } |
229 | 0 | return create_namebased_scoreboard(global_pool, fname); |
230 | 0 | } |
231 | 0 | else { /* config didn't specify, we get to choose shmem type */ |
232 | 0 | rv = apr_shm_create(&ap_scoreboard_shm, scoreboard_size, NULL, |
233 | 0 | global_pool); /* anonymous shared memory */ |
234 | 0 | if ((rv != APR_SUCCESS) && (rv != APR_ENOTIMPL)) { |
235 | 0 | ap_log_error(APLOG_MARK, APLOG_CRIT, rv, ap_server_conf, APLOGNO(00004) |
236 | 0 | "Unable to create or access scoreboard " |
237 | 0 | "(anonymous shared memory failure)"); |
238 | 0 | return rv; |
239 | 0 | } |
240 | | /* Make up a filename and do name-based shmem */ |
241 | 0 | else if (rv == APR_ENOTIMPL) { |
242 | | /* Make sure it's an absolute pathname */ |
243 | 0 | ap_scoreboard_fname = DEFAULT_SCOREBOARD; |
244 | 0 | fname = ap_runtime_dir_relative(pconf, ap_scoreboard_fname); |
245 | |
|
246 | 0 | return create_namebased_scoreboard(global_pool, fname); |
247 | 0 | } |
248 | 0 | } |
249 | 0 | #endif /* APR_HAS_SHARED_MEMORY */ |
250 | 0 | return APR_SUCCESS; |
251 | 0 | } |
252 | | |
253 | | /* If detach is non-zero, this is a separate child process, |
254 | | * if zero, it is a forked child. |
255 | | */ |
256 | | AP_DECLARE(apr_status_t) ap_reopen_scoreboard(apr_pool_t *p, apr_shm_t **shm, |
257 | | int detached) |
258 | 0 | { |
259 | 0 | #if APR_HAS_SHARED_MEMORY |
260 | 0 | if (!detached) { |
261 | 0 | return APR_SUCCESS; |
262 | 0 | } |
263 | 0 | if (apr_shm_size_get(ap_scoreboard_shm) < scoreboard_size) { |
264 | 0 | ap_log_error(APLOG_MARK, APLOG_CRIT, 0, ap_server_conf, APLOGNO(00005) |
265 | 0 | "Fatal error: shared scoreboard too small for child!"); |
266 | 0 | apr_shm_detach(ap_scoreboard_shm); |
267 | 0 | ap_scoreboard_shm = NULL; |
268 | 0 | return APR_EINVAL; |
269 | 0 | } |
270 | | /* everything will be cleared shortly */ |
271 | 0 | if (*shm) { |
272 | 0 | *shm = ap_scoreboard_shm; |
273 | 0 | } |
274 | 0 | #endif |
275 | 0 | return APR_SUCCESS; |
276 | 0 | } |
277 | | |
278 | | apr_status_t ap_cleanup_scoreboard(void *d) |
279 | 0 | { |
280 | 0 | if (ap_scoreboard_image == NULL) { |
281 | 0 | return APR_SUCCESS; |
282 | 0 | } |
283 | 0 | if (scoreboard_type == SB_SHARED) { |
284 | 0 | ap_cleanup_shared_mem(NULL); |
285 | 0 | } |
286 | 0 | else { |
287 | 0 | free(ap_scoreboard_image->global); |
288 | 0 | free(ap_scoreboard_image); |
289 | 0 | ap_scoreboard_image = NULL; |
290 | 0 | } |
291 | 0 | return APR_SUCCESS; |
292 | 0 | } |
293 | | |
294 | | /* Create or reinit an existing scoreboard. The MPM can control whether |
295 | | * the scoreboard is shared across multiple processes or not |
296 | | */ |
297 | | int ap_create_scoreboard(apr_pool_t *p, ap_scoreboard_e sb_type) |
298 | 0 | { |
299 | 0 | int i; |
300 | 0 | #if APR_HAS_SHARED_MEMORY |
301 | 0 | apr_status_t rv; |
302 | 0 | #endif |
303 | |
|
304 | 0 | if (ap_scoreboard_image) { |
305 | 0 | ap_scoreboard_image->global->restart_time = apr_time_now(); |
306 | 0 | memset(ap_scoreboard_image->parent, 0, |
307 | 0 | SIZE_OF_process_score * server_limit); |
308 | 0 | for (i = 0; i < server_limit; i++) { |
309 | 0 | memset(ap_scoreboard_image->servers[i], 0, |
310 | 0 | SIZE_OF_worker_score * thread_limit); |
311 | 0 | } |
312 | 0 | ap_init_scoreboard(NULL); |
313 | 0 | return OK; |
314 | 0 | } |
315 | | |
316 | 0 | ap_calc_scoreboard_size(); |
317 | 0 | #if APR_HAS_SHARED_MEMORY |
318 | 0 | if (sb_type == SB_SHARED) { |
319 | 0 | void *sb_shared; |
320 | 0 | rv = open_scoreboard(p); |
321 | 0 | if (rv || !(sb_shared = apr_shm_baseaddr_get(ap_scoreboard_shm))) { |
322 | 0 | return HTTP_INTERNAL_SERVER_ERROR; |
323 | 0 | } |
324 | 0 | memset(sb_shared, 0, scoreboard_size); |
325 | 0 | ap_init_scoreboard(sb_shared); |
326 | 0 | } |
327 | 0 | else |
328 | 0 | #endif |
329 | 0 | { |
330 | | /* A simple malloc will suffice */ |
331 | 0 | void *sb_mem = ap_calloc(1, scoreboard_size); |
332 | 0 | ap_init_scoreboard(sb_mem); |
333 | 0 | } |
334 | | |
335 | 0 | scoreboard_type = sb_type; |
336 | 0 | ap_scoreboard_image->global->running_generation = 0; |
337 | 0 | ap_scoreboard_image->global->restart_time = apr_time_now(); |
338 | |
|
339 | 0 | apr_pool_cleanup_register(p, NULL, ap_cleanup_scoreboard, apr_pool_cleanup_null); |
340 | |
|
341 | 0 | return OK; |
342 | 0 | } |
343 | | |
344 | | /* Routines called to deal with the scoreboard image |
345 | | * --- note that we do *not* need write locks, since update_child_status |
346 | | * only updates a *single* record in place, and only one process writes to |
347 | | * a given scoreboard slot at a time (either the child process owning that |
348 | | * slot, or the parent, noting that the child has died). |
349 | | * |
350 | | * As a final note --- setting the score entry to getpid() is always safe, |
351 | | * since when the parent is writing an entry, it's only noting SERVER_DEAD |
352 | | * anyway. |
353 | | */ |
354 | | |
355 | | AP_DECLARE(int) ap_exists_scoreboard_image(void) |
356 | 0 | { |
357 | 0 | return (ap_scoreboard_image ? 1 : 0); |
358 | 0 | } |
359 | | |
360 | | AP_DECLARE(void) ap_set_conn_count(ap_sb_handle_t *sb, request_rec *r, |
361 | | unsigned short conn_count) |
362 | 0 | { |
363 | 0 | worker_score *ws; |
364 | |
|
365 | 0 | if (!sb) |
366 | 0 | return; |
367 | | |
368 | 0 | ws = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num]; |
369 | 0 | ws->conn_count = conn_count; |
370 | 0 | } |
371 | | |
372 | | AP_DECLARE(void) ap_increment_counts(ap_sb_handle_t *sb, request_rec *r) |
373 | 0 | { |
374 | 0 | worker_score *ws; |
375 | 0 | apr_off_t bytes; |
376 | |
|
377 | 0 | if (!sb) |
378 | 0 | return; |
379 | | |
380 | 0 | ws = &ap_scoreboard_image->servers[sb->child_num][sb->thread_num]; |
381 | 0 | if (pfn_ap_logio_get_last_bytes != NULL) { |
382 | 0 | bytes = pfn_ap_logio_get_last_bytes(r->connection); |
383 | 0 | } |
384 | 0 | else if (r->method_number == M_GET && r->method && r->method[0] == 'H') { |
385 | 0 | bytes = 0; |
386 | 0 | } |
387 | 0 | else { |
388 | 0 | bytes = r->bytes_sent; |
389 | 0 | } |
390 | |
|
391 | 0 | #ifdef HAVE_TIMES |
392 | 0 | times(&ws->times); |
393 | 0 | #endif |
394 | 0 | ws->access_count++; |
395 | 0 | ws->my_access_count++; |
396 | 0 | ws->conn_count++; |
397 | 0 | ws->bytes_served += bytes; |
398 | 0 | ws->my_bytes_served += bytes; |
399 | 0 | ws->conn_bytes += bytes; |
400 | 0 | } |
401 | | |
402 | | AP_DECLARE(int) ap_find_child_by_pid(apr_proc_t *pid) |
403 | 0 | { |
404 | 0 | int i; |
405 | 0 | int max_daemons_limit = 0; |
406 | |
|
407 | 0 | ap_mpm_query(AP_MPMQ_MAX_DAEMON_USED, &max_daemons_limit); |
408 | |
|
409 | 0 | for (i = 0; i < max_daemons_limit; ++i) { |
410 | 0 | if (ap_scoreboard_image->parent[i].pid == pid->pid) { |
411 | 0 | return i; |
412 | 0 | } |
413 | 0 | } |
414 | | |
415 | 0 | return -1; |
416 | 0 | } |
417 | | |
418 | | AP_DECLARE(void) ap_update_sb_handle(ap_sb_handle_t *sbh, |
419 | | int child_num, int thread_num) |
420 | 0 | { |
421 | 0 | sbh->child_num = child_num; |
422 | 0 | sbh->thread_num = thread_num; |
423 | 0 | } |
424 | | |
425 | | AP_DECLARE(void) ap_create_sb_handle(ap_sb_handle_t **new_sbh, apr_pool_t *p, |
426 | | int child_num, int thread_num) |
427 | 0 | { |
428 | 0 | *new_sbh = (ap_sb_handle_t *)apr_palloc(p, sizeof(ap_sb_handle_t)); |
429 | 0 | ap_update_sb_handle(*new_sbh, child_num, thread_num); |
430 | 0 | } |
431 | | |
432 | | AP_DECLARE(void) ap_sb_get_child_thread(ap_sb_handle_t *sbh, |
433 | | int *pchild_num, int *pthread_num) |
434 | 0 | { |
435 | 0 | AP_DEBUG_ASSERT(sbh); |
436 | 0 | *pchild_num = sbh->child_num; |
437 | 0 | *pthread_num = sbh->thread_num; |
438 | 0 | } |
439 | | |
440 | | static void copy_request(char *rbuf, apr_size_t rbuflen, request_rec *r) |
441 | 0 | { |
442 | 0 | char *p; |
443 | |
|
444 | 0 | if (r->the_request == NULL) { |
445 | 0 | apr_cpystrn(rbuf, "NULL", rbuflen); |
446 | 0 | return; /* short circuit below */ |
447 | 0 | } |
448 | | |
449 | 0 | if (r->parsed_uri.password == NULL) { |
450 | 0 | p = r->the_request; |
451 | 0 | } |
452 | 0 | else { |
453 | | /* Don't reveal the password in the server-status view */ |
454 | 0 | p = apr_pstrcat(r->pool, r->method, " ", |
455 | 0 | apr_uri_unparse(r->pool, &r->parsed_uri, |
456 | 0 | APR_URI_UNP_OMITPASSWORD), |
457 | 0 | r->assbackwards ? NULL : " ", r->protocol, NULL); |
458 | 0 | } |
459 | | |
460 | | /* now figure out if we copy over the 1st rbuflen chars or the last */ |
461 | 0 | if (!ap_mod_status_reqtail) { |
462 | 0 | apr_cpystrn(rbuf, p, rbuflen); |
463 | 0 | } |
464 | 0 | else { |
465 | 0 | apr_size_t slen = strlen(p); |
466 | 0 | if (slen < rbuflen) { |
467 | | /* it all fits anyway */ |
468 | 0 | apr_cpystrn(rbuf, p, rbuflen); |
469 | 0 | } |
470 | 0 | else { |
471 | 0 | apr_cpystrn(rbuf, p+(slen-rbuflen+1), rbuflen); |
472 | 0 | } |
473 | 0 | } |
474 | 0 | } |
475 | | |
476 | | static int update_child_status_internal(int child_num, |
477 | | int thread_num, |
478 | | int status, |
479 | | conn_rec *c, |
480 | | server_rec *s, |
481 | | request_rec *r, |
482 | | const char *descr) |
483 | 0 | { |
484 | 0 | int old_status; |
485 | 0 | worker_score *ws; |
486 | 0 | int mpm_generation; |
487 | |
|
488 | 0 | ws = &ap_scoreboard_image->servers[child_num][thread_num]; |
489 | 0 | old_status = ws->status; |
490 | 0 | ws->status = status; |
491 | | |
492 | 0 | if (status == SERVER_READY |
493 | 0 | && old_status == SERVER_STARTING) { |
494 | 0 | process_score *ps = &ap_scoreboard_image->parent[child_num]; |
495 | 0 | ws->thread_num = child_num * thread_limit + thread_num; |
496 | 0 | ap_mpm_query(AP_MPMQ_GENERATION, &mpm_generation); |
497 | 0 | ps->generation = mpm_generation; |
498 | 0 | } |
499 | |
|
500 | 0 | if (ap_extended_status) { |
501 | 0 | const char *val; |
502 | | |
503 | 0 | if (status == SERVER_READY || status == SERVER_DEAD) { |
504 | | /* |
505 | | * Reset individual counters |
506 | | */ |
507 | 0 | if (status == SERVER_DEAD) { |
508 | 0 | ws->my_access_count = 0L; |
509 | 0 | ws->my_bytes_served = 0L; |
510 | 0 | #ifdef HAVE_TIMES |
511 | 0 | ws->times.tms_utime = 0; |
512 | 0 | ws->times.tms_stime = 0; |
513 | 0 | ws->times.tms_cutime = 0; |
514 | 0 | ws->times.tms_cstime = 0; |
515 | 0 | #endif |
516 | 0 | } |
517 | 0 | ws->conn_count = 0; |
518 | 0 | ws->conn_bytes = 0; |
519 | 0 | ws->last_used = apr_time_now(); |
520 | 0 | } |
521 | |
|
522 | 0 | if (descr) { |
523 | 0 | apr_cpystrn(ws->request, descr, sizeof(ws->request)); |
524 | 0 | } |
525 | 0 | else if (r) { |
526 | 0 | copy_request(ws->request, sizeof(ws->request), r); |
527 | 0 | } |
528 | 0 | else if (c) { |
529 | 0 | ws->request[0]='\0'; |
530 | 0 | } |
531 | |
|
532 | 0 | if (r && r->useragent_ip) { |
533 | 0 | if (!(val = ap_get_useragent_host(r, REMOTE_NOLOOKUP, NULL))) { |
534 | 0 | apr_cpystrn(ws->client, r->useragent_ip, sizeof(ws->client)); /* DEPRECATE */ |
535 | 0 | apr_cpystrn(ws->client64, r->useragent_ip, sizeof(ws->client64)); |
536 | 0 | } |
537 | 0 | else { |
538 | 0 | apr_cpystrn(ws->client, val, sizeof(ws->client)); /* DEPRECATE */ |
539 | 0 | apr_cpystrn(ws->client64, val, sizeof(ws->client64)); |
540 | 0 | } |
541 | 0 | } |
542 | 0 | else if (c) { |
543 | 0 | if (!(val = ap_get_remote_host(c, c->base_server->lookup_defaults, |
544 | 0 | REMOTE_NOLOOKUP, NULL))) { |
545 | 0 | apr_cpystrn(ws->client, c->client_ip, sizeof(ws->client)); /* DEPRECATE */ |
546 | 0 | apr_cpystrn(ws->client64, c->client_ip, sizeof(ws->client64)); |
547 | 0 | } |
548 | 0 | else { |
549 | 0 | apr_cpystrn(ws->client, val, sizeof(ws->client)); /* DEPRECATE */ |
550 | 0 | apr_cpystrn(ws->client64, val, sizeof(ws->client64)); |
551 | 0 | } |
552 | 0 | } |
553 | |
|
554 | 0 | if (s) { |
555 | 0 | if (c) { |
556 | 0 | apr_snprintf(ws->vhost, sizeof(ws->vhost), "%s:%d", |
557 | 0 | s->server_hostname, c->local_addr->port); |
558 | 0 | } |
559 | 0 | else { |
560 | 0 | apr_cpystrn(ws->vhost, s->server_hostname, sizeof(ws->vhost)); |
561 | 0 | } |
562 | 0 | } |
563 | 0 | else if (c) { |
564 | 0 | ws->vhost[0]='\0'; |
565 | 0 | } |
566 | |
|
567 | 0 | if (c) { |
568 | 0 | val = ap_get_protocol(c); |
569 | 0 | apr_cpystrn(ws->protocol, val, sizeof(ws->protocol)); |
570 | 0 | } |
571 | 0 | } |
572 | |
|
573 | 0 | return old_status; |
574 | 0 | } |
575 | | |
576 | | AP_DECLARE(int) ap_update_child_status_from_indexes(int child_num, |
577 | | int thread_num, |
578 | | int status, |
579 | | request_rec *r) |
580 | 0 | { |
581 | 0 | if (child_num < 0) { |
582 | 0 | return -1; |
583 | 0 | } |
584 | | |
585 | 0 | return update_child_status_internal(child_num, thread_num, status, |
586 | 0 | r ? r->connection : NULL, |
587 | 0 | r ? r->server : NULL, |
588 | 0 | r, NULL); |
589 | 0 | } |
590 | | |
591 | | AP_DECLARE(int) ap_update_child_status(ap_sb_handle_t *sbh, int status, |
592 | | request_rec *r) |
593 | 0 | { |
594 | 0 | if (!sbh || (sbh->child_num < 0)) |
595 | 0 | return -1; |
596 | | |
597 | 0 | return update_child_status_internal(sbh->child_num, sbh->thread_num, |
598 | 0 | status, |
599 | 0 | r ? r->connection : NULL, |
600 | 0 | r ? r->server : NULL, |
601 | 0 | r, NULL); |
602 | 0 | } |
603 | | |
604 | | AP_DECLARE(int) ap_update_child_status_from_conn(ap_sb_handle_t *sbh, int status, |
605 | | conn_rec *c) |
606 | 0 | { |
607 | 0 | if (!sbh || (sbh->child_num < 0)) |
608 | 0 | return -1; |
609 | | |
610 | 0 | return update_child_status_internal(sbh->child_num, sbh->thread_num, |
611 | 0 | status, c, NULL, NULL, NULL); |
612 | 0 | } |
613 | | |
614 | | AP_DECLARE(int) ap_update_child_status_from_server(ap_sb_handle_t *sbh, int status, |
615 | | conn_rec *c, server_rec *s) |
616 | 0 | { |
617 | 0 | if (!sbh || (sbh->child_num < 0)) |
618 | 0 | return -1; |
619 | | |
620 | 0 | return update_child_status_internal(sbh->child_num, sbh->thread_num, |
621 | 0 | status, c, s, NULL, NULL); |
622 | 0 | } |
623 | | |
624 | | AP_DECLARE(int) ap_update_child_status_descr(ap_sb_handle_t *sbh, int status, const char *descr) |
625 | 0 | { |
626 | 0 | if (!sbh || (sbh->child_num < 0)) |
627 | 0 | return -1; |
628 | | |
629 | 0 | return update_child_status_internal(sbh->child_num, sbh->thread_num, |
630 | 0 | status, NULL, NULL, NULL, descr); |
631 | 0 | } |
632 | | |
633 | | AP_DECLARE(void) ap_time_process_request(ap_sb_handle_t *sbh, int status) |
634 | 0 | { |
635 | 0 | worker_score *ws; |
636 | |
|
637 | 0 | if (!sbh) |
638 | 0 | return; |
639 | | |
640 | 0 | if (sbh->child_num < 0) { |
641 | 0 | return; |
642 | 0 | } |
643 | | |
644 | 0 | ws = &ap_scoreboard_image->servers[sbh->child_num][sbh->thread_num]; |
645 | |
|
646 | 0 | if (status == START_PREQUEST) { |
647 | 0 | ws->start_time = ws->last_used = apr_time_now(); |
648 | 0 | } |
649 | 0 | else if (status == STOP_PREQUEST) { |
650 | 0 | ws->stop_time = ws->last_used = apr_time_now(); |
651 | 0 | if (ap_extended_status) { |
652 | 0 | ws->duration += ws->stop_time - ws->start_time; |
653 | 0 | } |
654 | 0 | } |
655 | 0 | } |
656 | | |
657 | | AP_DECLARE(int) ap_update_global_status() |
658 | 0 | { |
659 | 0 | #ifdef HAVE_TIMES |
660 | 0 | if (ap_scoreboard_image == NULL) { |
661 | 0 | return APR_SUCCESS; |
662 | 0 | } |
663 | 0 | times(&ap_scoreboard_image->global->times); |
664 | 0 | #endif |
665 | 0 | return APR_SUCCESS; |
666 | 0 | } |
667 | | |
668 | | AP_DECLARE(worker_score *) ap_get_scoreboard_worker_from_indexes(int x, int y) |
669 | 0 | { |
670 | 0 | if (((x < 0) || (x >= server_limit)) || |
671 | 0 | ((y < 0) || (y >= thread_limit))) { |
672 | 0 | return(NULL); /* Out of range */ |
673 | 0 | } |
674 | 0 | return &ap_scoreboard_image->servers[x][y]; |
675 | 0 | } |
676 | | |
677 | | AP_DECLARE(worker_score *) ap_get_scoreboard_worker(ap_sb_handle_t *sbh) |
678 | 0 | { |
679 | 0 | if (!sbh) |
680 | 0 | return NULL; |
681 | | |
682 | 0 | return ap_get_scoreboard_worker_from_indexes(sbh->child_num, |
683 | 0 | sbh->thread_num); |
684 | 0 | } |
685 | | |
686 | | AP_DECLARE(void) ap_copy_scoreboard_worker(worker_score *dest, |
687 | | int child_num, |
688 | | int thread_num) |
689 | 0 | { |
690 | 0 | worker_score *ws = ap_get_scoreboard_worker_from_indexes(child_num, thread_num); |
691 | |
|
692 | 0 | memcpy(dest, ws, sizeof *ws); |
693 | | |
694 | | /* For extra safety, NUL-terminate the strings returned, though it |
695 | | * should be true those last bytes are always zero anyway. */ |
696 | 0 | dest->client[sizeof(dest->client) - 1] = '\0'; |
697 | 0 | dest->client64[sizeof(dest->client64) - 1] = '\0'; |
698 | 0 | dest->request[sizeof(dest->request) - 1] = '\0'; |
699 | 0 | dest->vhost[sizeof(dest->vhost) - 1] = '\0'; |
700 | 0 | dest->protocol[sizeof(dest->protocol) - 1] = '\0'; |
701 | 0 | } |
702 | | |
703 | | AP_DECLARE(process_score *) ap_get_scoreboard_process(int x) |
704 | 0 | { |
705 | 0 | if ((x < 0) || (x >= server_limit)) { |
706 | 0 | return(NULL); /* Out of range */ |
707 | 0 | } |
708 | 0 | return &ap_scoreboard_image->parent[x]; |
709 | 0 | } |
710 | | |
711 | | AP_DECLARE(global_score *) ap_get_scoreboard_global() |
712 | 0 | { |
713 | 0 | return ap_scoreboard_image->global; |
714 | 0 | } |