1 /**
2 * Copyright 2010 Christian Liesch
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 /**
18 * @file
19 *
20 * @Author christian liesch <liesch@gmx.ch>
21 *
22 * Implementation of the HTTP Test Tool date module
23 */
24
25 /************************************************************************
26 * Includes
27 ***********************************************************************/
28 #include "module.h"
29 #include "worker.h"
30
31 /************************************************************************
32 * Definitions
33 ***********************************************************************/
34 const char * date_module = "date_module";
35 apr_time_t start_time;
36
37 typedef struct date_wconf_s {
38 apr_time_t start_time;
39 } date_wconf_t;
40
41 /************************************************************************
42 * Commands
43 ***********************************************************************/
44
45 /**
46 * Get lua config from worker
47 *
48 * @param worker IN worker
49 * @return lua config
50 */
date_get_worker_config(worker_t * worker)51 static date_wconf_t *date_get_worker_config(worker_t *worker) {
52 date_wconf_t *config = module_get_config(worker->config, date_module);
53 if (config == NULL) {
54 config = apr_pcalloc(worker->pbody, sizeof(*config));
55 config->start_time = start_time;
56 module_set_config(worker->config, apr_pstrdup(worker->pbody, date_module), config);
57 }
58 return config;
59 }
60
61 /**
62 * TIME command stores time in a variable [ms]
63 *
64 * @param self IN command
65 * @param worker IN thread data object
66 * @param data IN variable name
67 *
68 * @return APR_SUCCESS
69 */
block_DATE_GET_TIME(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)70 apr_status_t block_DATE_GET_TIME(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
71 const char *var = store_get(worker->params, "1");
72
73 if (!var) {
74 worker_log(worker, LOG_ERR, "Need a variable name to store time");
75 }
76
77 worker_var_set(parent, var, apr_off_t_toa(worker->pbody, apr_time_as_msec(apr_time_now())));
78
79 return APR_SUCCESS;
80 }
81
82 /**
83 * STRFTIME command
84 *
85 * @param self IN command
86 * @param worker IN thread data object
87 * @param data IN time [ms] "format" variable
88 *
89 * @return APR_SUCCESS or APR_EGENERAL on wrong parameters
90 */
block_DATE_FORMAT(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)91 apr_status_t block_DATE_FORMAT(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
92 apr_status_t status;
93 const char *time;
94 const char *fmt;
95 const char *var;
96 const char *type;
97 char *timefmt;
98 apr_size_t len;
99 apr_time_exp_t tm;
100 apr_time_t timems;
101
102 time = store_get(worker->params, "1");
103 fmt = store_get(worker->params, "2");
104 var = store_get(worker->params, "3");
105 type = store_get(worker->params, "4");
106
107 if (!time) {
108 worker_log(worker, LOG_ERR, "Time not specified");
109 return APR_EGENERAL;
110 }
111 if (!fmt) {
112 worker_log(worker, LOG_ERR, "Format not specified");
113 return APR_EGENERAL;
114 }
115 if (!var) {
116 worker_log(worker, LOG_ERR, "Variable not specified");
117 return APR_EGENERAL;
118 }
119
120 timems = apr_atoi64(time);
121
122 timefmt = apr_pcalloc(worker->pbody, 255);
123
124 if (type && strncasecmp(type, "Local", 5) == 0) {
125 if ((status = apr_time_exp_lt(&tm, timems * 1000)) != APR_SUCCESS) {
126 return status;
127 }
128 }
129 else {
130 if ((status = apr_time_exp_gmt(&tm, timems * 1000)) != APR_SUCCESS) {
131 return status;
132 }
133 }
134
135 if ((status = apr_strftime(timefmt, &len, 254, fmt, &tm)) != APR_SUCCESS) {
136 return status;
137 }
138
139 worker_var_set_and_zero_terminate(parent, var, timefmt, len);
140
141 return APR_SUCCESS;
142 }
143
144 /**
145 * SYNC command
146 *
147 * @param worker IN callee
148 * @param parent IN caller
149 * @param ptmp IN temporary pool
150 *
151 * @return APR_SUCCESS
152 */
block_DATE_SYNC(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)153 apr_status_t block_DATE_SYNC(worker_t *worker, worker_t *parent, apr_pool_t *ptmp) {
154 apr_time_t seconds;
155 apr_time_t next_full;
156
157 const char *first = store_get(worker->params, "1");
158 apr_time_t now = apr_time_now();
159
160 if (!first || strcmp(first, "second") == 0) {
161 seconds = apr_time_sec(now) + 1;
162 next_full = apr_time_from_sec(seconds);
163 }
164 else /* if (first && strcmp(first, "minute") == 0) */ {
165 seconds = apr_time_sec(now) + (60 - (apr_time_sec(now) % 60));
166 next_full = apr_time_from_sec(seconds);
167 }
168
169 apr_sleep(next_full - now);
170
171 return APR_SUCCESS;
172 }
173
174 /**
175 * TIMER command
176 * @param worker IN callee
177 * @param parent IN caller
178 * @param ptmp IN temporary pool
179 * @return APR_SUCCESS
180 */
block_DATE_TIMER(worker_t * worker,worker_t * parent,apr_pool_t * ptmp)181 apr_status_t block_DATE_TIMER(worker_t *worker, worker_t *parent,
182 apr_pool_t *ptmp) {
183
184 const char *cmd;
185 const char *var;
186 date_wconf_t *wconf = date_get_worker_config(worker);
187
188 apr_time_t cur = apr_time_now();
189
190 cmd = store_get(worker->params, "1");
191 var = store_get(worker->params, "2");
192
193 if (strcasecmp(cmd, "GET") == 0) {
194 if (var && var[0] != 0) {
195 worker_var_set(worker, var,
196 apr_off_t_toa(ptmp,
197 apr_time_as_msec(cur - wconf->start_time)));
198 }
199 }
200 else if (strcasecmp(cmd, "RESET") == 0) {
201 wconf->start_time = apr_time_now();
202 }
203 else {
204 worker_log(worker, LOG_ERR, "Timer command %s not implemented", cmd);
205 }
206 return APR_SUCCESS;
207 }
208
209 /************************************************************************
210 * Module
211 ***********************************************************************/
date_module_init(global_t * global)212 apr_status_t date_module_init(global_t *global) {
213 apr_status_t status;
214 start_time = apr_time_now();
215 if ((status = module_command_new(global, "DATE", "_GET_TIME",
216 "<var>",
217 "Stores the current time [ms] into <var>",
218 block_DATE_GET_TIME)) != APR_SUCCESS) {
219 return status;
220 }
221 if ((status = module_command_new(global, "DATE", "_FORMAT",
222 "<time> <format> <variable> [Local|GMT]",
223 "Do format <time> with <format> and stores it in <variable>. "
224 "Local is default.",
225 block_DATE_FORMAT)) != APR_SUCCESS) {
226 return status;
227 }
228 if ((status = module_command_new(global, "DATE", "_SYNC",
229 "[second|minute]",
230 "Default wait the next full second. "
231 "Optional wait the next full minute.",
232 block_DATE_SYNC)) != APR_SUCCESS) {
233 return status;
234 }
235
236 if ((status = module_command_new(global, "DATE", "_TIMER",
237 "GET|RESET [<variable>]",
238 "Stores time duration from last reset or from start of test.",
239 block_DATE_TIMER)) != APR_SUCCESS) {
240 return status;
241 }
242
243
244 return APR_SUCCESS;
245 }
246
247