OpenDNSSEC-enforcer 2.1.12
time_leap_cmd.c
Go to the documentation of this file.
1/*
2 * Copyright (c) 2014 NLNet Labs
3 * Copyright (c) 2014 OpenDNSSEC AB (svb)
4 * All rights reserved.
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 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
17 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
19 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE
21 * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER
23 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
24 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
25 * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 *
27 */
28
29#include "config.h"
30#include <getopt.h>
31
32#include "file.h"
33#include "duration.h"
34#include "log.h"
35#include "str.h"
36#include "cmdhandler.h"
38#include "daemon/engine.h"
39#include "clientpipe.h"
41
43
44#define MAX_ARGS 5
45
46static const char *module_str = "time_leap_cmd";
47
48static void
49usage(int sockfd)
50{
51 client_printf(sockfd,
52 "time leap\n"
53 " --time <time> aka -t \n"
54 " --attach aka -a\n"
55 );
56}
57
58static void
59help(int sockfd)
60{
61 client_printf(sockfd,
62 "*WARNING* time leap is a debugging/testing tool, it should NEVER be used\n"
63 "in production! Without arguments the daemon inspects the first task in the\n"
64 "schedule and sets its internal time to the time of the task. This allows for\n"
65 "a quick replay of a test scenario. With the --time or -t switch the daemon\n"
66 "sets its time to the argument given as: \"YYYY-MM-DD-HH:MM:SS\"."
67 "\n"
68 "\nOptions:\n"
69 "time leap to this exact time\n"
70 "attach Perform 1 task and stay attached, use only when workerthreads=0\n\n"
71 );
72}
73
74static int
75run(int sockfd, cmdhandler_ctx_type* context, const char *cmd)
76{
77 db_connection_t* dbconn;
78 struct tm strtime_struct;
79 char strtime[64]; /* at least 26 according to docs plus a long integer */
80 char buf[ODS_SE_MAXLINE];
81 time_t now = time_now();
82 const char *time = NULL;
83 time_t time_leap = 0;
84 struct tm tm;
85 const int NARGV = MAX_ARGS;
86 const char *argv[MAX_ARGS];
87 int taskcount;
88 int argc = 0, attach = 0;
89 int long_index = 0, opt = 0;
90 int processed_enforce;
91 task_type* task = NULL;
92 engine_type* engine = getglobalcontext(context);
93
94 static struct option long_options[] = {
95 {"time", required_argument, 0, 't'},
96 {"attach", no_argument, 0, 'a'},
97 {0, 0, 0, 0}
98 };
99
100 ods_log_debug("[%s] %s command", module_str, time_leap_funcblock.cmdname);
101
102 strncpy(buf, cmd, sizeof(buf));
103 buf[sizeof(buf)-1] = '\0';
104
105 argc = ods_str_explode(buf, NARGV, argv);
106 if (argc == -1) {
107 ods_log_error_and_printf(sockfd, module_str, "too many arguments");
108 return -1;
109 }
110
111 optind = 0;
112 while ((opt = getopt_long(argc, (char* const*)argv, "t:a", long_options, &long_index)) != -1) {
113 switch (opt) {
114 case 't':
115 time = optarg;
116 break;
117 case 'a':
118 attach = 1;
119 break;
120 default:
121 client_printf_err(sockfd, "unknown arguments\n");
122 ods_log_error("[%s] unknown arguments for %s command",
123 module_str, time_leap_funcblock.cmdname);
124 return -1;
125 }
126 }
127
128 if (time) {
129 if (strptime(time, "%Y-%m-%d-%H:%M:%S", &tm)) {
130 tm.tm_isdst = -1;
131 time_leap = mktime(&tm);
132 client_printf(sockfd,
133 "Using %s parameter value as time to leap to\n", time);
134 } else {
135 client_printf_err(sockfd,
136 "Time leap: Error - could not convert '%s' to a time. "
137 "Format is YYYY-MM-DD-HH:MM:SS \n", time);
138 return -1;
139 }
140 }
141
142 ods_log_assert(engine);
143 if (!engine->taskq || !engine->taskq->tasks) {
144 client_printf(sockfd, "There are no tasks scheduled.\n");
145 return 1;
146 }
147
148 schedule_info(engine->taskq, &time_leap, NULL, &taskcount);
149 now = time_now();
150 strftime(strtime, sizeof(strtime), "%c", localtime_r(&now, &strtime_struct));
151 client_printf(sockfd,
152 "There are %i tasks scheduled.\nIt is now %s (%ld seconds since epoch)\n",
153 taskcount, strtime, (long)now);
154
155 if (!time) schedule_info(engine->taskq, &time_leap, NULL, NULL);
156 if (time_leap == -1) {
157 client_printf(sockfd, "No tasks in queue. Not able to leap.\n");
158 return 0;
159 }
160
161 if (!attach) {
162 set_time_now(time_leap);
163 strftime(strtime, sizeof(strtime), "%c", localtime_r(&time_leap, &strtime_struct));
164 client_printf(sockfd, "Leaping to time %s (%ld seconds since epoch)\n",
165 (strtime[0]?strtime:"(null)"), (long)time_leap);
166 ods_log_info("Time leap: Leaping to time %s\n", strtime);
167 /* Wake up all workers and let them reevaluate wether their
168 tasks need to be executed */
169 client_printf(sockfd, "Waking up workers\n");
170 engine_wakeup_workers(engine);
171 return 0;
172 }
173
174 if (!(dbconn = get_database_connection(engine))) {
175 client_printf_err(sockfd, "Failed to open DB connection.\n");
176 client_exit(sockfd, 1);
177 return -1;
178 }
179 /* Keep looping until an enforce task is found, then loop but don't advance time */
180 processed_enforce = 0;
181 while (1) {
182 /*if time is set never advance time but only consume all task <= time*/
183 if (!time) {
184 schedule_info(engine->taskq, &time_leap, NULL, NULL);
185 if (processed_enforce && time_leap > time_now()) break;
186 }
187 if (time_leap == -1) {
188 client_printf(sockfd, "No tasks in queue. Not able to leap.\n");
189 break;
190 }
191
192 set_time_now(time_leap);
193 strftime(strtime, sizeof(strtime), "%c", localtime_r(&time_leap, &strtime_struct));
194 client_printf(sockfd, "Leaping to time %s (%ld seconds since epoch)\n",
195 (strtime[0]?strtime:"(null)"), (long)time_leap);
196 ods_log_info("Time leap: Leaping to time %s\n", strtime);
197 if (!(task = schedule_pop_first_task(engine->taskq)))
198 break;
199 if (schedule_task_istype(task, TASK_TYPE_ENFORCE))
200 processed_enforce = 1;
201 task_perform(engine->taskq, task, dbconn);
202 ods_log_debug("[timeleap] finished working");
203 }
204 db_connection_free(dbconn);
205 return 0;
206}
207
208
209struct cmd_func_block time_leap_funcblock = {
210 "time leap", &usage, &help, NULL, &run
211};
#define NARGV
void db_connection_free(db_connection_t *connection)
Definition: db_connection.c:45
engine_type * getglobalcontext(cmdhandler_ctx_type *context)
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:218
db_connection_t * get_database_connection(engine_type *engine)
Definition: engine.c:226
schedule_type * taskq
Definition: engine.h:60
#define MAX_ARGS
Definition: time_leap_cmd.c:44
struct cmd_func_block time_leap_funcblock