1 /*	$Id: proto_push_clear_status.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 
48 #include <libarms/malloc.h>
49 #include <libarms/base64.h>
50 #include <transaction/transaction.h>
51 #include <protocol/arms_methods.h>
52 
53 /*
54  * Callback Functions
55  */
56 static void *clear_status_context(tr_ctx_t *ctx);
57 static int
58 clear_status_cparg(AXP *axp, uint32_t pm_type, int tag, const char *buf,
59 		size_t len, tr_ctx_t *ctx);
60 static int
61 clear_status_done(transaction *tr, char *buf, int len, int *wrote);
62 static void clear_status_release(tr_ctx_t *ctx);
63 
64 /*
65  * XML Schema: clear-status-start-request
66  */
67 static char *status_req_attr[] = {
68 	"id", NULL,
69 	"encoding", NULL,
70 	NULL
71 };
72 static struct axp_schema arms_clear_status_sreq_body[] = {
73 	{ARMS_TAG_STATUS_REQ, "status-request", AXP_TYPE_TEXT,
74 		status_req_attr, push_default_hook, NULL},
75 
76 	{0, NULL, 0, NULL, NULL, NULL}
77 };
78 static struct axp_schema clear_status_start_request = {
79 	ARMS_TAG_CLEARSTATUS_SREQ, "clear-status-start-request", AXP_TYPE_CHILD,
80 		NULL, push_default_hook, arms_clear_status_sreq_body
81 };
82 
83 /*
84  * Method definition
85  */
86 arms_method_t clear_status_methods = {
87 	ARMS_TR_CLEAR_STATUS,	/* pm_type */
88 	"clear-status",		/* pm_string */
89 	&clear_status_start_request, /* schema */
90 	0,			/* pm_flags */
91 	build_generic_res,	/* pm_response */
92 	clear_status_done,	/* pm_done */
93 	NULL,			/* pm_exec */
94 	clear_status_cparg,	/* pm_copyarg */
95 	NULL,			/* pm_rollback */
96 	clear_status_context,	/* pm_context */
97 	clear_status_release,	/* pm_release */
98 };
99 
100 /*
101  * Method implementations
102  */
103 
104 #define BEGIN  1
105 #define RESULT 2
106 #define DONE   3
107 
108 struct status_req {
109 	int id;
110 	char *buf;
111 	size_t len;
112 };
113 
114 struct clear_status_args {
115 	int mod_id;
116 	int nstatus;
117 	int i;
118 
119 	int state;
120 	int maxindex;
121 	struct status_req *status_list;
122 	char result[1024];
123 	arms_base64_stream_t base64;
124 };
125 
126 /*
127  * Context Alloc
128  */
129 static void *
clear_status_context(tr_ctx_t * tr_ctx)130 clear_status_context(tr_ctx_t *tr_ctx)
131 {
132 	struct clear_status_args *arg;
133 	arms_context_t *res = arms_get_context();
134 
135 	if (res->callbacks.command_cb == NULL) {
136 		tr_ctx->result = 505;/*Not Support*/
137 		return NULL;
138 	}
139 	arg = CALLOC(1, sizeof(*arg));
140 	if (arg != NULL) {
141 		arg->state = BEGIN;
142 		arg->maxindex = 16;
143 		arg->status_list = CALLOC(arg->maxindex + 1, sizeof(int));
144 		if (arg->status_list == NULL) {
145 			FREE(arg);
146 			arg = NULL;
147 			tr_ctx->result = 413;/*413 Resource Exhausted*/
148 		}
149 	} else {
150 		tr_ctx->result = 413;/*413 Resource Exhausted*/
151 	}
152 
153 	return arg;
154 }
155 
156 /*
157  * Context Free
158  */
159 static void
clear_status_release(tr_ctx_t * tr_ctx)160 clear_status_release(tr_ctx_t *tr_ctx)
161 {
162 	struct clear_status_args *arg;
163 
164 	arg = tr_ctx->arg;
165 	if (arg) {
166 		if (arg->status_list != NULL) {
167 			int i;
168 
169 			for (i = 0; i < arg->nstatus; i++) {
170 				if (arg->status_list[i].len > 0)
171 					FREE(arg->status_list[i].buf);
172 			}
173 			FREE(arg->status_list);
174 		}
175 		FREE(arg);
176 	}
177 }
178 
179 /*
180  * Copy argument
181  */
182 static int
add_status_id(struct clear_status_args * arg,int mod_id,const char * buf,size_t len,int encoding)183 add_status_id(struct clear_status_args *arg,
184 	      int mod_id, const char *buf, size_t len, int encoding)
185 {
186 	int newmax;
187 	struct status_req *newlist;
188 	char *newbuf;
189 
190 	if (arg->nstatus >= arg->maxindex) {
191 		newmax = arg->maxindex * 2;
192 		newlist = REALLOC(arg->status_list,
193 				  sizeof(struct status_req) * (newmax + 1));
194 		if (newlist == NULL)
195 			return -1;
196 		arg->maxindex = newmax;
197 		arg->status_list = newlist;
198 	}
199 
200 	arg->status_list[arg->nstatus].id = mod_id;
201 	arg->status_list[arg->nstatus].buf = newbuf = MALLOC(len + 1);
202 	if (newbuf == NULL)
203 		return -1;
204 	if (encoding == ARMS_DATA_BINARY) {
205 		/* decode base64 */
206 		len = arms_base64_decode_stream(
207 			&arg->base64, newbuf, len, buf, len);
208 	} else {
209 		memcpy(newbuf, buf, len);
210 	}
211 	newbuf[len] = '\0';
212 	arg->status_list[arg->nstatus].len = len;
213 	arg->nstatus++;
214 
215 	return 0;
216 }
217 
218 static int
clear_status_cparg(AXP * axp,uint32_t pm_type,int tag,const char * buf,size_t len,tr_ctx_t * tr_ctx)219 clear_status_cparg(AXP *axp, uint32_t pm_type, int tag,
220 		const char *buf, size_t len, tr_ctx_t *tr_ctx)
221 {
222 	struct clear_status_args *arg = tr_ctx->arg;
223 
224 	if (tag == ARMS_TAG_STATUS_REQ) {
225 		const char *attr;
226 
227 		attr = axp_find_attr(axp, tag, "id");
228 		if (attr == NULL) {
229 			return -1;
230 		}
231 		if (add_status_id(arg, atoi(attr),
232 				  buf, len, arms_get_encoding(axp, tag)) < 0) {
233 			tr_ctx->result = 413;/*Resouce Exhausted*/
234 		}
235 	} else if (tag == ARMS_TAG_END_CPARG) {
236 		if (arg->nstatus == 0) {
237 			/* <status-request id="xx"> tag not found. */
238 			tr_ctx->result = 203;/*Invalid Parameter*/
239 		}
240 	} else {
241 		/* other tag (ignored) */
242 	}
243 
244 	return 0;
245 }
246 
247 /*
248  * Done
249  */
250 static int
clear_status_done(transaction * tr,char * buf,int len,int * wrote)251 clear_status_done(transaction *tr, char *buf, int len, int *wrote)
252 {
253 	tr_ctx_t *tr_ctx = &tr->tr_ctx;
254 	struct clear_status_args *arg = tr_ctx->arg;
255 	arms_context_t *res = arms_get_context();
256 	int size, total, rv;
257 
258 	switch (arg->state) {
259 	case BEGIN:
260 		libarms_log(ARMS_LOG_DEBUG,
261 			    "Generate clear-status-done");
262 		size = arms_write_begin_message(tr, buf, len);
263 		buf += size;
264 		len -= size;
265 		arg->state = RESULT;
266 		*wrote = size;
267 		return TR_WANT_WRITE;
268 	case RESULT:
269 		rv = res->callbacks.command_cb(
270 			arg->status_list[arg->i].id,
271 			ARMS_PUSH_CLEAR_STATUS,
272 			arg->status_list[arg->i].buf,
273 			arg->status_list[arg->i].len,
274 			arg->result, sizeof(arg->result),
275 			NULL,
276 			res->udata);
277 		if (ARMS_RESULT_IS_ERROR(rv) ||
278 		    (ARMS_RESULT_IS_BYTES(rv) &&
279 		     ARMS_RV_DATA_MASK(rv) > sizeof(arg->result))) {
280 			/* callback error */
281 			total = 0;
282 			size = snprintf(buf, len,
283 			    "<status-report id=\"%d\" result=\"402\">%s",
284 			    arg->status_list[arg->i].id,
285 			    arms_escape(arg->result));
286 			buf += size;
287 			len -= size;
288 			total += size;
289 		} else if (ARMS_RESULT_IS_BYTES(rv)) {
290 			total = 0;
291 			size = snprintf(buf, len,
292 				  "<status-report id=\"%d\""
293 				  " encoding=\"base64\" result=\"100\">",
294 				  arg->status_list[arg->i].id);
295 			buf += size;
296 			len -= size;
297 			total += size;
298 
299 			size = arms_base64_encode(buf, len,
300 						  arg->result,
301 						  ARMS_RV_DATA_MASK(rv));
302 			buf += size;
303 			len -= size;
304 			total += size;
305 		} else {
306 			/* text */
307 			total = 0;
308 			size = snprintf(buf, len,
309 				  "<status-report id=\"%d\" result=\"100\">"
310 				  "%s",
311 				  arg->status_list[arg->i].id,
312 				  arms_escape(arg->result));
313 			buf += size;
314 			len -= size;
315 			total += size;
316 		}
317 		total += snprintf(buf, len, "</status-report>");
318 		*wrote = total;
319 		arg->i++;
320 		if (arg->i >= arg->nstatus)
321 			arg->state = DONE;
322 		return TR_WANT_WRITE;
323 	case DONE:
324 		*wrote = arms_write_end_message(tr, buf, len);
325 		return TR_WRITE_DONE;
326 	default:
327 		break;
328 	}
329 	return TR_FATAL_ERROR;
330 }
331