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"
40 #include "hsmkey/hsm_key_factory.h"
41 
42 #include "daemon/time_leap_cmd.h"
43 
44 #define MAX_ARGS 5
45 
46 static const char *module_str = "time_leap_cmd";
47 
48 static void
49 usage(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 
58 static void
59 help(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 
74 static int
75 run(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 
209 struct 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)
db_connection_t * get_database_connection(engine_type *engine)
Definition: engine.c:226
void engine_wakeup_workers(engine_type *engine)
Definition: engine.c:218
schedule_type * taskq
Definition: engine.h:60
#define MAX_ARGS
Definition: time_leap_cmd.c:44
struct cmd_func_block time_leap_funcblock