Coverage Report

Created: 2023-03-26 06:28

/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
}