예제 #1
0
static void
upload_stats_add(const char *pathname, filesize_t size, const char *name,
	guint32 attempts, guint32 complete, guint64 ul_bytes,
	time_t rtime, time_t dtime, const struct sha1 *sha1)
{
	static const struct ul_stats zero_stats;
	struct ul_stats *s;

	g_assert(pathname != NULL);
	g_assert(name != NULL);

	WALLOC(s);
	*s = zero_stats;
	s->pathname = atom_str_get(pathname);
	s->filename = atom_str_get(name);
	s->size = size;
	s->attempts = attempts;
	s->complete = complete;
	s->norm = size > 0 ? 1.0 * ul_bytes / size : 0.0;
	s->bytes_sent = ul_bytes;
	s->rtime = rtime;
	s->dtime = dtime;
	s->sha1 = sha1 ? atom_sha1_get(sha1) : NULL;

	if (!upload_stats_list) {
		g_assert(!upload_stats_by_sha1);
		upload_stats_list = hash_list_new(ul_stats_hash, ul_stats_eq);
		upload_stats_by_sha1 = g_hash_table_new(sha1_hash, sha1_eq);
	}
	hash_list_append(upload_stats_list, s);
	if (s->sha1)
		gm_hash_table_insert_const(upload_stats_by_sha1, s->sha1, s);
	gcu_upload_stats_gui_add(s);
}
예제 #2
0
/**
 * Allocate a new attribute key/value.
 *
 * @param uri		the namespace URI (may be NULL)
 * @param local		the local name
 * @param value		the attribute value (copied)
 *
 * @return a new attribute key/value.
 */
static struct xattr *
xattr_alloc(const char *uri, const char *local, const char *value)
{
	struct xattr *xa;

	WALLOC(xa);
	xa->uri = (NULL == uri) ? NULL : atom_str_get(uri);
	xa->local = atom_str_get(local);
	xa->value = h_strdup(value);

	return xa;
}
예제 #3
0
/**
 * Allocate a new service description.
 *
 * The control URL is copied.
 *
 * @param type		service type
 * @param version	service version number
 * @param ctrl_url	control URL
 * @param scpd_url	SCPD URL
 */
static upnp_service_t *
upnp_service_alloc(enum upnp_service_type type, unsigned version,
	const char *ctrl_url, const char *scpd_url)
{
	upnp_service_t *usd;

	WALLOC0(usd);
	usd->magic = UPNP_SVC_DESC_MAGIC;
	usd->type = type;
	usd->version = version;
	usd->control_url = atom_str_get(ctrl_url);
	usd->scpd_url = atom_str_get(scpd_url);

	return usd;
}
예제 #4
0
/**
 * Create a new element tag node, inserted under parent node as the last child.
 *
 * @param parent		the parent node (NULL creates a standalone node)
 * @param ns			the namespace URI (NULL if none)
 * @param name			the element's name (copied)
 */
xnode_t *
xnode_new_element(xnode_t *parent, const char *ns, const char *name)
{
	xnode_t *xn;

	g_assert(name != NULL);

	xn = xnode_new(XNODE_T_ELEMENT);
	xn->u.e.name = atom_str_get(name);
	xn->u.e.ns_uri = NULL == ns ? NULL : atom_str_get(ns);

	if (parent != NULL)
		xnode_add_child(parent, xn);

	return xn;
}
예제 #5
0
static struct file_object *
file_object_alloc(const int fd, const char * const pathname, int accmode)
{
    static const struct file_object zero_fo;
    struct file_object *fo;
    hikset_t *ht;

    g_return_val_if_fail(fd >= 0, NULL);
    g_return_val_if_fail(pathname, NULL);
    g_return_val_if_fail(is_absolute_path(pathname), NULL);
    g_return_val_if_fail(!file_object_find(pathname, accmode), NULL);

    ht = file_object_mode_get_table(accmode);
    g_return_val_if_fail(ht, NULL);

    WALLOC(fo);
    *fo = zero_fo;
    fo->magic = FILE_OBJECT_MAGIC;
    fo->ref_count = 1;
    fo->fd = fd;
    fo->accmode = accmode;
    fo->pathname = atom_str_get(pathname);

    file_object_check(fo);
    g_assert(is_valid_fd(fo->fd));
    hikset_insert(ht, fo);

    return fo;
}
예제 #6
0
파일: nodes.c 프로젝트: lucab/gtk-gnutella
/**
 * Adds the given node to the gui.
 */
void
nodes_gui_add_node(gnet_node_info_t *info)
{
	static const struct node_data zero_data;
	struct node_data *data;
	gnet_node_flags_t flags;

    g_return_if_fail(info);
	g_return_if_fail(!htable_contains(nodes_handles, info->node_id));

	WALLOC(data);
	*data = zero_data;

	data->node_id = nid_ref(info->node_id);
	data->user_agent = info->vendor ? atom_str_get(info->vendor) : NULL;
	data->country = info->country;
	data->host_size = w_concat_strings(&data->host,
						host_addr_port_to_string(info->addr, info->port),
						(void *) 0);
	str_bprintf(data->version, sizeof data->version, "%u.%u",
		info->proto_major, info->proto_minor);

	guc_node_fill_flags(data->node_id, &flags);
	nodes_gui_update_node_flags(data, &flags);

	htable_insert(nodes_handles, data->node_id, data);

    gtk_list_store_append(nodes_model, &data->iter);
    gtk_list_store_set(nodes_model, &data->iter, 0, data, (-1));

}
예제 #7
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
static struct magnet_source *
magnet_parse_location(const char *uri, const char **error_str)
{
	struct magnet_source *ms;
	const char *p, *host, *host_end;
	host_addr_t addr;
	uint16 port;

	clear_error_str(&error_str);
	g_return_val_if_fail(uri, NULL);

	p = uri;

	p = magnet_parse_host_port(uri, &addr, &port, &host, &host_end, error_str);
	if (NULL == p)
		return NULL;

	ms = magnet_parse_path(p, error_str);
	if (NULL == ms)
		return NULL;

	if (host) {
		char *h = h_strndup(host, host_end - host);
		ms->hostname = atom_str_get(h);
		HFREE_NULL(h);
	}

	ms->addr = addr;
	ms->port = port;

	return ms;
}
예제 #8
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
void
magnet_add_search(struct magnet_resource *res, const char *search)
{
	g_return_if_fail(res);
	g_return_if_fail(search);

	res->searches = g_slist_prepend(res->searches,
						deconstify_gchar(atom_str_get(search)));
}
예제 #9
0
/**
 * Prepare reception of query hit data by building an appropriate RX stack.
 *
 * @return TRUE if we may continue with the download, FALSE if the search
 * was already closed in the GUI.
 */
gboolean
browse_host_dl_receive(
	struct browse_ctx *bc, gnet_host_t *host, wrap_io_t *wio,
	const char *vendor, guint32 flags)
{
	g_assert(bc != NULL);

	if (bc->closed)
		return FALSE;

	gnet_host_copy(&bc->host, host);
	bc->vendor = atom_str_get(vendor);

	/*
	 * Freeing of the RX stack must be asynchronous: each time we establish
	 * a new connection, dismantle the previous stack.  Otherwise the RX
	 * stack will be freed when the corresponding download structure is
	 * reclaimed.
	 */

	if (bc->rx != NULL) {
		rx_free(bc->rx);
		bc->rx = NULL;
	}

	{
		struct rx_link_args args;

		args.cb = &browse_rx_link_cb;
		args.bws = bsched_in_select_by_addr(gnet_host_get_addr(&bc->host));
		args.wio = wio;

		bc->rx = rx_make(bc, &bc->host, rx_link_get_ops(), &args);
	}

	if (flags & BH_DL_CHUNKED) {
		struct rx_chunk_args args;

		args.cb = &browse_rx_chunk_cb;

		bc->rx = rx_make_above(bc->rx, rx_chunk_get_ops(), &args);
	}

	if (flags & BH_DL_INFLATE) {
		struct rx_inflate_args args;

		args.cb = &browse_rx_inflate_cb;

		bc->rx = rx_make_above(bc->rx, rx_inflate_get_ops(), &args);
	}

	rx_set_data_ind(bc->rx, browse_data_ind);
	rx_enable(bc->rx);

	return TRUE;
}
예제 #10
0
/**
 * Create a new namesize structure.
 */
namesize_t *
namesize_make(const char *name, filesize_t size)
{
	namesize_t *ns;

	WALLOC(ns);
	ns->name = atom_str_get(name);
	ns->size = size;

	return ns;
}
예제 #11
0
static struct uhc *
uhc_new(const char *host)
{
	struct uhc *uhc;

	g_assert(host != NULL);

	WALLOC0(uhc);
	uhc->host = atom_str_get(host);
	return uhc;
}
예제 #12
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
/**
 * Record given string magnet resource at the supplied location.
 */
static void
magnet_resource_set_string(const char **p, const char *str)
{
	const char *atom;

	g_return_if_fail(p);
	g_return_if_fail(str);

	atom = atom_str_get(str);
	atom_str_free_null(p);
	*p = atom;
}
예제 #13
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
void
magnet_add_source_by_url(struct magnet_resource *res, const char *url)
{
	struct magnet_source *s;

	g_return_if_fail(res);
	g_return_if_fail(url);

	s = magnet_source_new();
	s->url = atom_str_get(url);
	magnet_add_source(res, s);
}
예제 #14
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
void
magnet_set_display_name(struct magnet_resource *res, const char *name)
{
	const char *atom;

	g_return_if_fail(res);
	g_return_if_fail(name);

	atom = atom_str_get(name);
	atom_str_free_null(&res->display_name);
	res->display_name = atom;
}
예제 #15
0
파일: ghc.c 프로젝트: graaff/gtk-gnutella
/**
 * Create a new GHC.
 */
static struct ghc *
ghc_new(const char *url)
{
	struct ghc *ghc;

	g_assert(url != NULL);

	WALLOC0(ghc);
	ghc->url = atom_str_get(url);
	ghc->stamp = 0;
	ghc->used = 0;

	return ghc;
}
예제 #16
0
파일: huge.c 프로젝트: lucab/gtk-gnutella
/**
 * Add a new entry to the in-memory cache.
 */
static void
add_volatile_cache_entry(const char *filename, filesize_t size, time_t mtime,
	const struct sha1 *sha1, const struct tth *tth, bool known_to_be_shared)
{
	struct sha1_cache_entry *item;
   
	WALLOC(item);
	item->file_name = atom_str_get(filename);
	item->size = size;
	item->mtime = mtime;
	item->sha1 = atom_sha1_get(sha1);
	item->tth = tth ? atom_tth_get(tth) : NULL;
	item->shared = known_to_be_shared;
	hikset_insert_key(sha1_cache, &item->file_name);
}
예제 #17
0
/**
 * Register new file to be monitored.
 *
 * If the file was already monitored, cancel the previous monitoring action
 * and replace it with this one.
 *
 * @param filename the file to monitor (string duplicated)
 * @param cb the callback to invoke when the file changes
 * @param udata extra data to pass to the callback, along with filename
 */
void
watcher_register(const char *filename, watcher_cb_t cb, void *udata)
{
	struct monitored *m;

	WALLOC0(m);
	m->filename = atom_str_get(filename);
	m->cb = cb;
	m->udata = udata;
	m->mtime = watcher_mtime(filename);

	if (hikset_contains(monitored, filename))
		watcher_unregister(filename);

	hikset_insert_key(monitored, &m->filename);
}
예제 #18
0
/**
 * Ensures that we have a valid `gwc_current_url' or pick a new one.
 * Also force change a the current URL after too many uses.
 *
 * @return TRUE if we got a valid URL.
 */
static bool
gwc_check_current_url(void)
{
    if (gwc_current_url == NULL || gwc_current_reused >= MAX_GWC_REUSE) {
        /*
         * `gwc_current_url' must be an atom since we may replace the value
         * in the cache at any time: we could be using a cache even after
         * its entry has been superseded.
         */
        const char *ptr = gwc_pick();

        atom_str_free_null(&gwc_current_url);
        gwc_current_url = ptr == NULL ? NULL : atom_str_get(ptr);
        gwc_current_reused = 0;
    } else
        gwc_current_reused++;

    return gwc_current_url != NULL;
}
예제 #19
0
파일: wd.c 프로젝트: MrJoe/gtk-gnutella
/**
 * Create a new watchdog.
 *
 * @param name		the watchdog name, for logging purposes
 * @param period	the period after which it triggers, in seconds
 * @param trigger	the callback to invoke if no kicking during period
 * @param arg		the user-supplied argument given to callback
 * @param start		whether to start immediately, or put in sleep state
 *
 * @return the created watchdog object.
 */
watchdog_t *
wd_make(const char *name, int period,
	wd_trigger_t trigger, void *arg, bool start)
{
	watchdog_t *wd;

	WALLOC0(wd);
	wd->magic = WATCHDOG_MAGIC;
	wd->name = atom_str_get(name);
	wd->period = period;
	wd->trigger = trigger;
	wd->arg = arg;

	if (start)
		wd_start(wd);

	watchdog_check(wd);
	return wd;
}
예제 #20
0
/**
 * Insert an item into the search_table
 * one-char strings are silently ignored.
 *
 * @return TRUE if the item was inserted; FALSE otherwise.
 */
gboolean
st_insert_item(search_table_t *table, const char *s, const shared_file_t *sf)
{
	size_t i, len;
	struct st_entry *entry;
	GHashTable *seen_keys;

	len = utf8_char_count(s);
	if ((size_t) -1 == len || len < 2)
		return FALSE;

	seen_keys = g_hash_table_new(NULL, NULL);

	WALLOC(entry);
	entry->string = atom_str_get(s);
	entry->sf = shared_file_ref(sf);
	entry->mask = mask_hash(entry->string);

	len = strlen(entry->string);
	for (i = 0; i < len - 1; i++) {
		int key = st_key(table, &entry->string[i]);

		/* don't insert item into same bin twice */
		if (g_hash_table_lookup(seen_keys, GINT_TO_POINTER(key)))
			continue;

		g_hash_table_insert(seen_keys, GINT_TO_POINTER(key),
			GINT_TO_POINTER(1));

		g_assert(key < table->nbins);
		if (table->bins[key] == NULL)
			table->bins[key] = bin_allocate();

		bin_insert_item(table->bins[key], entry);
	}
	bin_insert_item(&table->all_entries, entry);
	table->nentries++;

	g_hash_table_destroy(seen_keys);
	return TRUE;
}
예제 #21
0
파일: nodes.c 프로젝트: lucab/gtk-gnutella
/**
 * Updates vendor, version and info column.
 */
static void
nodes_gui_update_node_info(struct node_data *data, gnet_node_info_t *info)
{
    gnet_node_status_t status;

    g_assert(info != NULL);

    if (data == NULL)
        data = find_node(info->node_id);

	g_assert(NULL != data);
	g_assert(data->node_id == info->node_id);

    if (guc_node_get_status(info->node_id, &status)) {
		str_bprintf(data->version, sizeof data->version, "%u.%u",
				info->proto_major, info->proto_minor);
		atom_str_free_null(&data->user_agent);
		data->user_agent = info->vendor ? atom_str_get(info->vendor) : NULL;
		data->country = info->country;
	}
}
예제 #22
0
/**
 * Create a new formatting context for a header line.
 *
 * @param `field' is the header field name, without trailing ':'.
 *
 * @param `separator' is the optional default separator to emit between
 * the values added via header_fmd_append_value().  To supersede the
 * default separator, use header_fmd_append() and specify another separator
 * explicitly.  If set to NULL, there will be no default separator and
 * values will be simply concatenated together.  The value given must
 * NOT be freed before the header_fmt_end() call (usually it will just
 * be a static string).  Trailing spaces in the separator will be stripped
 * if it is emitted at the end of a line before a continuation.
 *
 * @param `len_hint' is the expected line size, for pre-sizing purposes.
 * (0 to guess).
 *
 * @param `max_size' is the maximum header size, including the final "\r\n"
 * and the trailing NUL.  If the initial field name is larger than the
 * configured maximum size, the header field will remain completely empty.
 *
 * @return pointer to the formatting object.
 */
header_fmt_t *
header_fmt_make(const char *field, const char *separator,
	size_t len_hint, size_t max_size)
{
	struct header_fmt *hf;

	g_assert(size_is_non_negative(len_hint));

	WALLOC(hf);
	hf->magic = HEADER_FMT_MAGIC;
	hf->header = str_new(len_hint ? len_hint : HEADER_FMT_DFLT_LEN);
	hf->maxlen = HEADER_FMT_LINE_LEN;
	hf->data_emitted = FALSE;
	hf->frozen = FALSE;
	hf->max_size = max_size;
	hf->sep = atom_str_get(separator ? separator : "");
	hf->seplen = strlen(hf->sep);
	hf->stripped_seplen = stripped_strlen(hf->sep, hf->seplen);
	str_cat(hf->header, field);
	STR_CAT(hf->header, ": ");

	hf->current_len = str_len(hf->header);

	/*
	 * If right from the start the header would be larger than the configured
	 * size, force it to stay empty.  That means, the final string returned
	 * will be "", the empty string.
	 */

	if (str_len(hf->header) + sizeof("\r\n") > hf->max_size) {
		hf->empty = TRUE;
		str_setlen(hf->header, 0);
	} else {
		hf->empty = FALSE;
	}

	header_fmt_check(hf);

	return hf;
}
예제 #23
0
파일: cq.c 프로젝트: MrJoe/gtk-gnutella
/**
 * Initialize newly created callout queue object.
 *
 * @param name		queue name, for logging
 * @param now		virtual current time -- use 0 if not important
 * @param period	period between heartbeats, in ms
 *
 * @return the initialized object
 */
static cqueue_t *
cq_initialize(cqueue_t *cq, const char *name, cq_time_t now, int period)
{
	/*
	 * The cq_hash hash list is used to speed up insert/delete operations.
	 */

	cq->cq_magic = CQUEUE_MAGIC;
	cq->cq_name = atom_str_get(name);
	XMALLOC0_ARRAY(cq->cq_hash, HASH_SIZE);
	cq->cq_items = 0;
	cq->cq_ticks = 0;
	cq->cq_time = now;
	cq->cq_last_bucket = EV_HASH(now);
	cq->cq_current = NULL;
	cq->cq_period = period;
	mutex_init(&cq->cq_lock);
	mutex_init(&cq->cq_idle_lock);

	cqueue_check(cq);
	return cq;
}
예제 #24
0
/**
 * Add a new upload stats row to the model.
 *
 * Add the information within the ul_stats structure
 * to the GtkTreeModel and another row the the
 * upload statistics pane.
 *
 * @param us A ul_stats structure with new upload stats to add.
 *
 */
void
upload_stats_gui_add(struct ul_stats *us)
{
	struct upload_data *data;
    GtkListStore *store;

	g_assert(us != NULL);

	upload_stats_gui_init_intern(TRUE);
	store = GTK_LIST_STORE(gtk_tree_view_get_model(upload_stats_treeview));
	g_return_if_fail(store);
	g_return_if_fail(!htable_contains(ht_uploads, us));

	WALLOC(data);
	data->us = us;

	data->filename = atom_str_get(us->filename);
	htable_insert(ht_uploads, data->us, data);

	gtk_list_store_append(store, &data->iter);
    gtk_list_store_set(store, &data->iter, 0, data, (-1));
}
예제 #25
0
파일: adns.c 프로젝트: lucab/gtk-gnutella
/**
 * Adds ``hostname'' and ``addr'' to the cache. The cache is implemented
 * as a wrap-around FIFO. In case it's full, the oldest entry will be
 * overwritten.
 */
static void
adns_cache_add(adns_cache_t *cache, time_t now,
	const char *hostname, const host_addr_t *addrs, size_t n)
{
	adns_cache_entry_t *entry;
	size_t i;
	
	g_assert(NULL != addrs);
	g_assert(NULL != cache);
	g_assert(NULL != hostname);
	g_assert(n > 0);

	g_assert(!hikset_contains(cache->ht, hostname));
	g_assert(cache->pos < G_N_ELEMENTS(cache->entries));
	
	entry = adns_cache_get_entry(cache, cache->pos);
	if (entry) {
		g_assert(entry->hostname);
		g_assert(entry == hikset_lookup(cache->ht, entry->hostname));

		hikset_remove(cache->ht, entry->hostname);
		adns_cache_free_entry(cache, cache->pos);
		entry = NULL;
	}

	entry = walloc(adns_cache_entry_size(n));
	entry->n = n;
	entry->hostname = atom_str_get(hostname);
	entry->timestamp = now;
	entry->id = cache->pos;
	for (i = 0; i < entry->n; i++) {
		entry->addrs[i] = addrs[i];
	}
	hikset_insert_key(cache->ht, &entry->hostname);
	cache->entries[cache->pos++] = entry;
	cache->pos %= G_N_ELEMENTS(cache->entries);
}
예제 #26
0
파일: magnet.c 프로젝트: MrJoe/gtk-gnutella
static struct magnet_source *
magnet_parse_path(const char *path, const char **error_str)
{
	static const struct magnet_source zero_ms;
	struct magnet_source ms;
	const char *p, *endptr;

	clear_error_str(&error_str);
	g_return_val_if_fail(path, NULL);

	ms = zero_ms;
	p = path;

	if ('/' != *p) {
		*error_str = "Expected path starting with '/'";
		/* Skip this parameter */
		return NULL;
	}
	g_assert(*p == '/');

	endptr = is_strprefix(p, "/uri-res/N2R?");
	if (endptr) {
		struct sha1 sha1;
		
		p = endptr;
		if (!urn_get_sha1(p, &sha1)) {
			*error_str = "Bad SHA1 in MAGNET URI";
			return NULL;
		}
		ms.sha1 = atom_sha1_get(&sha1);
	} else {
		ms.path = atom_str_get(p);
	}

	return wcopy(&ms, sizeof ms);
}
예제 #27
0
파일: soap.c 프로젝트: Haxe/gtk-gnutella
/**
 * Initiate a SOAP remote procedure call.
 *
 * Call will be launched asynchronously, not immediately upon return so that
 * callbacks are never called on the same stack frame and to allow further
 * options to be set on the handle before the call begins.
 *
 * Initially the request is sent as a regular POST.  It is possible to force
 * the usage of the HTTP Extension Framework by using the SOAP_RPC_O_MAN_FORCE
 * option, in which case an M-POST will be sent with the proper SOAP Man:
 * header.  Finally, automatic retry of the request can be requested via the
 * SOAP_RPC_O_MAN_RETRY option: it will start with POST and switch to M-POST
 * on 405 or 510 errors.
 *
 * @param url		the HTTP URL to contact for the RPC
 * @param action	the SOAP action to perform
 * @param maxlen	maximum length of data we accept to receive
 * @param options	user-supplied options
 * @param xn		SOAP RPC data payload (XML tree root, will be freed)
 * @param soap_ns	requested SOAP namespace prefix, NULL to use default
 * @param reply_cb	callback to invoke when we get a reply
 * @param error_cb	callback to invoke on error
 * @param arg		additional user-defined callback parameter
 *
 * @return a SOAP RPC handle, NULL if the request cannot be initiated (XML
 * payload too large).  In any case, the XML tree is freed.
 */
soap_rpc_t *
soap_rpc(const char *url, const char *action, size_t maxlen, guint32 options,
	xnode_t *xn, const char *soap_ns,
	soap_reply_cb_t reply_cb, soap_error_cb_t error_cb, void *arg)
{
	soap_rpc_t *sr;
	xnode_t *root, *body;
	pmsg_t *mb;
	ostream_t *os;
	gboolean failed = FALSE;

	g_assert(url != NULL);
	g_assert(action != NULL);

	/*
	 * Create the SOAP XML request.
	 */

	root = xnode_new_element(NULL, SOAP_NAMESPACE, SOAP_X_ENVELOPE);
	xnode_add_namespace(root, soap_ns ? soap_ns : "SOAP", SOAP_NAMESPACE);
	xnode_prop_ns_set(root, SOAP_NAMESPACE, SOAP_X_ENC_STYLE, SOAP_ENCODING);

	body = xnode_new_element(root, SOAP_NAMESPACE, SOAP_X_BODY);
	xnode_add_child(body, xn);

	/*
	 * Serialize the XML tree to a PDU message buffer.
	 */

	mb = pmsg_new(PMSG_P_DATA, NULL, SOAP_MAX_PAYLOAD);
	os = ostream_open_pmsg(mb);
	xfmt_tree(root, os, XFMT_O_NO_INDENT);

	if (!ostream_close(os)) {
		failed = TRUE;
		g_warning("SOAP unable to serialize payload within %d bytes",
			SOAP_MAX_PAYLOAD);
		if (GNET_PROPERTY(soap_debug) > 1)
			xfmt_tree_dump(root, stderr);
	}

	/*
	 * Free the XML tree, including the supplied user nodes.
	 */

	xnode_tree_free(root);

	if (failed) {
		pmsg_free(mb);
		return NULL;
	}

	/*
	 * Serialization of the XML payload was successful, prepare the
	 * asynchronous SOAP request.
	 */

	sr = soap_rpc_alloc();
	sr->url = atom_str_get(url);
	sr->action = atom_str_get(action);
	sr->maxlen = maxlen;
	sr->content_len = maxlen;		/* Until we see a Content-Length */
	sr->options = options;
	sr->mb = mb;
	sr->reply_cb = reply_cb;
	sr->error_cb = error_cb;
	sr->arg = arg;

	/*
	 * Make sure the error callback is not called synchronously, and give
	 * them time to supply other options after creating the request before
	 * it starts.
	 */

	sr->delay_ev = cq_main_insert(1, soap_rpc_launch, sr);

	return sr;
}
예제 #28
0
/**
 * Launch UPnP control request.
 *
 * The argv[] vector (with argc entries) contains the arguments and their
 * values to send to the remote UPnP device.
 *
 * If a structured reply is expected (and not just a returned status code),
 * a launch_cb callback must be provided to process the arguments returned
 * by the control request and populate a structure that will be passed to the
 * user callback to propagate the result of the control request.
 *
 * @param usd		the service to contact
 * @param action	the action to request
 * @param argv		the argument list for the request
 * @param argc		amount of arguments in argv[]
 * @param cb		user-callback when action is completed
 * @param cb_arg	additional callback argument
 * @param launch_cb	internal launch callback invoked on SOAP reply
 *
 * @return UPnP request handle if the SOAP RPC was initiated, NULL otherwise
 * (in which case callbacks will never be called).
 */
static upnp_ctrl_t *
upnp_ctrl_launch(const upnp_service_t *usd, const char *action,
	nv_pair_t **argv, size_t argc, upnp_ctrl_cb_t cb, void *cb_arg,
	upnp_ctrl_launch_cb_t launch_cb)
{
	upnp_ctrl_t *ucd;
	xnode_t *root;
	size_t i;
	soap_rpc_t *sr;

	g_assert(usd != NULL);
	g_assert(action != NULL);
	g_assert(0 == argc || argv != NULL);

	WALLOC0(ucd);
	ucd->magic = UPNP_CTRL_MAGIC;
	ucd->lcb = launch_cb;
	ucd->cb = cb;
	ucd->cb_arg = cb_arg;

	/*
	 * The root element of the UPnP request.
	 *
	 * Its serialized form looks like this:
	 *
	 * <u:action xmlns:u="urn:schemas-upnp-org:service:serviceType:v">
	 *	 <arg1>in value1</arg1>
	 *	 <arg2>in value2</arg2>
	 *       :  :  :  :
	 *   <argn>in valuen</argn>
	 * </u:action>
	 *
	 * The "u" prefix is arbitrary but it is the one used in all examples
	 * presented in the UPnP architecture, and naive implementations within
	 * devices could choke on anything else.
	 */

	{
		char ns[256];
		
		gm_snprintf(ns, sizeof ns, "%s%s:%u",
			UPNP_NS_BASE,
			upnp_service_type_to_string(upnp_service_type(usd)),
			upnp_service_version(usd));

		root = xnode_new_element(NULL, ns, action);
		xnode_add_namespace(root, UPNP_PREFIX, ns);
	}

	/*
	 * Attach each argument to the root.
	 */

	for (i = 0; i < argc; i++) {
		nv_pair_t *nv = argv[i];
		xnode_t *xargs;

		xargs = xnode_new_element(root, NULL, nv_pair_name(nv));
		xnode_new_text(xargs, nv_pair_value_str(nv), FALSE);
	}

	/*
	 * Launch the SOAP RPC.
	 *
	 * We force "s" as the SOAP prefix.  It shouldn't matter at all, but
	 * since the UPnP architecture documents its examples with "s", naive
	 * implementations in devices could choke on anything else.
	 *
	 * Likewise, since the UPnP architecture document uses all-caps HTTP header
	 * names, we can expect that some implementations within devices will
	 * not properly understand headers spelt with traditional mixed-cased,
	 * although it mentions that headers are case-insensitive names.  Hence,
	 * force all-caps header names.
	 *
	 * If the SOAP RPC cannot be launched (payload too large), the XML tree
	 * built above was freed anyway.
	 */

	{
		char action_uri[256];
		guint32 options = SOAP_RPC_O_MAN_RETRY | SOAP_RPC_O_ALL_CAPS;

		/*
		 * Grab our local IP address if it is unknown so far.
		 */

		if (host_addr_net(upnp_get_local_addr()) == NET_TYPE_NONE)
			options |= SOAP_RPC_O_LOCAL_ADDR;

		gm_snprintf(action_uri, sizeof action_uri, "%s#%s",
			xnode_element_ns(root), action);

		ucd->action = atom_str_get(action_uri);

		sr = soap_rpc(upnp_service_control_url(usd), action_uri,
			UPNP_REPLY_MAXSIZE, options, root, UPNP_SOAP_PREFIX,
			upnp_ctrl_soap_reply, upnp_ctrl_soap_error, ucd);
	}

	/*
	 * We no longer need the arguments.
	 */

	for (i = 0; i < argc; i++) {
		nv_pair_free_null(&argv[i]);
	}

	/*
	 * Cleanup if we were not able to launch the request because the
	 * serialized XML payload is too large.
	 */

	if (NULL == sr) {
		if (GNET_PROPERTY(upnp_debug)) {
			g_warning("UPNP SOAP RPC \"%s\" to \"%s\" not launched: "
				"payload is too large", action, upnp_service_control_url(usd));
		}
		upnp_ctrl_free(ucd);
		return NULL;
	}

	ucd->sr = sr;		/* So that we may cancel it if needed */

	return ucd;
}
예제 #29
0
/**
 * Locate statistics structure for the file.
 *
 * If a SHA1 is given, we search by SHA1. Otherwise we search by (name, size)
 * and if the record is missing the SHA1, probably because it was not
 * available at the time of insertion, then it is added to the structure
 * and recorded as such.
 */
static struct ul_stats *
upload_stats_find(const struct sha1 *sha1, const char *pathname, guint64 size)
{
	struct ul_stats *s = NULL;

	if (upload_stats_list) {
		static const struct ul_stats zero_stats;
		struct ul_stats key;
		gconstpointer orig_key;

		g_assert(upload_stats_by_sha1);

		if (sha1) {
			s = g_hash_table_lookup(upload_stats_by_sha1, sha1);
			if (s)
				goto done;		/* Found it by SHA1 */
		}

		key = zero_stats;
		key.pathname = atom_str_get(pathname);
		key.size = size;

		if (hash_list_find(upload_stats_list, &key, &orig_key))
			s = deconstify_gpointer(orig_key);
		atom_str_free_null(&key.pathname);

		if (s && sha1) {
			/* Was missing from the by-SHA1 table */
			if (NULL == s->sha1) {
				/* SHA1 was unknown */

				s->sha1 = atom_sha1_get(sha1);
			} else {
				/* SHA1 changed, file was modified */
				struct ul_stats *old =
					g_hash_table_lookup(upload_stats_by_sha1, s->sha1);

				g_assert(old == s);		/* Must be the same filename entry */

				g_hash_table_remove(upload_stats_by_sha1, s->sha1);
				atom_sha1_free(s->sha1);
				s->sha1 = atom_sha1_get(sha1);
			}
			gm_hash_table_insert_const(upload_stats_by_sha1, s->sha1, s);
		}
	}

done:

	/* We guarantee the SHA1 is present in the record if known */
	g_assert(!(s && sha1) || s->sha1);

	/* Postcondition: if we return something, it must be "correct" */
	if (s != NULL) {
		g_assert(atom_is_str(s->pathname));
		g_assert(atom_is_str(s->filename));
		g_assert(s->norm >= 0.0);
	}

	return s;
}
예제 #30
0
/**
 * Add new URL to cache, possibly pushing off an older one if cache is full.
 *
 * @return TRUE if the URL was added, FALSE otherwise.
 */
static bool
gwc_add(const char *new_url)
{
    const char *url_atom;
    const char *old_url;
    char *url, *ret;

    url = h_strdup(new_url); /* url_normalize() can modify the URL */

    ret = url_normalize(url, URL_POLICY_GWC_RULES);
    if (!ret) {
        g_warning("%s(): ignoring bad web cache URL \"%s\"",
                  G_STRFUNC, new_url);
        HFREE_NULL(url);
        return FALSE;
    }
    if (ret != url) {
        HFREE_NULL(url);
        url = ret;
    }

    /*
     * Don't add duplicates to the cache.
     */

    if (
        hset_contains(gwc_known_url, url) ||
        hset_contains(gwc_failed_url, url)
    ) {
        HFREE_NULL(url);
        return FALSE;
    }

    /*
     * OK, record new entry at the `gwc_url_slot'.
     */

    if (++gwc_url_slot >= MAX_GWC_URLS)
        gwc_url_slot = 0;

    g_assert(url != NULL);
    url_atom = atom_str_get(url);
    HFREE_NULL(url);

    /*
     * Expire any entry present at the slot we're about to write into.
     */

    old_url = gwc_url[gwc_url_slot].url;

    if (old_url != NULL) {
        g_assert(hset_contains(gwc_known_url, old_url));
        hset_remove(gwc_known_url, old_url);
        atom_str_free_null(&old_url);
        gwc_url[gwc_url_slot].url = NULL;
    }

    hset_insert(gwc_known_url, url_atom);

    gwc_url[gwc_url_slot].url = url_atom;
    gwc_url[gwc_url_slot].stamp = 0;
    gwc_file_dirty = TRUE;

    if (GNET_PROPERTY(bootstrap_debug)) {
        g_debug("%s(): loaded GWC URL %s", G_STRFUNC, url_atom);
    }

    return TRUE;
}