Annotation of embedaddon/libpdel/http/http_xml.c, revision 1.1.1.1
1.1 misho 1:
2: /*
3: * Copyright (c) 2001-2002 Packet Design, LLC.
4: * All rights reserved.
5: *
6: * Subject to the following obligations and disclaimer of warranty,
7: * use and redistribution of this software, in source or object code
8: * forms, with or without modifications are expressly permitted by
9: * Packet Design; provided, however, that:
10: *
11: * (i) Any and all reproductions of the source or object code
12: * must include the copyright notice above and the following
13: * disclaimer of warranties; and
14: * (ii) No rights are granted, in any manner or form, to use
15: * Packet Design trademarks, including the mark "PACKET DESIGN"
16: * on advertising, endorsements, or otherwise except as such
17: * appears in the above copyright notice or in the software.
18: *
19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
36: * THE POSSIBILITY OF SUCH DAMAGE.
37: *
38: * Author: Archie Cobbs <archie@freebsd.org>
39: */
40:
41: #include <sys/types.h>
42:
43: #include <netinet/in.h>
44: #include <arpa/inet.h>
45:
46: #include <stdio.h>
47: #include <stdlib.h>
48: #include <stdarg.h>
49: #include <string.h>
50: #include <syslog.h>
51: #include <errno.h>
52: #include <pthread.h>
53:
54: #include <openssl/ssl.h>
55:
56: #include "structs/structs.h"
57: #include "structs/type/array.h"
58: #include "structs/type/union.h"
59: #include "structs/xml.h"
60: #include "structs/xmlrpc.h"
61:
62: #include "io/boundary_fp.h"
63: #include "io/string_fp.h"
64: #include "sys/alog.h"
65: #include "util/typed_mem.h"
66:
67: #include "http/http_defs.h"
68: #include "http/http_server.h"
69: #include "http/xml.h"
70:
71: #define MEM_TYPE "http_xml_send_xmlrpc"
72:
73: /* Context for http_xml_send_xmlrpc() */
74: struct http_xml_send_xmlrpc_ctx {
75: struct xmlrpc_request *xreq;
76: struct xmlrpc_response_union *xrep;
77: };
78:
79: /*
80: * Internal functions
81: */
82: static void http_xml_send_xmlrpc_cleanup(void *arg);
83: static void http_xml_send_cleanup(void *arg);
84:
85: /*
86: * Send an XML-RPC message
87: *
88: * Returns:
89: * 0 Success
90: * -1 System error, errno is set
91: * -2 XML-RPC fault received
92: *
93: * The reply 'rep' may be NULL to ignore any reply value, otherwise
94: * it should already be initialized.
95: *
96: * If an XML-RPC fault is received, and "faultp" is not NULL, then
97: * it will be initialized with the fault received.
98: *
99: * This properly handles the calling thread's being canceled.
100: */
101: int
102: http_xml_send_xmlrpc(struct http_client *client,
103: struct in_addr ip, u_int16_t port, int https,
104: const char *username, const char *password,
105: const char *methodName, u_int nparams,
106: const struct structs_type **ptypes, const void **pdatas,
107: const struct structs_type *rep_type, void *rep,
108: struct xmlrpc_compact_fault *faultp, structs_xmllog_t *rlogger)
109: {
110: const struct structs_type *const xreq_type
111: = &structs_type_xmlrpc_request;
112: const struct structs_type *const xrep_type
113: = &structs_type_xmlrpc_response;
114: const struct structs_type *const ftype
115: = &structs_type_xmlrpc_compact_fault;
116: struct http_xml_send_xmlrpc_ctx *ctx;
117: struct xmlrpc_compact_fault fault;
118: char ebuf[128];
119: int ret = -1;
120: int r;
121:
122: /* Get context */
123: if ((ctx = MALLOC(MEM_TYPE, sizeof(*ctx))) == NULL) {
124: alogf(LOG_ERR, "%s: %m", "malloc");
125: return (-1);
126: }
127: memset(ctx, 0, sizeof(*ctx));
128: pthread_cleanup_push(http_xml_send_xmlrpc_cleanup, ctx);
129:
130: /* Build XML-RPC request and reply */
131: if ((ctx->xreq = structs_xmlrpc_build_request(MEM_TYPE,
132: methodName, nparams, ptypes, pdatas)) == NULL) {
133: alogf(LOG_ERR, "%s: %m", "structs_xmlrpc_build_request");
134: goto fail;
135: }
136: if ((ctx->xrep = MALLOC(MEM_TYPE, xrep_type->size)) == NULL) {
137: alogf(LOG_ERR, "%s: %m", "malloc");
138: goto fail;
139: }
140: if (structs_init(xrep_type, NULL, ctx->xrep) == -1) {
141: alogf(LOG_ERR, "%s: %m", "structs_init");
142: FREE(MEM_TYPE, ctx->xrep);
143: ctx->xrep = NULL;
144: goto fail;
145: }
146:
147: #ifdef XML_RPC_DEBUG
148: printf("%s: sending this XML-RPC request:\n", __FUNCTION__);
149: (void)structs_xml_output(xreq_type, XML_RPC_REQUEST_TAG,
150: NULL, ctx->xreq, stdout, NULL, 0);
151: #endif
152:
153: /* Send request and get reply; note: we could get canceled here. */
154: r = http_xml_send(client, ip, port, https, XML_RPC_URL,
155: username, password, XML_RPC_REQUEST_TAG, NULL, xreq_type,
156: ctx->xreq, STRUCTS_XML_FULL, XML_RPC_REPLY_TAG, NULL, NULL,
157: xrep_type, ctx->xrep, 0, rlogger);
158:
159: #ifdef XML_RPC_DEBUG
160: printf("%s: got this XML-RPC reply (error=%s):\n",
161: __FUNCTION__, r == -1 ? strerror(errno) : "none");
162: (void)structs_xml_output(xrep_type, XML_RPC_REPLY_TAG,
163: NULL, ctx->xrep, stdout, NULL, 0);
164: #endif
165:
166: /* Check error */
167: if (r == -1)
168: goto fail;
169:
170: /* Check for fault */
171: if (structs_init(ftype, NULL, &fault) == -1) {
172: alogf(LOG_ERR, "%s: %m", "structs_init");
173: goto fail;
174: }
175: if (structs_xmlrpc2struct(xrep_type, ctx->xrep,
176: "fault.value", ftype, &fault, NULL, NULL, 0) == 0) {
177: if (faultp != NULL)
178: *faultp = fault;
179: else
180: structs_free(ftype, NULL, &fault);
181: ret = -2; /* -2 indicates fault */
182: goto fail;
183: }
184: structs_free(ftype, NULL, &fault);
185:
186: /* Extract response (if desired) */
187: if (rep != NULL) {
188: if (rep_type != NULL) { /* return compact type */
189: if (structs_xmlrpc2struct(xrep_type, ctx->xrep,
190: "params.0.value", rep_type, rep, NULL, ebuf,
191: sizeof(ebuf)) == -1) {
192: (*rlogger)(LOG_ERR, "error decoding XML-RPC"
193: " response: %s", ebuf);
194: goto fail;
195: }
196: } else { /* return exploded type */
197: if (structs_get(&structs_type_xmlrpc_value,
198: "params.0.value", ctx->xrep, rep) == -1) {
199: alogf(LOG_ERR, "structs_get: %m");
200: goto fail;
201: }
202: }
203: }
204:
205: /* OK */
206: ret = 0;
207:
208: fail:;
209: /* Done */
210: pthread_cleanup_pop(1);
211: return (ret);
212: }
213:
214: /*
215: * Cleanup for http_xml_send_xmlrpc()
216: */
217: static void
218: http_xml_send_xmlrpc_cleanup(void *arg)
219: {
220: struct http_xml_send_xmlrpc_ctx *const ctx = arg;
221: const struct structs_type *const xreq_type
222: = &structs_type_xmlrpc_request;
223: const struct structs_type *const xrep_type
224: = &structs_type_xmlrpc_response;
225:
226: if (ctx->xreq != NULL) {
227: structs_free(xreq_type, NULL, ctx->xreq);
228: FREE(MEM_TYPE, ctx->xreq);
229: }
230: if (ctx->xrep != NULL) {
231: structs_free(xrep_type, NULL, ctx->xrep);
232: FREE(MEM_TYPE, ctx->xrep);
233: }
234: FREE(MEM_TYPE, ctx);
235: }
236:
237: /*
238: * Send a copy of the message, wait for a reply, and return the reply.
239: *
240: * The "reply" should already be initialized.
241: *
242: * This properly handles the calling thread's being canceled.
243: */
244: int
245: http_xml_send(struct http_client *client, struct in_addr ip,
246: u_int16_t port, int https, const char *urlpath, const char *username,
247: const char *password, const char *ptag, const char *pattrs,
248: const struct structs_type *ptype, const void *payload, int pflags,
249: const char *rtag, char **rattrsp, const char *rattrs_mtype,
250: const struct structs_type *rtype, void *reply, int rflags,
251: structs_xmllog_t *rlogger)
252: {
253: struct http_client_connection *cc;
254: struct http_request *req;
255: struct http_response *resp;
256: int ret = -1;
257: u_int code;
258: FILE *fp;
259:
260: /* Get HTTP connection */
261: if ((cc = http_client_connect(client, ip, port, https)) == NULL) {
262: alogf(LOG_ERR, "can't %s for %s:%u: %m",
263: "get HTTP client", inet_ntoa(ip), port);
264: return -1;
265: }
266:
267: /* Push cleanup hook */
268: pthread_cleanup_push(http_xml_send_cleanup, cc);
269:
270: /* Set up request */
271: req = http_client_get_request(cc);
272: if (http_request_set_method(req,
273: payload != NULL ? HTTP_METHOD_POST : HTTP_METHOD_GET) == -1) {
274: alogf(LOG_ERR, "can't %s for %s:%u: %m",
275: "set method", inet_ntoa(ip), port);
276: goto fail;
277: }
278: if (http_request_set_path(req, urlpath) == -1) {
279: alogf(LOG_ERR, "can't %s for %s:%u: %m",
280: "set path", inet_ntoa(ip), port);
281: goto fail;
282: }
283: if (http_request_set_header(req, 0, "Content-Type", "text/xml") == -1) {
284: alogf(LOG_ERR, "can't %s for %s:%u: %m",
285: "set content-type", inet_ntoa(ip), port);
286: goto fail;
287: }
288: if (username != NULL && password != NULL) {
289: char *auth;
290:
291: if ((auth = http_request_encode_basic_auth(TYPED_MEM_TEMP,
292: username, password)) == NULL) {
293: alogf(LOG_ERR, "can't %s for %s:%u: %m",
294: "encode authorization", inet_ntoa(ip), port);
295: goto fail;
296: }
297: if (http_request_set_header(req, 0, "Authorization",
298: "Basic %s", auth) == -1) {
299: alogf(LOG_ERR, "can't %s for %s:%u: %m",
300: "set authorization header", inet_ntoa(ip), port);
301: FREE(TYPED_MEM_TEMP, auth);
302: goto fail;
303: }
304: FREE(TYPED_MEM_TEMP, auth);
305: }
306:
307: /* Write XML data to HTTP client output stream */
308: if (payload != NULL) {
309: if ((fp = http_request_get_output(req, 1)) == NULL) {
310: alogf(LOG_ERR, "can't %s for %s:%u: %m",
311: "get output", inet_ntoa(ip), port);
312: goto fail;
313: }
314: if (structs_xml_output(ptype,
315: ptag, pattrs, payload, fp, NULL, pflags) == -1) {
316: alogf(LOG_ERR, "can't %s for %s:%u: %m",
317: "write XML", inet_ntoa(ip), port);
318: goto fail;
319: }
320: }
321:
322: /* Get response */
323: if ((resp = http_client_get_response(cc)) == NULL) {
324: alogf(LOG_ERR, "can't %s for %s:%u: %m",
325: "get response", inet_ntoa(ip), port);
326: goto fail;
327: }
328: if ((code = http_response_get_code(resp)) != HTTP_STATUS_OK) {
329: alogf(LOG_ERR, "rec'd HTTP error code %d from"
330: "http%s://%s:%u%s: %s", code, https ? "s" : "",
331: inet_ntoa(ip), port, urlpath,
332: http_response_status_msg(code));
333: goto fail;
334: }
335:
336: /* Read XML reply from client input stream */
337: if ((fp = http_response_get_input(resp)) == NULL) {
338: alogf(LOG_ERR, "can't %s for %s:%u: %m",
339: "get input", inet_ntoa(ip), port);
340: goto fail;
341: }
342: if (structs_xml_input(rtype, rtag, rattrsp,
343: rattrs_mtype, fp, reply, rflags, rlogger) == -1) {
344: alogf(LOG_ERR, "can't %s for %s:%u: %m",
345: "read XML reply", inet_ntoa(ip), port);
346: goto fail;
347: }
348:
349: /* OK */
350: ret = 0;
351:
352: fail:;
353: /* Done */
354: pthread_cleanup_pop(1);
355: return (ret);
356: }
357:
358: /*
359: * Cleanup for http_xml_send()
360: */
361: static void
362: http_xml_send_cleanup(void *arg)
363: {
364: struct http_client_connection *cc = arg;
365:
366: http_client_close(&cc);
367: }
368:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>