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>