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); }
/** * 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; }
/** * 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; }
/** * 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; }
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; }
/** * 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)); }
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; }
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))); }
/** * 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; }
/** * 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; }
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; }
/** * 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; }
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); }
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; }
/** * 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; }
/** * 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); }
/** * 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); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; } }
/** * 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; }
/** * 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; }
/** * 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)); }
/** * 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); }
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); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }