CimxmlMessage *cimxml_message_new() {
	CimxmlMessage *cimxml_msg = u_zalloc(sizeof(CimxmlMessage));
	u_buf_create(&cimxml_msg->request);
	u_buf_create(&cimxml_msg->response);
	cimxml_msg->status.code = CIMXML_STATUS_OK;
	return cimxml_msg;
}
Beispiel #2
0
/*
   The PUT method requests that the resource identified by the request
   URI be updated or created with the enclosed representation.  The
   representation format is specified by the media type given in the
   Content-Type Option.

   If a resource exists at the request URI the enclosed representation
   SHOULD be considered a modified version of that resource, and a 2.04
   (Changed) response SHOULD be returned.  If no resource exists then
   the server MAY create a new resource with that URI, resulting in a
   2.01 (Created) response.  If the resource could not be created or
   modified, then an appropriate error response code SHOULD be sent.

   Further restrictions to a PUT can be made by including the If-Match
   (see Section 5.10.9) or If-None-Match (see Section 5.10.10) options
   in the request.

   PUT is not safe, but idempotent.
 */
int serve_put(ec_server_t *srv, ec_rep_t *rep)
{
    /* This routine handles the update of a resource using the PUT method.
     * Creation of a resource via PUT is done by the create() routine. */

    ec_mt_t mt;
    size_t pload_sz;
    uint8_t etag[EC_ETAG_SZ] = { 0 }, *pload;
    ec_res_t *res = ec_rep_get_res(rep);
    size_t bsz = g_ctx.bsz ? g_ctx.bsz : EC_COAP_BLOCK_MAX;
    blockopt_t b1 = { .bnum = 0, .more = false, .bsz = 0 };

    /* Check conditionals:
     * 1) If-None-Match
     * "If the target resource does exist, then the server MUST NOT perform
     *  the requested method.  Instead, the server MUST respond with the 4.12
     *  (Precondition Failed) response code." */
    if (res && ec_request_get_if_none_match(srv) == 0)
    {
        (void) ec_response_set_code(srv, EC_PRECONDITION_FAILED);
        return 0;
    }

    /* 2) If-Match (TODO) */

    /* Get payload and media type (if specified.) */
    pload = ec_request_get_payload(srv, &pload_sz);
    if (pload_sz > bsz)
    {
        (void) ec_response_set_code(srv, EC_REQUEST_ENTITY_TOO_LARGE);
        return 0;
    }

    /* Get media type (if not specified default to text/plain. */
    if (ec_request_get_content_type(srv, &mt))
        mt = EC_MT_TEXT_PLAIN;

    /* Handle Block1 Option.
     * Implementation is stateful: we just check that bnum corresponds to
     * expected and add the new representation atomically. */
    if (ec_request_get_block1(srv, &b1.bnum, &b1.more, &b1.bsz) == 0)
    {
        dbg_err_if (b1.bnum != g_ctx.b1.bnum++);

        if (b1.bsz)
           bsz = U_MIN(bsz, b1.bsz);

        dbg_err_if (ec_response_add_block1(srv, b1.bnum, b1.more, bsz));
    }

    /* First block. */
    if (g_ctx.resbuf == NULL)
        dbg_err_if (u_buf_create(&g_ctx.resbuf));

    /* All blocks are appended to resource buffer. */
    if (pload)
        dbg_err_if (u_buf_append(g_ctx.resbuf, pload, pload_sz));

    /* Last block - now we can process it. */
    if (!b1.more)
    {
        /* Add new representation. */
        dbg_err_if (ec_resource_add_rep(res, u_buf_ptr(g_ctx.resbuf),
                    u_buf_len(g_ctx.resbuf), mt, etag));

        /* Delete old in case media-type matches. */
        if (mt == rep->media_type)
            (void) ec_rep_del(res, rep);

        /* Return Etag of the new representation. */
        (void) ec_response_add_etag(srv, etag, sizeof etag);

        /* Reset state. */
        u_buf_free(g_ctx.resbuf);
        g_ctx.resbuf = NULL;
        g_ctx.b1.bnum = 0;
        g_ctx.b1.more = false;
        g_ctx.b1.bsz = 0;
    }

    (void) ec_response_set_code(srv, EC_CHANGED);
    return 0;
err:
    (void) ec_response_set_code(srv, EC_INTERNAL_SERVER_ERROR);

    /* Reset state. */
    if (g_ctx.resbuf)
        u_buf_free(g_ctx.resbuf);
    g_ctx.resbuf = NULL;
    g_ctx.b1.bnum = 0;
    g_ctx.b1.more = false;
    g_ctx.b1.bsz = 0;

    return -1;
}

/*
 * The POST method requests that the representation enclosed in the
 * request be processed.  The actual function performed by the POST
 * method is determined by the origin server and dependent on the target
 * resource.  It usually results in a new resource being created or the
 * target resource being updated.
 *
 * If a resource has been created on the server, a 2.01 (Created)
 * response that includes the URI of the new resource in a sequence of
 * one or more Location-Path and/or Location-Query Options SHOULD be
 * returned.  If the POST succeeds but does not result in a new resource
 * being created on the server, a 2.04 (Changed) response SHOULD be
 * returned.  If the POST succeeds and results in the target resource
 * being deleted, a 2.02 (Deleted) response SHOULD be returned.
 *
 * POST is neither safe nor idempotent.
 */
/* 
 * Creates a new resource at <request_uri>/<num>, where num is an incremental
 * counter.
 */
int serve_post(ec_server_t *srv)
{
    /* Request vars. */
    ec_mt_t mt;
    ec_res_t *res = NULL;
    bool is_proxy = false;
    uint8_t *pload;
    size_t pload_sz;
    ec_method_mask_t mm = EC_METHOD_MASK_ALL;
    char uri[U_URI_STRMAX];
    char ruri[U_URI_STRMAX];

    /* Block handling. */
    size_t bsz = g_ctx.bsz ? g_ctx.bsz : EC_COAP_BLOCK_MAX;
    blockopt_t b1 = { .bnum = 0, .more = false, .bsz = 0 };

    /* Path tokenisation. */
    size_t nelems, i;
    char **tv = NULL;

    pload = ec_request_get_payload(srv, &pload_sz);
    if (pload_sz > bsz)
    {
        (void) ec_response_set_code(srv, EC_REQUEST_ENTITY_TOO_LARGE);
        return 0;
    }

    /* Get media type (if not specified default to text/plain. */
    if (ec_request_get_content_type(srv, &mt))
        mt = EC_MT_TEXT_PLAIN;
    
    /* Handle Block1 Option.
     * Implementation is stateful: we just check that bnum corresponds to
     * expected and add the new representation atomically. */
    if (ec_request_get_block1(srv, &b1.bnum, &b1.more, &b1.bsz) == 0)
    {
        dbg_err_if (b1.bnum != g_ctx.b1.bnum++);

        if (b1.bsz)
           bsz = U_MIN(bsz, b1.bsz);

        dbg_err_if (ec_response_add_block1(srv, b1.bnum, b1.more, bsz));
    }

    /* First block. */
    if (g_ctx.resbuf == NULL)
        dbg_err_if (u_buf_create(&g_ctx.resbuf));

    /* All blocks are appended to resource buffer. */
    if (pload)
        dbg_err_if (u_buf_append(g_ctx.resbuf, pload, pload_sz));

    /* Last block - now we can process it. */
    if (!b1.more)
    {
        (void) ec_request_get_uri(srv, uri, &is_proxy);

        dbg_err_if (u_snprintf(ruri, sizeof ruri, "%s/%u", uri, g_ctx.resnum));

        u_dbg("creating resource on uri: %s", ruri);

        /* Create resource with all methods allowed. */
        dbg_err_ifm ((res = ec_resource_new(ruri, mm, EC_COAP_DEFAULT_MAX_AGE))
                == NULL, "resource creation failed");

        /* Create new resource representation with the requested media type. */
        /* Each resource only has one representation in this implementation.
         * Use automatic ETag. */
        dbg_err_ifm (ec_resource_add_rep(res, u_buf_ptr(g_ctx.resbuf),
                    u_buf_len(g_ctx.resbuf), mt, NULL),
                "error adding representation for %s", ruri);

        /* Attach resource to FS. */
        dbg_err_ifm (ec_filesys_put_resource(g_ctx.fs, res),
                "adding resource failed");
        res = NULL;

        /* Register the callback that will serve this URI.
         * XXX If we get an error here it's really a bad thing because
         * the resource has been already registered and we go into an
         * inconsistent state. */
        dbg_err_ifm (ec_register_cb(g_ctx.coap, ruri, serve, NULL),
                "registering callback for %s failed", ruri);

        dbg_err_if (u_strtok(ruri, "/", &tv, &nelems));
        dbg_err_if (nelems < 3);

        for (i = 2; i < nelems; i++)  /* Get path only */
            dbg_err_if (ec_response_add_location_path(srv, tv[i]));

        u_strtok_cleanup(tv, nelems);

        /* Reset state. */
        u_buf_free(g_ctx.resbuf);
        g_ctx.resbuf = NULL;
        g_ctx.b1.bnum = 0;
        g_ctx.b1.more = false;
        g_ctx.b1.bsz = 0;

        g_ctx.resnum++;
    }

    (void) ec_response_set_code(srv, EC_CREATED);
    return 0;
err:
    (void) ec_response_set_code(srv, EC_INTERNAL_SERVER_ERROR);
    if (res)
        ec_resource_free(res);
    if (tv)
        u_strtok_cleanup(tv, nelems);

    /* Reset state. */
    if (g_ctx.resbuf)
        u_buf_free(g_ctx.resbuf);
    g_ctx.resbuf = NULL;
    g_ctx.b1.bnum = 0;
    g_ctx.b1.more = false;
    g_ctx.b1.bsz = 0;
    return -1;

#if 0
    /* This routine handles the creation of a resource using the POST method. */
    ec_mt_t mt;
    uint8_t *pload;
    size_t pload_sz;
    ec_res_t *res = NULL;
    bool is_proxy = false;
    ec_method_mask_t mm = EC_METHOD_MASK_ALL;
    char uri[U_URI_STRMAX], *first, *uri_tmp, *uri_res;

    /* Get payload (may be empty/NULL).
     * If it is not empty/NULL check/parse the content */
    pload = ec_request_get_payload(srv, &pload_sz);

    first = strtok((char *) pload, ">");
    do
    {
        uri_tmp = strpbrk(first, "<");

        (void) ec_request_get_uri(srv, uri, &is_proxy);

        uri_res = strcat(uri, ++uri_tmp);

        CHAT("adding resource for: %s", uri_res);

        /* Create resource with all methods allowed. */
        dbg_err_ifm ((res = ec_resource_new(uri_res, mm, 3600)) == NULL,
                "resource creation failed");

        /* Get media type (if not specified default to text/plain. */
        if (ec_request_get_content_type(srv, &mt))
            mt = EC_MT_TEXT_PLAIN;

        /* Create new resource representation with the requested media type. */
        /* Each resource only has one representation in this implementation.
         * Use automatic ETag. */
        dbg_err_ifm (ec_resource_add_rep(res, (const uint8_t *) " ", 1, mt, NULL),
                "error adding representation for %s", uri_res);

        /* Attach resource to FS. */
        dbg_err_ifm (ec_filesys_put_resource(g_ctx.fs, res),
                "adding resource failed");
        res = NULL;

        /* Register the callback that will serve this URI.
         * XXX If we get an error here it's really a bad thing because
         * the resource has been already registered and we go into an
         * inconsistent state. */
        dbg_err_ifm (ec_register_cb(g_ctx.coap, uri_res, serve, NULL),
                "registering callback for %s failed", uri_res);

        first = NULL;
        uri[0] = '\0';
        first = strtok(NULL, ">");
    }
    while (first != NULL);

    /* 2.01 Created */
    (void) ec_response_set_code(srv, EC_CREATED);

    return EC_CBRC_READY;
err:
    if (res)
        ec_resource_free(res);
    return EC_CBRC_ERROR;
#endif
}

#if 0
ec_cbrc_t create(ec_server_t *srv, void *u0, struct timeval *u1, bool u2)
{
    uint8_t *pload;
    size_t pload_sz;
    ec_res_t *res = NULL;
    ec_method_t method;
    bool is_proxy = false;
    char uri[U_URI_STRMAX];
    ec_mt_t mt;
    ec_method_mask_t mm = EC_METHOD_MASK_ALL;

    u_unused_args(u0, u1, u2);

    /* Get the requested URI and method. */
    (void) ec_request_get_uri(srv, uri, &is_proxy);

    switch ((method = ec_server_get_method(srv)))
    {
        case EC_COAP_POST:
            (void) serve_post(srv, NULL);
            return EC_CBRC_READY;
        case EC_COAP_PUT:
            break;
        default:
            (void) ec_response_set_code(srv, EC_NOT_FOUND);
            return EC_CBRC_READY;
    }

    CHAT("adding resource for: %s", uri);

    /* Create resource with all methods allowed. */
    dbg_err_ifm((res = ec_resource_new(uri, mm, 3600)) == NULL,
            "resource creation failed");

    /* Get payload (may be empty/NULL). */
    pload = ec_request_get_payload(srv, &pload_sz);

    /* Get media type (if not specified default to text/plain. */
    if (ec_request_get_content_type(srv, &mt))
        mt = EC_MT_TEXT_PLAIN;

    /* Create new resource representation with the requested media type. */
    /* Each resource only has one representation in this implementation.
     * Use automatic ETag. */
    dbg_err_ifm (ec_resource_add_rep(res, pload, pload_sz, mt, NULL),
            "error adding representation for %s", uri);

    /* Attach resource to FS. */
    dbg_err_ifm (ec_filesys_put_resource(g_ctx.fs, res),
            "adding resource failed");
    res = NULL;

    /* Register the callback that will serve this URI.
     * XXX If we get an error here it's really a bad thing because
     * the resource has been already registered and we go into an
     * inconsistent state. */
    dbg_err_ifm (ec_register_cb(g_ctx.coap, uri, serve, NULL),
            "registering callback for %s failed", uri);

    /* 2.01 Created */
    (void) ec_response_set_code(srv, EC_CREATED);

    return EC_CBRC_READY;
err:
    (void) ec_response_set_code(srv, EC_INTERNAL_SERVER_ERROR);
    if (res)
        ec_resource_free(res);
    return EC_CBRC_ERROR;
}
void
wsmc_handler( WsManClient *cl,
		WsXmlDocH rqstDoc,
		void* user_data)
{
#define curl_err(str)  debug("Error = %d (%s); %s", \
		r, curl_easy_strerror(r), str);
	WsManConnection *con = cl->connection;
	CURL *curl = NULL;
	CURLcode r;
	char *upwd = NULL;
	char *usag = NULL;
	struct curl_slist *headers=NULL;
	char *buf = NULL;
	int len;
	char *soapact_header = NULL;
	long http_code;
	long auth_avail = 0;
	char *_user = NULL, *_pass = NULL;
	u_buf_t *response = NULL;
	//char *soapaction;
	char *tmp_str = NULL;

	if (!cl->initialized && wsmc_transport_init(cl, NULL)) {
		cl->last_error = WS_LASTERR_FAILED_INIT;
		return;
	}
	if (cl->transport == NULL) {
		cl->transport = init_curl_transport(cl);
                if (cl->transport == NULL) {
                        return;
                }
	}
	curl = (CURL *)cl->transport;

	r = curl_easy_setopt(curl, CURLOPT_URL, cl->data.endpoint);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_URL, ...)");
		goto DONE;
	}

	r = curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, write_handler);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, ..)");
		goto DONE;
	}
	u_buf_create(&response);
	r = curl_easy_setopt(curl, CURLOPT_WRITEDATA, response);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_WRITEDATA, ..)");
		goto DONE;
	}
	char content_type[64];
	snprintf(content_type, 64, "Content-Type: application/soap+xml;charset=%s", cl->content_encoding);
	headers = curl_slist_append(headers, content_type);
	tmp_str = wsman_transport_get_agent(cl);
	usag = malloc(12 + strlen(tmp_str) + 1);
	if (usag == NULL) {
		r = CURLE_OUT_OF_MEMORY;
		cl->fault_string = u_strdup("Could not malloc memory");
		curl_err("Could not malloc memory");
		goto DONE;
	}

	sprintf(usag, "User-Agent: %s", tmp_str);
	free(tmp_str);
	headers = curl_slist_append(headers, usag);

#if 0
	soapaction = ws_xml_get_xpath_value(rqstDoc, "/s:Envelope/s:Header/wsa:Action");
	if (soapaction) {
		soapact_header = malloc(12 + strlen(soapaction) + 1);
		if (soapact_header) {
			sprintf(soapact_header, "SOAPAction: %s", soapaction);
			headers = curl_slist_append(headers, soapact_header);
		}
		u_free(soapaction);
	}
#endif

	r = curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_HTTPHEADER, ..)");
		goto DONE;
	}

	ws_xml_dump_memory_enc(rqstDoc, &buf, &len, cl->content_encoding);
#if 0
	int count = 0;
	while(count < len) {
		printf("%c",buf[count++]);
	}
#endif
	debug("*****set post buf len = %d******",len);
	r = curl_easy_setopt(curl, CURLOPT_POSTFIELDS, buf);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_POSTFIELDS, ..)");
		goto DONE;
	}
	r = curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, len);
	if (r != CURLE_OK) {
		cl->fault_string = u_strdup(curl_easy_strerror(r));
		curl_err("Could not curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, ..)");
		goto DONE;
	}

	int iDone = 0;
	while (1) {
		u_free(_user);
		u_free(_pass);
		_user = wsmc_get_user(cl);
		_pass = wsmc_get_password(cl);
		if (_user && _pass && cl->data.auth_set) {
			r = curl_easy_setopt(curl, CURLOPT_HTTPAUTH, cl->data.auth_set);
			if (r != CURLE_OK) {
				cl->fault_string = u_strdup(curl_easy_strerror(r));
				curl_err("curl_easy_setopt(CURLOPT_HTTPAUTH) failed");
				goto DONE;
			}
			u_free(upwd);
			upwd = u_strdup_printf(  "%s:%s", _user ,  _pass);
			if (!upwd) {
				r = CURLE_OUT_OF_MEMORY;
				cl->fault_string = u_strdup("Could not malloc memory");
				curl_err("Could not malloc memory");
				goto DONE;
			}
			r = curl_easy_setopt(curl, CURLOPT_USERPWD, upwd);
			if (r != CURLE_OK) {
				cl->fault_string = u_strdup(curl_easy_strerror(r));
				curl_err("curl_easy_setopt(curl, CURLOPT_USERPWD, ..) failed");
				goto DONE;
			}
		}

		if (wsman_debug_level_debugged(DEBUG_LEVEL_MESSAGE)) {
			curl_easy_setopt(curl, CURLOPT_VERBOSE, 1);
		}

		r = curl_easy_perform(curl);
		if (r != CURLE_OK) {
			cl->fault_string = u_strdup(curl_easy_strerror(r));
			curl_err("curl_easy_perform failed");
			goto DONE;
		}

		r = curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
		if (r != CURLE_OK) {
			cl->fault_string = u_strdup(curl_easy_strerror(r));
			curl_err("curl_easy_getinfo(CURLINFO_RESPONSE_CODE) failed");
			goto DONE;
		}

		switch (http_code) 
		{
			case 200:
			case 400:
			case 500:
				// The resource was successfully retrieved or WSMan server 
				// returned a HTTP status code. You can use WinHttpReadData to 
				// read the contents of the server's response.
				iDone = 1;
				break;
			case 401:
				// The server requires authentication.
				break;
			default:
				// The status code does not indicate success.
				r = WS_LASTERR_OTHER_ERROR;
				iDone = 1;
				break;
		}

		if(iDone == 1) {
			break;
		}

		/* we are here because of authentication required */
		r = curl_easy_getinfo(curl, CURLINFO_HTTPAUTH_AVAIL, &auth_avail);
		if (r != CURLE_OK) {
			cl->fault_string = u_strdup(curl_easy_strerror(r));
			curl_err("curl_easy_getinfo(CURLINFO_HTTPAUTH_AVAIL) failed");
			goto DONE;
		}

		cl->data.auth_set = reauthenticate(cl, cl->data.auth_set, auth_avail,
                        &cl->data.user, &cl->data.pwd);
                u_buf_clear(response);
                if (cl->data.auth_set == 0) {
                    /* FIXME: user wants to cancel authentication */
#if LIBCURL_VERSION_NUM >= 0x70D01
                    r = CURLE_LOGIN_DENIED;
#else
					/* Map the login failure error to CURLE_LOGIN_DENIED (67) so that we
					 * get the same error code in case of login failure
					 */
					r = 67;
#endif
                    curl_err("user/password wrong or empty.");
		    break;
                }
        }
#if 0
	unsigned char *mbbuf = NULL;
	iconv_t cd;
	if(strcmp(cl->content_encoding, "UTF-8")) {
                cd = iconv_open("UTF-8", cl->content_encoding);
                if(cd == -1) {
			cl->last_error = WS_LASTERR_BAD_CONTENT_ENCODING;
			goto DONE2;
                }
                mbbuf = u_zalloc(u_buf_len(response));
                size_t outbuf_len = u_buf_len(response);
                size_t inbuf_len = outbuf_len;
                char *inbuf = u_buf_ptr(response);
                char *outbuf = mbbuf;
                size_t coverted = iconv(cd, &inbuf, &inbuf_len, &outbuf, &outbuf_len);
		  iconv_close(cd);
                if( coverted == -1) {
			cl->last_error = WS_LASTERR_BAD_CONTENT_ENCODING;
			goto DONE2;
                }
                u_buf_append(con->response, mbbuf, u_buf_len(response) - inbuf_len);
        }
	u_free(mbbuf);
#endif
	u_buf_append(con->response, u_buf_ptr(response), u_buf_len(response));
DONE:
	curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_code);
	cl->response_code = http_code;
	cl->last_error = convert_to_last_error(r);

	debug("curl error code: %d.", r);
	debug("cl->response_code: %d.", cl->response_code);
	debug("cl->last_error code: %d.", cl->last_error);

	curl_slist_free_all(headers);
	u_buf_free(response);
	u_free(soapact_header);
	u_free(usag);
	u_free(upwd);
	u_free(_pass);
	u_free(_user);
#ifdef _WIN32
	ws_xml_free_memory(buf);
#else
	u_free(buf);
#endif

	return;
#undef curl_err

}