1 /*	$Id: proto_push_md_command.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 <libarms/base64.h>
47 #include <libarms/malloc.h>
48 #include <transaction/transaction.h>
49 #include <protocol/arms_methods.h>
50 #include <module_db_mi.h>
51 
52 #include "compat.h"
53 
54 /*
55  * Callback Functions
56  */
57 static void *md_command_context(tr_ctx_t *);
58 static int
59 md_command_cparg(AXP *, uint32_t, int, const char *, size_t, tr_ctx_t *);
60 static int md_command_response(transaction *, char *, int, int *);
61 static void md_command_release(tr_ctx_t *);
62 
63 
64 static char *arms_md_command_attr[] = {
65 	"id", NULL,
66 	"encoding", NULL,
67 	NULL
68 };
69 
70 /*
71  * XML Schema: md-command-request
72  */
73 static struct axp_schema arms_md_command_req_body[] = {
74 	{ARMS_TAG_MDCOMMAND, "md-command", AXP_TYPE_TEXT,
75 		arms_md_command_attr, push_default_hook, NULL},
76 	{0, NULL, 0, NULL, NULL, NULL}
77 };
78 static struct axp_schema md_command_request = {
79 	ARMS_TAG_MDCOMMAND_REQ, "md-command-request", AXP_TYPE_CHILD,
80 		NULL, push_default_hook, arms_md_command_req_body
81 };
82 
83 /*
84  * Method definition
85  */
86 arms_method_t md_command_methods = {
87 	ARMS_TR_MD_COMMAND,	/* pm_type */
88 	"md-command",		/* type string */
89 	&md_command_request,	/* schema */
90 	0,			/* pm_flags */
91 	md_command_response,	/* pm_response */
92 	NULL,			/* pm_done */
93 	NULL,			/* pm_exec */
94 	md_command_cparg,	/* pm_copyarg */
95 	NULL,			/* pm_rollback */
96 	md_command_context,	/* pm_context */
97 	md_command_release,	/* pm_release */
98 };
99 
100 /*
101  * Method implementations
102  */
103 
104 #define BEGIN        1
105 #define FIRST_RESULT 2
106 #define NEXT_RESULT  3
107 #define DONE         4
108 #define END          5
109 #define ERROR_RESULT 6
110 struct md_command_args {
111 	int mod_id;
112 	int mod_count;
113 	int already_running;
114 	int state;
115 	int req_len;
116 	int encoding;
117 	char request[8192];
118 	char result[1024 + 1];
119 	int resultlen;
120 	int next;
121 	arms_base64_stream_t base64;
122 };
123 
124 static int already_running = 0;
125 
126 
127 /*
128  * Context Alloc
129  */
130 static void *
md_command_context(tr_ctx_t * ctx)131 md_command_context(tr_ctx_t *ctx)
132 {
133 	struct md_command_args *arg;
134 
135 	arg = CALLOC(1, sizeof(*arg));
136 	if (arg != NULL) {
137 		if (already_running) {
138 			arg->already_running = already_running;
139 		} else {
140 			/* only one md-command */
141 			already_running = 1;
142 		}
143 		arg->state = BEGIN;
144 	}
145 	return arg;
146 }
147 
148 /*
149  * Context Free
150  */
151 static void
md_command_release(tr_ctx_t * tr_ctx)152 md_command_release(tr_ctx_t *tr_ctx)
153 {
154 	struct md_command_args *arg;
155 
156 	if (tr_ctx->arg) {
157 		arg = tr_ctx->arg;
158 		if (arg->already_running == 0)
159 			already_running = 0;
160 		FREE(arg);
161 	}
162 }
163 
164 /*
165  * Copy argument
166  */
167 static int
md_command_cparg(AXP * axp,uint32_t pm_type,int tag,const char * buf,size_t len,tr_ctx_t * tr_ctx)168 md_command_cparg(AXP *axp, uint32_t pm_type, int tag,
169 		 const char *buf, size_t len, tr_ctx_t *tr_ctx)
170 {
171 	struct md_command_args *arg = tr_ctx->arg;
172 	uint32_t mod_id;
173 
174 	if (arg->already_running) {
175 		tr_ctx->result = 302;
176 		return 0;
177 	}
178 
179 	switch (tag) {
180 		case ARMS_TAG_START_CPARG:
181 			break;
182 		case ARMS_TAG_END_CPARG:
183 			if (arg->mod_count < 1) {
184 				tr_ctx->result = 203;/*Parameter Problem*/
185 			}
186 			break;
187 		case ARMS_TAG_MDCOMMAND:
188 			if (tr_ctx->read_done)
189 				break;
190 			arg->mod_count++;
191 			if (arg->mod_count > 1) {
192 				tr_ctx->result = 422;/*Multiple Request*/
193 				return -1;
194 			}
195 			mod_id = get_module_id(axp, tag);
196 			arg->mod_id = mod_id;
197 			if (sizeof(arg->request) < len) {
198 				tr_ctx->result = 402;/*SA Failure*/
199 				return -1;
200 			}
201 			if (arms_get_encoding(axp, tag) == ARMS_DATA_BINARY) {
202 				/* decode base64 */
203 				len = arms_base64_decode_stream(&arg->base64,
204 							 arg->request,
205 							 sizeof(arg->request),
206 							 buf, len);
207 			} else {
208 				memcpy(arg->request, buf, len);
209 			}
210 			arg->req_len = len;
211 			break;
212 		default:
213 			break;
214 	}
215 
216 	return 0;
217 }
218 
219 /*
220  * Generate md-command-response mesage.
221  */
222 static int
md_command_response(transaction * tr,char * buf,int len,int * wrote)223 md_command_response(transaction *tr, char *buf, int len, int *wrote)
224 {
225 	tr_ctx_t *tr_ctx = &tr->tr_ctx;
226 	struct md_command_args *arg = tr_ctx->arg;
227 	arms_context_t *res = arms_get_context();
228 	int size, total, rv;
229 
230 	switch (arg->state) {
231 	case BEGIN:
232 		libarms_log(ARMS_LOG_DEBUG, "Generate response to RS");
233 		arg->result[0] = '\0';
234 		rv = res->callbacks.command_cb(
235 			arg->mod_id,
236 			ARMS_PUSH_MD_COMMAND,
237 			arg->request, arg->req_len,
238 			arg->result, sizeof(arg->result) - 1,
239 			&arg->next,
240 			res->udata);
241 		arg->encoding = ARMS_DATA_TEXT;
242 		if (ARMS_RESULT_IS_ERROR(rv)) {
243 			tr_ctx->result = 102;/*exec error*/
244 			arg->state = ERROR_RESULT;
245 		} else {
246 			arg->state = FIRST_RESULT;
247 		}
248 		if (ARMS_RESULT_IS_BYTES(rv)) {
249 			if (ARMS_RV_DATA_MASK(rv) < sizeof(arg->result)) {
250 				arg->encoding = ARMS_DATA_BINARY;
251 				arg->resultlen = ARMS_RV_DATA_MASK(rv);
252 			} else {
253 				/* too big bytes.  no md-result */
254 				tr_ctx->result = 102;/*exec error*/
255 				arg->state = ERROR_RESULT;
256 				snprintf(arg->result, sizeof(arg->result),
257 					 "data length too big (%d bytes)",
258 					 ARMS_RV_DATA_MASK(rv));
259 			}
260 		}
261 		size = arms_write_begin_message(tr, buf, len);
262 		buf += size;
263 		len -= size;
264 		if (arg->encoding == ARMS_DATA_BINARY) {
265 			size += snprintf(buf, len,
266 				 "<md-result id=\"%d\" encoding=\"base64\">",
267 					 arg->mod_id);
268 		} else {
269 			size += snprintf(buf, len,
270 				 "<md-result id=\"%d\">", arg->mod_id);
271 		}
272 		*wrote = size;
273 		return TR_WANT_WRITE;
274 	case ERROR_RESULT:
275 		*wrote = strlcpy(buf, arms_escape(arg->result), len);
276 		arg->state = DONE;
277 		return TR_WANT_WRITE;
278 	case FIRST_RESULT:
279 		if (arg->encoding == ARMS_DATA_BINARY) {
280 			int blen;
281 
282 			blen = ROUND_BASE64_BINARY(arg->resultlen);
283 			arg->resultlen -= blen;
284 			*wrote = arms_base64_encode(buf, len,
285 						    arg->result,
286 						    blen);
287 			memcpy(arg->result,
288 			       arg->result + blen, arg->resultlen);
289 		} else {
290 			*wrote = strlcpy(buf, arms_escape(arg->result), len);
291 			arg->resultlen = 0;
292 		}
293 		if ((arg->next & ARMS_FRAG_FINISHED) != 0)
294 			arg->state = DONE;
295 		else
296 			arg->state = NEXT_RESULT;
297 		return TR_WANT_WRITE;
298 	case NEXT_RESULT:
299 		arg->result[arg->resultlen] = '\0';
300 		arg->next = 0;
301 		rv = res->callbacks.command_cb(
302 			arg->mod_id,
303 			ARMS_PUSH_MD_COMMAND,
304 			NULL, 0,
305 			arg->result + arg->resultlen,
306 			sizeof(arg->result) - 1 - arg->resultlen,
307 			&arg->next,
308 			res->udata);
309 		if (ARMS_RESULT_IS_BYTES(rv) &&
310 		    ARMS_RV_DATA_MASK(rv) < sizeof(arg->result)) {
311 			int blen;
312 
313 			/* binary */
314 			arg->resultlen += ARMS_RV_DATA_MASK(rv);
315 			blen = ROUND_BASE64_BINARY(arg->resultlen);
316 			arg->resultlen -= blen;
317 			*wrote = arms_base64_encode(buf, len,
318 						    arg->result,
319 						    blen);
320 			memcpy(arg->result,
321 			       arg->result + blen, arg->resultlen);
322 		} else {
323 			/* text */
324 			*wrote = strlcpy(buf, arms_escape(arg->result), len);
325 			arg->resultlen = 0;
326 		}
327 		if ((arg->next & ARMS_FRAG_FINISHED) != 0)
328 			arg->state = DONE;
329 		else
330 			arg->state = NEXT_RESULT;
331 		return TR_WANT_WRITE;
332 	case DONE:
333 		if (arg->resultlen > 0) {
334 			total = size = arms_base64_encode(buf, len,
335 					  arg->result, arg->resultlen);
336 			buf += size;
337 			len -= size;
338 		} else {
339 			total = 0;
340 		}
341 
342 		size = snprintf(buf, len, "</md-result>");
343 		buf += size;
344 		len -= size;
345 		total += size;
346 
347 		total += arms_write_end_message(tr, buf, len);
348 		*wrote = total;
349 		arg->state = END;
350 		return TR_WRITE_DONE;
351 	case END:
352 		return TR_WRITE_DONE;
353 	default:
354 		break;
355 	}
356 	return TR_FATAL_ERROR;
357 }
358