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 skeleton file
38  *
39  * skeleton test program, will not be installed with a "make install"
40  *
41  * To create a new test based on the skeleton:
42  *
43  * _ copy the folder
44  * _ replace "skeleton" by the name of the test
45  * _ add the test to the top level Makefile.am and configure.ac
46  *
47  */
48 
49 #include <dnscore/dnscore.h>
50 #include <dnscore/random.h>
51 #include <dnscore/message.h>
52 #include <dnscore/config_settings.h>
53 #include <dnscore/host_address.h>
54 #include <dnscore/format.h>
55 #include <dnscore/thread_pool.h>
56 #include <dnscore/buffer_output_stream.h>
57 #include <dnscore/logger_channel_stream.h>
58 #include <dnscore/file_output_stream.h>
59 
60 #define HEAP_SIZE 0x40000000
61 
62 static logger_handle *notify_log = LOGGER_HANDLE_SINK;
63 
64 #define MODULE_MSG_HANDLE notify_log
65 
help()66 static void help()
67 {
68     println("parameters: server-ip zone [count [loops]]");
69     flushout();
70 }
71 
72 struct notify_send_args_s
73 {
74     host_address *ip;
75     int count;
76     int loops;
77     u8 zone[256];
78 };
79 
notify_send(void * args_)80 static void *notify_send(void* args_)
81 {
82     struct notify_send_args_s *args = (struct notify_send_args_s*)args_;
83 
84     ya_result ret;
85     random_ctx rndctx = random_init_auto();
86     message_data* mesg = message_new_instance();
87 
88     s64 last = timeus();
89 
90     s64 total_time = 0;
91     s64 max_time = 0;
92     s64 min_time = MAX_S64;
93     s64 faults = 0;
94     s64 delta;
95 
96     for(int i = 0; i < args->loops; ++i)
97     {
98         u16 id = (u16)random_next(rndctx);
99         message_make_notify(mesg, id, args->zone, TYPE_SOA, CLASS_IN);
100 
101         s64 now = timeus();
102 
103         if(now - last > ONE_SECOND_US)
104         {
105             s64 next = last + ONE_SECOND_US;
106             last = next;
107             while(next < now)
108             {
109                 last = next;
110                 next += ONE_SECOND_US;
111             }
112 
113             double mean_reply_time = total_time;
114             mean_reply_time /= (i + 1);
115             mean_reply_time /= ONE_SECOND_US_F;
116 
117             double max_reply_time = max_time;
118             max_reply_time /= ONE_SECOND_US_F;
119             double min_reply_time = min_time;
120             min_reply_time /= ONE_SECOND_US_F;
121 
122             log_info("notify %{dnsname} to %{hostaddr} %i/%i, %lli faults, mean reply time = %3.6fs [%3.6fs; %3.6fs]", args->zone, args->ip, i, args->loops, faults, mean_reply_time, min_reply_time, max_reply_time);
123         }
124 
125         if(ISOK(ret = message_query_udp_with_timeout(mesg, args->ip, 600, 0)))
126         {
127             s64 reply = timeus();
128             delta = reply - now;
129 
130             // message_print_format_dig(termout, message_get_buffer_const(mesg), message_get_size(mesg), 15, 0);
131         }
132         else
133         {
134             s64 reply = timeus();
135             delta = reply - now;
136             ++faults;
137 
138             log_err("%{dnsname}  network failed with: %r", args->zone, ret);
139             --i;
140         }
141 
142         total_time += delta;
143         max_time = MAX(delta, max_time);
144         min_time = MIN(delta, min_time);
145 
146         // message_reset_control(mesg);
147     }
148 
149     message_free(mesg);
150 
151     return NULL;
152 }
153 
154 int
main(int argc,char * argv[])155 main(int argc, char *argv[])
156 {
157     ya_result ret;
158 
159     struct notify_send_args_s args;
160 
161     args.ip = NULL;
162     args.zone[0] = '\0';
163     args.count = 1;
164 
165     /* initializes the core library */
166     dnscore_init();
167 
168     if(argc < 3)
169     {
170         help();
171         return EXIT_FAILURE;
172     }
173 
174     static const anytype defaults = {._8u8={CONFIG_HOST_LIST_FLAGS_DEFAULT,128,0,0,0,0,0,0}};
175 
176     if(FAIL(ret = config_set_host_list(argv[1], &args.ip, defaults)))
177     {
178         formatln("%s is an invalid ip: %r", argv[1], ret);
179         help();
180         return EXIT_FAILURE;
181     }
182 
183     if(args.ip->port == 0)
184     {
185         args.ip->port = NU16(53);
186     }
187 
188     if(FAIL(ret = cstr_to_dnsname_with_check(args.zone, argv[2])))
189     {
190         formatln("%s is an invalid zone: %r", argv[2], ret);
191         help();
192         return EXIT_FAILURE;
193     }
194 
195     if(argc >= 4)
196     {
197         args.count = atoi(argv[3]);
198         if(args.count < 0)
199         {
200             args.count = 1;
201         }
202         if(args.count > 255)
203         {
204             args.count = 255;
205         }
206     }
207 
208     if(argc >= 5)
209     {
210         args.loops = atoi(argv[4]);
211         if(args.loops < 0)
212         {
213             args.loops = 1;
214         }
215     }
216 
217     logger_init_ex(0x100000, HEAP_SIZE);
218     logger_start();
219 
220     {
221         output_stream stdout_os;
222         logger_channel *stdout_channel;
223         static const char * const log_file_name = "/tmp/notify-test.log";
224 
225         unlink(log_file_name);
226 
227         fd_output_stream_attach(&stdout_os, dup_ex(1));
228         /*
229         ya_result ret;
230         if(FAIL(ret = file_output_stream_create(&stdout_os, log_file_name, 0644)))
231         {
232             formatln("failed to create %s: %r", log_file_name, ret);
233             exit(1);
234         }
235         */
236         buffer_output_stream_init(&stdout_os, &stdout_os, 65536);
237         stdout_channel = logger_channel_alloc();
238         logger_channel_stream_open(&stdout_os, FALSE, stdout_channel);
239         logger_channel_register("stdout", stdout_channel);
240         logger_handle_create("notify", &notify_log);
241 
242         logger_handle_add_channel("notify", MSG_ALL_MASK, "stdout");
243 
244         logger_flush();
245 
246         sleep(1);
247     }
248 
249 
250     message_edns0_setmaxsize(4096);
251 
252     struct thread_pool_s *tp = thread_pool_init_ex(args.count, args.count * 2, "notify");
253 
254     // thread_pool_wait_all_running(tp);
255 
256     if(tp != NULL)
257     {
258         for(int i = 0; i < args.count; ++i)
259         {
260             log_info("starting notify_send %i", i);
261             thread_pool_enqueue_call(tp, notify_send, &args, NULL, "notify");
262         }
263     }
264 
265     thread_pool_destroy(tp);
266     tp = NULL;
267 
268     flushout();
269     flusherr();
270     fflush(NULL);
271 
272     dnscore_finalize();
273 
274     return EXIT_SUCCESS;
275 }
276