1 /* $NetBSD: isctest.c,v 1.7 2022/09/23 12:15:34 christos Exp $ */
2
3 /*
4 * Copyright (C) Internet Systems Consortium, Inc. ("ISC")
5 *
6 * SPDX-License-Identifier: MPL-2.0
7 *
8 * This Source Code Form is subject to the terms of the Mozilla Public
9 * License, v. 2.0. If a copy of the MPL was not distributed with this
10 * file, you can obtain one at https://mozilla.org/MPL/2.0/.
11 *
12 * See the COPYRIGHT file distributed with this work for additional
13 * information regarding copyright ownership.
14 */
15
16 /*! \file */
17
18 #include "isctest.h"
19 #include <inttypes.h>
20 #include <stdbool.h>
21 #include <stdlib.h>
22 #include <time.h>
23
24 #include <isc/buffer.h>
25 #include <isc/hash.h>
26 #include <isc/managers.h>
27 #include <isc/mem.h>
28 #include <isc/os.h>
29 #include <isc/socket.h>
30 #include <isc/string.h>
31 #include <isc/task.h>
32 #include <isc/timer.h>
33 #include <isc/util.h>
34
35 isc_mem_t *test_mctx = NULL;
36 isc_log_t *test_lctx = NULL;
37 isc_taskmgr_t *taskmgr = NULL;
38 isc_timermgr_t *timermgr = NULL;
39 isc_socketmgr_t *socketmgr = NULL;
40 isc_nm_t *netmgr = NULL;
41 isc_task_t *maintask = NULL;
42 int ncpus;
43
44 static bool test_running = false;
45
46 /*
47 * Logging categories: this needs to match the list in bin/named/log.c.
48 */
49 static isc_logcategory_t categories[] = { { "", 0 },
50 { "client", 0 },
51 { "network", 0 },
52 { "update", 0 },
53 { "queries", 0 },
54 { "unmatched", 0 },
55 { "update-security", 0 },
56 { "query-errors", 0 },
57 { NULL, 0 } };
58
59 static void
cleanup_managers(void)60 cleanup_managers(void) {
61 if (maintask != NULL) {
62 isc_task_shutdown(maintask);
63 isc_task_destroy(&maintask);
64 }
65
66 isc_managers_destroy(netmgr == NULL ? NULL : &netmgr,
67 taskmgr == NULL ? NULL : &taskmgr);
68
69 if (socketmgr != NULL) {
70 isc_socketmgr_destroy(&socketmgr);
71 }
72 if (timermgr != NULL) {
73 isc_timermgr_destroy(&timermgr);
74 }
75 }
76
77 static isc_result_t
create_managers(unsigned int workers)78 create_managers(unsigned int workers) {
79 isc_result_t result;
80 char *p;
81
82 if (workers == 0) {
83 workers = isc_os_ncpus();
84 }
85
86 p = getenv("ISC_TASK_WORKERS");
87 if (p != NULL) {
88 workers = atoi(p);
89 }
90
91 CHECK(isc_managers_create(test_mctx, workers, 0, &netmgr, &taskmgr));
92 CHECK(isc_task_create_bound(taskmgr, 0, &maintask, 0));
93 isc_taskmgr_setexcltask(taskmgr, maintask);
94
95 CHECK(isc_timermgr_create(test_mctx, &timermgr));
96 CHECK(isc_socketmgr_create(test_mctx, &socketmgr));
97 return (ISC_R_SUCCESS);
98
99 cleanup:
100 cleanup_managers();
101 return (result);
102 }
103
104 isc_result_t
isc_test_begin(FILE * logfile,bool start_managers,unsigned int workers)105 isc_test_begin(FILE *logfile, bool start_managers, unsigned int workers) {
106 isc_result_t result;
107
108 INSIST(!test_running);
109 test_running = true;
110
111 isc_mem_debugging |= ISC_MEM_DEBUGRECORD;
112
113 INSIST(test_mctx == NULL);
114 isc_mem_create(&test_mctx);
115
116 if (logfile != NULL) {
117 isc_logdestination_t destination;
118 isc_logconfig_t *logconfig = NULL;
119
120 INSIST(test_lctx == NULL);
121 isc_log_create(test_mctx, &test_lctx, &logconfig);
122 isc_log_registercategories(test_lctx, categories);
123 isc_log_setcontext(test_lctx);
124
125 destination.file.stream = logfile;
126 destination.file.name = NULL;
127 destination.file.versions = ISC_LOG_ROLLNEVER;
128 destination.file.maximum_size = 0;
129 isc_log_createchannel(logconfig, "stderr", ISC_LOG_TOFILEDESC,
130 ISC_LOG_DYNAMIC, &destination, 0);
131 CHECK(isc_log_usechannel(logconfig, "stderr", NULL, NULL));
132 }
133
134 ncpus = isc_os_ncpus();
135
136 if (start_managers) {
137 CHECK(create_managers(workers));
138 }
139
140 return (ISC_R_SUCCESS);
141
142 cleanup:
143 isc_test_end();
144 return (result);
145 }
146
147 void
isc_test_end(void)148 isc_test_end(void) {
149 if (maintask != NULL) {
150 isc_task_detach(&maintask);
151 }
152
153 cleanup_managers();
154
155 if (test_lctx != NULL) {
156 isc_log_destroy(&test_lctx);
157 }
158 if (test_mctx != NULL) {
159 isc_mem_destroy(&test_mctx);
160 }
161
162 test_running = false;
163 }
164
165 /*
166 * Sleep for 'usec' microseconds.
167 */
168 void
isc_test_nap(uint32_t usec)169 isc_test_nap(uint32_t usec) {
170 struct timespec ts;
171
172 ts.tv_sec = usec / 1000000;
173 ts.tv_nsec = (usec % 1000000) * 1000;
174 nanosleep(&ts, NULL);
175 }
176