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