1 /*------------------------------------------------------------------------------
2  *
3  * Copyright (c) 2011-2021, EURid vzw. All rights reserved.
4  * The YADIFA TM software product is provided under the BSD 3-clause license:
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  *        * Redistributions of source code must retain the above copyright
11  *          notice, this list of conditions and the following disclaimer.
12  *        * Redistributions in binary form must reproduce the above copyright
13  *          notice, this list of conditions and the following disclaimer in the
14  *          documentation and/or other materials provided with the distribution.
15  *        * Neither the name of EURid nor the names of its contributors may be
16  *          used to endorse or promote products derived from this software
17  *          without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
23  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  *
31  *------------------------------------------------------------------------------
32  *
33  */
34 
35 /** @defgroup test
36  *  @ingroup test
37  *  @brief logger_test file
38  *
39  * logger_test test program, will not be installed with a "make install"
40  *
41  * To create a new test based on the logger_test:
42  *
43  * _ copy the folder
44  * _ replace "logger_test" by the name of the test
45  * _ add the test to the top level Makefile.am and configure.ac
46  *
47  */
48 #include <sys/mman.h>
49 
50 #include <dnscore/dnscore.h>
51 #include <dnscore/logger.h>
52 #include <dnscore/fdtools.h>
53 #include <dnscore/file_output_stream.h>
54 #include <dnscore/logger_channel_stream.h>
55 #include <dnscore/thread_pool.h>
56 #include <dnscore/zalloc.h>
57 #include <dnscore/shared-heap.h>
58 #include <dnscore/buffer_output_stream.h>
59 #include <dnscore/process.h>
60 #include <dnscore/async.h>
61 #include <dnscore/server-setup.h>
62 #include <dnscore/socket-server.h>
63 
64 pid_t fork_ex();
65 
66 
67 static logger_handle *g_parent_logger = LOGGER_HANDLE_SINK;
68 static logger_handle *g_child_logger = LOGGER_HANDLE_SINK;
69 
70 #define HEAP_SIZE 0x40000000
71 
72 #define CHILDREN 4
73 
74 #define MMAP_TEST 0
75 #if 0
76 #define MICROPAUSE 10000
77 #endif
78 
79 static char one_kb_string[1048] =
80     "BEGIN0123456789ABCDEFGHIJKLMNOPQ"
81     "RSTUVWXYZabcdefghijklmnopqrstuvw"
82     "xyz-j7YZ5sjpN2GPC6B870yZ3HJBIbpk"
83     "7v6hmzxHu6eAomRhAb9ikkfxSP1qy7S6"
84     "Q6cnNREREssBkSv8hlsEoD0GR0Ip1Tu1"
85     "yDQj2LhCpzTJacaJ1qxJ2TjoQxoVi6xe"
86     "m7DHzeUvyJca06wmuZOs0oKGQmJFRu9a"
87     "uz9f8fT8onBFjgBpBcPmzor7rEpqWrcK"
88     "NEtpoueRln6q1qSK6RUkULbYwLShTWgD"
89     "bMstlAEVp5EqUIPhlQXSf4eOpImJM4Yt"
90     "Lu4LFThG5GU8n9zNTk4WlxcGQCj8Emx1"
91     "pqtjHWx55lLiqoJCLgDYPDN99vjB8ukz"
92     "XfaXHQIjq44rnxvwpf7cEpMMxHCp7IOO"
93     "18nJ42O4CmxTfoKtIkJkuA0NczkitEeF"
94     "64Gtj3TubiBLtfRra8zBN8ByqfeeQZG1"
95     "XgHaO6s6covHabtb0gzLVV1GenCPvYfp"
96     "pivvH8lSWvkeH0xJ5zTjG19Voql883Ii"
97     "y28NCXTosBFe81DhvqHQgQ7FU7Njv96o"
98     "kiC9Cr8f6CEXp23qe8fL3A4iaEcMPg4f"
99     "iRZzUAQtblzzf3nryBpe7gHZiIjE1kUG"
100     "eMXJehH0LDFrWR4AmUhZNxR8aK1RSFKZ"
101     "Uy32zPIx6TMrTFncSTBgqluwObbFAk6R"
102     "1G6ToGPL1X75JNpwXhURN752RNQQUCGo"
103     "Vv1SMKBTzpMXH9hfy33wllyiru6ZAciJ"
104     "iAa0KmlE9vfqYIv6hA0PyMqIwP7twDRs"
105     "kuVI4tbBBY5ScHsa42SnsFpYEXBJuKk1"
106     "LFQ4sQED1Stvt5rtf7FDUx316eZ64qVB"
107     "1k1sO9YgNzrrv3gpip3vcHr6SWLybVMa"
108     "yw047f0YZhjfNXg2YOXPJaNmXvKaUiOe"
109     "SyeINNqCIQuDzCUYeLscEEWaoyx5NAyt"
110     "mj9hcK4v3S4zLpB3fs1xa5icmV9uz2SW"
111     "Uk75WhbSnQ3iW8kMcP1TYz9yDIufAz6m"
112     "THE-END";
113 
114 struct thread_ctx
115 {
116     async_wait_s *aw;
117     logger_handle *logger;
118     int f;
119     int count;
120 };
121 
122 static char logging_stuff_thread_tag[8] = "stuff";
123 
124 static void*
logging_stuff_thread(void * args)125 logging_stuff_thread(void *args)
126 {
127     struct thread_ctx *ctx = (struct thread_ctx*)args;
128     async_wait_s *aw = ctx->aw;
129     int f = ctx->f;
130     int count = ctx->count;
131 
132 #define MODULE_MSG_HANDLE ctx->logger
133 
134     logger_handle_set_thread_tag(logging_stuff_thread_tag);
135 
136     async_wait(aw);
137 
138     for(int j = 0; j < count; j += 100)
139     {
140         for(int i = 0; i < 50; ++i)
141         {
142             log_info("child #%i log line %i that will require a growth of the originally allocated 48 bytes buffer (thread)", f, j + i);
143 #if MICROPAUSE > 0
144             usleep(MICROPAUSE);
145 #endif
146         }
147 
148         for(int i = 50; i < 100; ++i)
149         {
150             log_info("child #%i log line %i '%s' (thread)", f, j + i, &one_kb_string[(j + i) & 1023]);
151 #if MICROPAUSE > 0
152             usleep(MICROPAUSE);
153 #endif
154         }
155 
156 #if 0
157         if(j < 250)
158         {
159             logger_flush();
160         }
161 
162         if(j < 500)
163         {
164             usleep(10000);
165         }
166 #endif
167     }
168 
169 #undef MODULE_MSG_HANDLE
170 
171     logger_handle_clear_thread_tag();
172 
173     return NULL;
174 }
175 
176 static void
main_exit()177 main_exit()
178 {
179     logger_handle_msg(g_system_logger, MSG_INFO, "main_exit: terminating this process");
180     logger_flush();
181     flushout();
182     flusherr();
183 }
184 
185 int
main(int argc,char * argv[])186 main(int argc, char *argv[])
187 {
188     /* initializes the core library */
189 
190     int count = 0;
191     if(argc >= 2)
192     {
193         count = atoi(argv[1]);
194     }
195 
196     if(count <= 1)
197     {
198         count = 1000;
199     }
200 
201     dnscore_init_ex(DNSCORE_ALL, argc, argv);
202 
203     atexit(main_exit);
204 
205 #if MMAP_TEST
206     int *please_dont_be_shared_ptr;
207     please_dont_be_shared_ptr = (int*)mmap(NULL, 4096, PROT_READ | PROT_WRITE, MAP_ANONYMOUS | MAP_PRIVATE, -1, 0);
208     *please_dont_be_shared_ptr = 0;
209 #endif
210 
211     logger_init_ex(0x100000, HEAP_SIZE);
212     logger_start();
213 
214     {
215         output_stream stdout_os;
216         logger_channel *stdout_channel;
217 
218         static const char * const log_file_name = "/tmp/daemonised-logger-test.log";
219         unlink(log_file_name);
220 
221         ya_result ret;
222         //fd_output_stream_attach(&stdout_os, dup_ex(1));
223         if(FAIL(ret = file_output_stream_create(&stdout_os, log_file_name, 0644)))
224         {
225             formatln("failed to create %s: %r", log_file_name, ret);
226             exit(1);
227         }
228         buffer_output_stream_init(&stdout_os, &stdout_os, 65536);
229         stdout_channel = logger_channel_alloc();
230         logger_channel_stream_open(&stdout_os, FALSE, stdout_channel);
231         logger_channel_register("stdout", stdout_channel);
232 
233         logger_handle_create("system", &g_system_logger);
234         logger_handle_create("parent", &g_parent_logger);
235         logger_handle_create("child", &g_child_logger);
236 
237         logger_handle_add_channel("system", MSG_ALL_MASK, "stdout");
238         logger_handle_add_channel("parent", MSG_ALL_MASK, "stdout");
239         logger_handle_add_channel("child", MSG_ALL_MASK, "stdout");
240 
241         logger_flush();
242 
243         sleep(1);
244     }
245 
246     async_wait_s *aw = async_wait_create_shared(0, 1);
247 
248     logger_handle_msg(g_system_logger, MSG_INFO, "system: before daemonise");
249     logger_handle_msg(g_parent_logger, MSG_INFO, "parent: before daemonise");
250     logger_handle_msg(g_child_logger, MSG_INFO, "child: before daemonise");
251 
252     server_setup_daemon_go();
253 
254     logger_handle_msg(g_system_logger, MSG_INFO, "system: after daemonise");
255     logger_handle_msg(g_parent_logger, MSG_INFO, "parent: after daemonise");
256     logger_handle_msg(g_child_logger, MSG_INFO, "child: after daemonise");
257 
258     logger_flush();
259 
260     // the socket server is spawned before the damonise: let's see if it still works
261 
262     struct addrinfo *addr;
263 
264     if(FAIL(getaddrinfo("127.0.0.1", "8080", NULL, &addr)))
265     {
266         logger_handle_msg(g_parent_logger, MSG_INFO, "getaddrinfo failed with: %r", ERRNO_ERROR);
267         return EXIT_FAILURE;
268     }
269 
270     static int on = 1;
271     socket_server_opensocket_s socket;
272     ya_result ret;
273 
274     if(FAIL(ret = socket_server_opensocket_init(&socket, addr, SOCK_STREAM)))
275     {
276         logger_handle_msg(g_parent_logger, MSG_INFO, "socekt init failed with: %r", ret);
277         return EXIT_FAILURE;
278     }
279     socket_server_opensocket_setopt(&socket, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on));
280 #ifndef WIN32
281     socket_server_opensocket_setopt(&socket, SOL_SOCKET, SO_REUSEPORT, &on, sizeof(on));
282 #endif
283 
284     int sockfd = socket_server_opensocket_open(&socket);
285 
286     if(sockfd < 0)
287     {
288         logger_handle_msg(g_parent_logger, MSG_INFO, "socket_server_opensocket_open failed with: %r", sockfd);
289         return EXIT_FAILURE;
290     }
291 
292 #if CHILDREN
293     u8 child_heap_id[CHILDREN];
294     pid_t pid[CHILDREN];
295 
296     for(int f = 0; f < CHILDREN; ++f)
297     {
298         int id = shared_heap_create(HEAP_SIZE);
299         if(id < 0)
300         {
301             formatln("failed to allocate heap #%i", f);
302             exit(1);
303         }
304         child_heap_id[f] = (u8)id;
305     }
306 
307     for(int f = 0; f < CHILDREN; ++f)
308     {
309         pid[f] = fork_ex();
310 
311         if(pid[f] < 0)
312         {
313             formatln("failed to spawn child #%i", f);
314             exit(2);
315         }
316 
317         if(pid[f] == 0)
318         {
319 #if DNSCORE_HAS_LOG_THREAD_TAG
320             static char childid_thread_tag[9] = "childid";
321             logger_handle_set_thread_tag(childid_thread_tag);
322 #endif
323             logger_set_shared_heap(child_heap_id[f]);
324 
325     #if MMAP_TEST
326             for(int j = 0; j < 1000; j += 100)
327             {
328                 for(int i = 0; i < 100; ++i)
329                 {
330                     please_dont_be_shared_ptr[1] = j + i;
331                     formatln("[CHILD] *please_dont_be_shared_ptr = %i,%i", please_dont_be_shared_ptr[0], please_dont_be_shared_ptr[1]);
332                 }
333                 flushout();
334             }
335     #endif
336 
337             struct thread_ctx ctx;
338             ctx.aw = aw;
339             ctx.logger = g_child_logger;
340             ctx.f =f;
341             ctx.count = count;
342 
343             thread_t tid  = 0;
344             if(thread_create(&tid, logging_stuff_thread, &ctx) != 0)
345             {
346             }
347 
348             async_wait(aw);
349 
350     #if !HAS_SHARED_QUEUE_SUPPORT
351             logger_init_ex(16384);
352             logger_start_client();
353     #endif
354 
355     #define MODULE_MSG_HANDLE g_child_logger
356             //formatln("client logger @ %p = %p", g_child_logger, MODULE_MSG_HANDLE);
357             //flushout();
358 
359             for(int j = 0; j < count; j += 100)
360             {
361                 for(int i = 0; i < 50; ++i)
362                 {
363                     log_info("child #%i log line %i that will require a growth of the originally allocated 48 bytes buffer", f, j + i);
364     #if MICROPAUSE > 0
365                     usleep(MICROPAUSE);
366     #endif
367                 }
368 
369                 for(int i = 50; i < 100; ++i)
370                 {
371                     log_info("child #%i log line %i", f, j + i);
372     #if MICROPAUSE > 0
373                     usleep(MICROPAUSE);
374     #endif
375                 }
376 
377     #if 0
378                 if(j < 250)
379                 {
380                     logger_flush();
381                 }
382 
383                 if(j < 500)
384                 {
385                     usleep(10000);
386                 }
387     #endif
388             }
389 
390             log_info("child #%i done", f);
391 
392     #undef MODULE_MSG_HANDLE
393 
394             if(tid != 0)
395             {
396                 thread_join(tid, NULL);
397             }
398 
399             //logger_stop_client();
400             exit(0);
401         }
402     }
403 
404 #endif
405 
406     {
407 #if MMAP_TEST
408         for(int j = 0; j < 1000; j += 100)
409         {
410             for(int i = 0; i < 100; ++i)
411             {
412                 please_dont_be_shared_ptr[0] = j + i;
413                 formatln("[PARNT] *please_dont_be_shared_ptr = %i,%i", please_dont_be_shared_ptr[0], please_dont_be_shared_ptr[1]);
414             }
415             flushout();
416         }
417 #endif
418 #if !HAS_SHARED_QUEUE_SUPPORT
419         logger_start_server();
420 #endif
421 
422 #define MODULE_MSG_HANDLE g_parent_logger
423 
424         //formatln("parent logger @ %p = %p", g_parent_logger, MODULE_MSG_HANDLE);
425         //flushout();
426 
427         struct thread_ctx ctx;
428         ctx.aw = aw;
429         ctx.logger = g_parent_logger;
430         ctx.f = -1;
431         ctx.count = count;
432 
433         thread_t tid  = 0;
434         if(thread_create(&tid, logging_stuff_thread, &ctx) != 0)
435         {
436         }
437 
438         sleep(1);
439 
440         async_wait_progress(aw, 1);
441 
442         for(int j = 0; j < count; j += 100)
443         {
444             for(int i = 0; i < 50; ++i)
445             {
446                 log_info("parent log line %i", j + i);
447 #if MICROPAUSE > 0
448                 usleep(MICROPAUSE);
449 #endif
450             }
451 
452             for(int i = 50; i < 100; ++i)
453             {
454                 log_info("parent log line %i that will require a growth of the originally allocated 48 bytes buffer", j + i);
455 #if MICROPAUSE > 0
456                 usleep(MICROPAUSE);
457 #endif
458             }
459 
460 #if 0
461             if(j < 250)
462             {
463                 logger_flush();
464             }
465 
466             if(j < 500)
467             {
468                 usleep(10000);
469             }
470 #endif
471         }
472 
473 #if CHILDREN
474         log_info("waiting for child");
475 
476         for(int f = 0; f < CHILDREN; ++f)
477         {
478             waitpid_ex(pid[f], NULL, 0);
479         }
480 #endif
481 
482         if(tid != 0)
483         {
484             thread_join(tid, NULL);
485         }
486 
487         log_info("done");
488 
489 #undef MODULE_MSG_HANDLE
490 
491 #if !HAS_SHARED_QUEUE_SUPPORT
492         logger_stop_server();
493 #endif
494         logger_stop();
495     }
496 
497     async_wait_destroy_shared(aw);
498 
499     {
500         size_t total, count;
501         formatln("[0] testing block");
502         flushout();
503         shared_heap_count_allocated(0, &total, &count);
504         formatln("[0] after use: %llu allocated blocs using %llu bytes", count, total);
505         flushout();
506 
507 
508 #if CHILDREN
509         for(int f = 0; f < CHILDREN; ++f)
510         {
511             formatln("[%i] testing block", child_heap_id[f]);
512             flushout();
513             shared_heap_count_allocated(child_heap_id[f], &total, &count);
514             formatln("[%i] after use: %llu allocated blocs using %llu bytes", child_heap_id[f], count, total);
515             flushout();
516         }
517 #endif
518     }
519 
520     flushout();
521     flusherr();
522     fflush(NULL);
523 
524     dnscore_finalize();
525 
526     return EXIT_SUCCESS;
527 }
528