Example #1
0
/**
 * Declare user-defined mapping between a URI and a namespace.
 */
static void
xfmt_prefix_declare(struct xfmt_pass2 *xp2, const char *uri, const char *prefix)
{
    nv_pair_t *nv;

    nv = nv_table_lookup(xp2->uri2prefix, uri);
    if (nv != NULL) {
        /*
         * Silently ignore the mapping if we already have seen an identical one
         * in the XML tree during the first pass.
         */

        if (strcmp(prefix, nv_pair_value_str(nv)) != 0) {
            g_carp("XFMT ignoring supplied prefix '%s' for '%s': "
                   "already saw '%s' in the tree", prefix, uri,
                   nv_pair_value_str(nv));
        }
    } else {
        /*
         * New mapping.
         */

        nv = nv_pair_make_static_str(uri, prefix);
        nv_table_insert_pair(xp2->uri2prefix, nv);
    }
}
Example #2
0
/**
 * Record a tree-defined mapping between a prefix and a namespace URI.
 */
static void
xfmt_prefix_record(struct xfmt_pass1 *xp1, const char *prefix, const char *uri)
{
    nv_pair_t *nv;

    /*
     * Our policy is to use one single prefix for a given namespace URI
     * throughout the document.  Although several prefixes could be used.
     * this is confusing to read and serves no value: a human will be mislead
     * into thinking the two namespaces are different because they carry
     * distinct prefixes, and a machine will not care about the prefix value.
     */

    nv = nv_table_lookup(xp1->uri2prefix, uri);
    if (nv != NULL) {
        /*
         * Silently ignore the mapping if we already have seen an identical one
         * in the XML tree.
         */

        if (strcmp(prefix, nv_pair_value_str(nv)) != 0) {
            g_carp("XFMT ignoring prefix '%s' for '%s': "
                   "already saw '%s' earlier in the tree", prefix, uri,
                   nv_pair_value_str(nv));
        }
    } else {
        /*
         * New mapping.
         */

        nv = nv_pair_make_static_str(uri, prefix);
        nv_table_insert_pair(xp1->uri2prefix, nv);
    }
}
Example #3
0
/**
 * Add a port forwarding (*:ext_port -> addr:port) [IP or PPP connection].
 *
 * @param usd		the UPnP service to contact
 * @param proto		mapping protocol
 * @param ext_port	the mapped external port for which we want the mapping
 * @param int_addr	the internal client address
 * @param int_port	the internal port for which we want the mapping
 * @param desc		comment description
 * @param lease		lease duration (0 = permanent)
 * @param cb		callback to invoke when reply is available
 * @param arg		additional callback argument
 *
 * @return UPnP request handle if the SOAP RPC was initiated, NULL otherwise
 * (in which case callbacks will never be called).
 */
upnp_ctrl_t *
upnp_ctrl_AddPortMapping(const upnp_service_t *usd,
	enum upnp_map_proto proto, guint16 ext_port,
	host_addr_t int_addr, guint16 int_port,
	const char *desc, time_delta_t lease,
	upnp_ctrl_cb_t cb, void *arg)
{
	nv_pair_t *argv[8];
	char ext_port_buf[UINT16_DEC_BUFLEN];
	char int_port_buf[UINT16_DEC_BUFLEN];
	char int_addr_buf[HOST_ADDR_BUFLEN];
	char lease_buf[UINT32_DEC_BUFLEN];
	const char *protocol;
	const char *description;

	g_assert(lease >= 0);
	g_assert(lease <= MAX_INT_VAL(gint32));
	g_assert(ext_port != 0);
	g_assert(int_port != 0);

	int32_to_string_buf(ext_port, ext_port_buf, sizeof ext_port_buf);
	int32_to_string_buf(int_port, int_port_buf, sizeof int_port_buf);
	host_addr_to_string_buf(int_addr, int_addr_buf, sizeof int_addr_buf);
	protocol = upnp_map_proto_to_string(proto);
	int32_to_string_buf(lease, lease_buf, sizeof lease_buf);
	description = str_smsg("%s (%s)", desc, protocol);

	argv[0] = nv_pair_make_static_str(ARG_REMOTE_HOST, EMPTY);	/* Wildcard */
	argv[1] = nv_pair_make_static_str(ARG_EXTERNAL_PORT, ext_port_buf);
	argv[2] = nv_pair_make_static_str(ARG_PROTOCOL, protocol);
	argv[3] = nv_pair_make_static_str(ARG_INTERNAL_PORT, int_port_buf);
	argv[4] = nv_pair_make_static_str(ARG_INTERNAL_CLIENT, int_addr_buf);
	argv[5] = nv_pair_make_static_str(ARG_ENABLED, ONE);		/* Enable! */
	argv[6] = nv_pair_make_static_str(ARG_PORTMAP_DESC, description);
	argv[7] = nv_pair_make_static_str(ARG_LEASE_DURATION, lease_buf);

	/*
	 * TODO: when talking to a v2 WANIPConnection service, we can use
	 * the AddAnyPortMapping() call.  This will require that GTKG maintains
	 * knowledge about the remote port so that it can advertise that remote
	 * port instead of the local listening port.
	 *
	 * Attempts must be made to get the same external port for both TCP and UDP,
	 * or this will create problems to servents assuming that they will always
	 * be identical (like GTKG does when it uses the TCP listening port of
	 * a remote host to send a push-proxy request via UDP)..
	 *		--RAM, 2011-01-18
	 */

	return upnp_ctrl_launch(usd, "AddPortMapping",
		argv, G_N_ELEMENTS(argv), cb, arg,
		NULL);
}
Example #4
0
/**
 * Get information about a specific port mapping [IP or PPP connection].
 *
 * @param usd		the UPnP service to contact
 * @param proto		mapping protocol
 * @param port		the mapped external port for which we want the mapping
 * @param cb		callback to invoke when reply is available
 * @param arg		additional callback argument
 *
 * @return UPnP request handle if the SOAP RPC was initiated, NULL otherwise
 * (in which case callbacks will never be called).
 */
upnp_ctrl_t *
upnp_ctrl_GetSpecificPortMappingEntry(const upnp_service_t *usd,
	enum upnp_map_proto proto, guint16 port,
	upnp_ctrl_cb_t cb, void *arg)
{
	nv_pair_t *argv[3];
	char buf[UINT16_DEC_BUFLEN];
	const char *protocol;

	int32_to_string_buf(port, buf, sizeof buf);
	protocol = upnp_map_proto_to_string(proto);

	argv[0] = nv_pair_make_static_str(ARG_REMOTE_HOST, EMPTY);	/* Wildcard */
	argv[1] = nv_pair_make_static_str(ARG_EXTERNAL_PORT, buf);
	argv[2] = nv_pair_make_static_str(ARG_PROTOCOL, protocol);

	return upnp_ctrl_launch(usd, "GetSpecificPortMappingEntry",
		argv, G_N_ELEMENTS(argv), cb, arg,
		upnp_ctrl_ret_GetSpecificPortMappingEntry);
}
Example #5
0
/**
 * Declare association between a prefix and a namespace URI at
 * the current depth.
 *
 * @param xp2			the pass 2 context
 * @param prefix		declared prefix string
 * @param uri			namespace URI
 * @param free_prefix	whether the prefix string will have to be freed
 */
static void
xfmt_ns_declare(struct xfmt_pass2 *xp2,
                const char *prefix, const char *uri, bool free_prefix)
{
    nv_pair_t *nv;
    bool inserted;

    /*
     * The prefix string is shared between the two symbol tables, and is
     * optionally freed when the pair is removed from the uris table.
     * Therefore, removal must be done on the prefixes symbol table first.
     */

    nv = nv_pair_make_static_str(prefix, uri);
    inserted = symtab_insert_pair(xp2->prefixes, nv, xp2->depth);
    g_assert(inserted);

    nv = nv_pair_make_static_str(uri, prefix);
    if (free_prefix)
        nv_pair_set_value_free(nv, xfmt_nv_free);
    inserted = symtab_insert_pair(xp2->uris, nv, xp2->depth);
    g_assert(inserted);
}
Example #6
0
/**
 * Successful SOAP RPC reply callback.
 *
 * @param sr	the SOAP RPC request
 * @param root	XML tree of SOAP reply
 * @param arg	the UPnP control request
 */
static void
upnp_ctrl_soap_reply(const soap_rpc_t *sr, xnode_t *root, void *arg)
{
	upnp_ctrl_t *ucd = arg;
	xnode_t *xn;
	nv_table_t *nvt;
	void *reply;
	size_t reply_len;
	host_addr_t local_addr;
	int code;

	upnp_ctrl_check(ucd);

	if (GNET_PROPERTY(upnp_debug) > 1) {
		g_debug("UPNP got SOAP reply for %s", ucd->action);

		if (GNET_PROPERTY(upnp_debug) > 2)
			xfmt_tree_dump(root, stderr);
	}

	ucd->sr = NULL;		/* Done with SOAP request */

	if (soap_rpc_local_addr(sr, &local_addr))
		upnp_set_local_addr(local_addr);

	/*
	 * Decompile the returned values.
	 *
	 * <u:actionResponse xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
	 *	 <arg1>out value1</arg1>
	 *	 <arg2>out value2</arg2>
	 *       :  :  :  :
	 *   <argn>out valuen</argn>
	 * </u:actionResponse>
	 *
	 * Values are inserted in name / value pairs: "arg1" -> "out value 1" and
	 * given to the launch callback for extracting and decompiling the values.
	 */

	nvt = nv_table_make(TRUE);

	for (xn = xnode_first_child(root); xn; xn = xnode_next_sibling(xn)) {
		nv_pair_t *nv;
		xnode_t *xt;

		if (!xnode_is_element(xn)) {
			if (GNET_PROPERTY(upnp_debug)) {
				g_warning("UPNP \"%s\" skipping XML node %s",
					ucd->action, xnode_to_string(xn));
			}
			continue;
		}

		xt = xnode_first_child(xn);

		if (NULL == xt || !xnode_is_text(xt)) {
			if (GNET_PROPERTY(upnp_debug)) {
				g_warning("UPNP \"%s\" bad child node %s in %s",
					ucd->action, xnode_to_string(xt), xnode_to_string2(xn));
			}
		} else {
			/*
			 * Name/value strings point in the tree, which is going to be
			 * alive for the duration of the processing, so we can use the
			 * strings without copying them.
			 */

			nv = nv_pair_make_static_str(
				xnode_element_name(xn), xnode_text(xt));

			nv_table_insert_pair(nvt, nv);

			if (xnode_next_sibling(xt) != NULL) {
				if (GNET_PROPERTY(upnp_debug)) {
					g_warning("UPNP \"%s\" content of %s is not pure text",
						ucd->action, xnode_to_string(xt));
				}
			}
		}
	}

	/*
	 * Attempt to decompile the replied values, if any are expected.
	 *
	 * Allocated data is done via walloc(), and the returned structure is flat.
	 * It will be freed after invoking the user callback.
	 */

	if (ucd->lcb != NULL) {
		reply = (*ucd->lcb)(nvt, &reply_len);
		code = NULL == reply ? UPNP_ERR_OK : UPNP_ERR_BAD_REPLY;
	} else {
		code = UPNP_ERR_OK;
		reply = NULL;
		reply_len = 0;
	}

	/*
	 * Let UPnP control invoker know about the result of the query.
	 */

	(*ucd->cb)(code, reply, reply_len, ucd->cb_arg);

	/*
	 * Done, final cleanup.
	 */

	WFREE_NULL(reply, reply_len);
	nv_table_free(nvt);
	upnp_ctrl_free(ucd);
}