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