1 /* $Id: proto_push_read_storage.c 20800 2012-01-19 05:13:45Z m-oki $ */
2
3 /*
4 * Copyright (c) 2012, Internet Initiative Japan, Inc.
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
19 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
20 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
21 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
22 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
23 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
24 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
25 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
26 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
27 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30 #include "config.h"
31
32 #include <stdio.h>
33 #include <stdlib.h>
34 #include <inttypes.h>
35 #include <string.h>
36 #include <sys/time.h>
37 #include <sys/types.h>
38 #include <unistd.h>
39
40 #include <libarms.h>
41 #include <libarms_resource.h>
42 #include <axp_extern.h>
43
44 #include <libarms_log.h>
45 #include <arms_xml_tag.h>
46 #include <module_db_mi.h>
47 #include <libarms/base64.h>
48 #include <libarms/malloc.h>
49 #include <transaction/transaction.h>
50 #include <protocol/arms_methods.h>
51
52 #include "compat.h"
53
54 /*
55 * Callback Functions
56 */
57 /* context alloc */
58 static void *read_storage_context(tr_ctx_t *tr_ctx);
59 /* copy argument */
60 static int
61 read_storage_cparg(AXP *axp, uint32_t pm_type, int tag, const char *buf, size_t len, tr_ctx_t *tr_ctx);
62 /* done */
63 static int
64 read_storage_done(transaction *, char *buf, int, int *);
65 /* context free */
66 static void read_storage_release(tr_ctx_t *tr_ctx);
67
68 /*
69 * XML Schema: read-storage-start-request
70 */
71 static struct axp_schema arms_push_readstorage_req[] = {
72 {ARMS_TAG_STORAGE, "storage", AXP_TYPE_TEXT,
73 NULL, push_default_hook, NULL},
74 {0, NULL, 0, NULL, NULL, NULL}
75 };
76 struct axp_schema read_storage_start_req = {
77 ARMS_TAG_READSTORAGE_SREQ, "read-storage-start-request", AXP_TYPE_CHILD,
78 NULL, push_default_hook, arms_push_readstorage_req
79 };
80
81 /*
82 * Method definition
83 */
84 arms_method_t read_storage_methods = {
85 ARMS_TR_READ_STORAGE, /* pm_type */
86 "read-storage", /* pm_string */
87 &read_storage_start_req,/* schema */
88 0, /* pm_flags */
89 build_generic_res, /* pm_response */
90 read_storage_done, /* pm_done */
91 NULL, /* pm_exec */
92 read_storage_cparg, /* pm_copyarg */
93 NULL, /* pm_rollback */
94 read_storage_context, /* pm_context */
95 read_storage_release, /* pm_release */
96 };
97
98 /*
99 * Method implementations
100 */
101
102 #define BEGIN 1
103 #define FIRST_RESULT 2
104 #define NEXT_RESULT 3
105 #define DONE_RESULT 4
106 #define DONE 5
107
108 struct read_storage_args {
109 int props_id; /* storage type: running, candidata, or backup */
110 int mod_index;
111 int mod_max;
112 uint32_t mod_id;
113 int next;
114 int state;
115 int resultlen;
116 char result[1024];
117 char term; /* trailing NUL */
118 };
119
120 /*
121 * Context Alloc
122 */
123 static void *
read_storage_context(tr_ctx_t * tr_ctx)124 read_storage_context(tr_ctx_t *tr_ctx)
125 {
126 struct read_storage_args *arg;
127 arms_context_t *res = arms_get_context();
128
129 if (res->callbacks.read_config_cb == NULL) {
130 tr_ctx->result = 505;
131 return 0;
132 }
133
134 arg = CALLOC(1, sizeof(*arg));
135 if (arg != NULL) {
136 arg->state = BEGIN;
137 } else {
138 tr_ctx->result = 413; /*Resource Exhausted*/
139 }
140
141 return arg;
142 }
143
144 /*
145 * Context Free
146 */
147 static void
read_storage_release(tr_ctx_t * tr_ctx)148 read_storage_release(tr_ctx_t *tr_ctx)
149 {
150 struct read_storage_args *arg;
151
152 arg = tr_ctx->arg;
153 if (arg) {
154 FREE(tr_ctx->arg);
155 }
156 }
157
158 /*
159 * Copy argument
160 */
161 static int
parse_propsid(const char * buf,size_t len)162 parse_propsid(const char *buf, size_t len)
163 {
164 if (buf == NULL)
165 return -1;
166 if (len <= 0)
167 return -1;
168
169 #if 0 /* libarms doesn't support startup */
170 if (strncmp("startup", buf, len) == 0) {
171 return ARMS_CONFIG_STARTUP;
172 }
173 #endif
174 else if (strncmp("candidate", buf, len) == 0) {
175 return ARMS_CONFIG_CANDIDATE;
176 }
177 else if (strncmp("running", buf, len) == 0) {
178 return ARMS_CONFIG_RUNNING;
179 }
180 else if (strncmp("backup", buf, len) == 0) {
181 return ARMS_CONFIG_BACKUP;
182 }
183
184 return -1;
185 }
186
187 static int
read_storage_cparg(AXP * axp,uint32_t pm_type,int tag,const char * buf,size_t len,tr_ctx_t * tr_ctx)188 read_storage_cparg(AXP *axp, uint32_t pm_type, int tag,
189 const char *buf, size_t len, tr_ctx_t *tr_ctx)
190 {
191 struct read_storage_args *arg = tr_ctx->arg;
192
193 if (tag == ARMS_TAG_STORAGE) {
194 arg->props_id = parse_propsid(buf, len);
195 if (arg->props_id < 0) {
196 /* storage type is invalid. */
197 tr_ctx->result = 203;
198 }
199 } else {
200 /* other tag (error?) */
201 }
202 return 0;
203 }
204
205 /*
206 * read-storage-done
207 *
208 * like read-storage-done, but <md-config> tag has no result attribute.
209 * so fat, empty config means error. umm...
210 *
211 * SMF SDK 1.00 (and 1.10) cannot receive error result via any tag.
212 * - md-config has no result attribute.
213 * - transaction-result doesn't work between proxy and RS.
214 * workaround: done-req doesn't include md-config tag means error.
215 */
216 static int
read_storage_done(transaction * tr,char * buf,int len,int * wrote)217 read_storage_done(transaction *tr, char *buf, int len, int *wrote)
218 {
219 tr_ctx_t *tr_ctx = &tr->tr_ctx;
220 struct read_storage_args *arg = tr_ctx->arg;
221 arms_context_t *res = arms_get_context();
222 int size, err, rv;
223
224 switch (arg->state) {
225 case BEGIN:
226 libarms_log(ARMS_LOG_DEBUG,
227 "Generate read-storage-done");
228
229 arg->mod_max = arms_count_module();
230 size = arms_write_begin_message(tr, buf, len);
231 buf += size;
232 len -= size;
233 if (tr_ctx->result == 100)
234 arg->state = FIRST_RESULT;
235 else
236 arg->state = DONE;
237 *wrote = size;
238 return TR_WANT_WRITE;
239 case FIRST_RESULT:
240 /*
241 * mod_index++ if err or FINISHED.
242 */
243 rv = 0;
244 err = arms_get_module_id(&arg->mod_id, arg->mod_index);
245 if (err == 0) {
246 arg->next = ARMS_FRAG_FIRST;
247 arg->result[0] = '\0';
248 rv = res->callbacks.read_config_cb(
249 arg->mod_id,
250 arg->props_id,
251 arg->result, sizeof(arg->result),
252 &arg->next,
253 res->udata);
254 if (ARMS_RESULT_IS_BYTES(rv)) {
255 int blen;
256
257 /* binary */
258 size = snprintf(buf, len,
259 "<md-config id=\"%d\" "
260 "encoding=\"base64\">",
261 arg->mod_id);
262 buf += size;
263 len -= size;
264
265 arg->resultlen = ARMS_RV_DATA_MASK(rv);
266 blen = ROUND_BASE64_BINARY(arg->resultlen);
267 arg->resultlen -= blen;
268 size += arms_base64_encode(buf, len,
269 arg->result,
270 blen);
271 memcpy(arg->result,
272 arg->result + blen, arg->resultlen);
273 } else {
274 /* text or error */
275 size = snprintf(buf, len,
276 "<md-config id=\"%d\">%s",
277 arg->mod_id,
278 arms_escape(arg->result));
279 arg->resultlen = 0;
280 }
281 *wrote = size;
282 }
283 if ((arg->next & ARMS_FRAG_FINISHED) != 0 ||
284 ARMS_RESULT_IS_ERROR(rv))
285 arg->state = DONE_RESULT;
286 else
287 arg->state = NEXT_RESULT;
288 return TR_WANT_WRITE;
289 case NEXT_RESULT:
290 arg->next = ARMS_FRAG_CONTINUE;
291 rv = res->callbacks.read_config_cb(
292 arg->mod_id,
293 arg->props_id,
294 arg->result + arg->resultlen,
295 sizeof(arg->result) - arg->resultlen,
296 &arg->next,
297 res->udata);
298 if (ARMS_RESULT_IS_ERROR(rv)) {
299 *wrote = 0;
300 arg->state = DONE_RESULT;
301 return TR_WANT_WRITE;
302 }
303 if (ARMS_RESULT_IS_BYTES(rv)) {
304 int blen;
305
306 arg->resultlen += ARMS_RV_DATA_MASK(rv);
307 blen = ROUND_BASE64_BINARY(arg->resultlen);
308 arg->resultlen -= blen;
309 *wrote = arms_base64_encode(buf, len,
310 arg->result,
311 blen);
312 memcpy(arg->result,
313 arg->result + blen, arg->resultlen);
314 } else {
315 *wrote = strlcpy(buf, arms_escape(arg->result), len);
316 }
317 if ((arg->next & ARMS_FRAG_FINISHED) != 0)
318 arg->state = DONE_RESULT;
319 return TR_WANT_WRITE;
320 case DONE_RESULT:
321 if (arg->resultlen > 0) {
322 size = arms_base64_encode(buf, len,
323 arg->result, arg->resultlen);
324 buf += size;
325 len -= size;
326 } else {
327 size = 0;
328 }
329 size += snprintf(buf, len, "</md-config>");
330 *wrote = size;
331 arg->mod_index++;
332 if (arg->mod_index >= arg->mod_max)
333 arg->state = DONE;
334 else
335 arg->state = FIRST_RESULT;
336 return TR_WANT_WRITE;
337 case DONE:
338 *wrote = arms_write_end_message(tr, buf, len);
339 libarms_log(ARMS_LOG_DEBUG,
340 "Read Storage Execute done.");
341 return TR_WRITE_DONE;
342 default:
343 break;
344 }
345 return TR_FATAL_ERROR;
346 }
347