/* * Copy the attributes of stanza src into stanza dst. Return -1 on error. */ static int _stanza_copy_attributes(xmpp_stanza_t * dst, const xmpp_stanza_t * const src) { hash_iterator_t *iter; const char *key; const char *val; int rc = XMPP_EOK; iter = hash_iter_new(src->attributes); if (!iter) rc = XMPP_EMEM; while (rc == XMPP_EOK && (key = hash_iter_next(iter))) { val = hash_get(src->attributes, key); if (!val) rc = XMPP_EINT; if (rc == XMPP_EOK) rc = xmpp_stanza_set_attribute(dst, key, val); } hash_iter_release(iter); if (rc != XMPP_EOK && dst->attributes) { hash_release(dst->attributes); dst->attributes = NULL; } return rc; }
/* * Copy the attributes of stanza src into stanza dst. Return -1 on error. */ static int _stanza_copy_attributes(xmpp_stanza_t * dst, const xmpp_stanza_t * const src) { hash_iterator_t *iter = NULL; const char *key; void *val; dst->attributes = hash_new(src->ctx, 8, xmpp_free); if (!dst->attributes) return -1; iter = hash_iter_new(src->attributes); if (!iter) goto error; while ((key = hash_iter_next(iter))) { val = xmpp_strdup(src->ctx, (char *)hash_get(src->attributes, key)); if (!val) goto error; if (hash_add(dst->attributes, key, val)) { xmpp_free(src->ctx, val); goto error; } } hash_iter_release(iter); return 0; error: if (iter != NULL) hash_iter_release(iter); hash_release(dst->attributes); return -1; }
/** Get all attributes for a stanza object. * This function populates the array with attributes from the stanza. The * attr array will be in the format: attr[i] = attribute name, * attr[i+1] = attribute value. * * @param stanza a Strophe stanza object * @param attr the string array to populate * @param attrlen the size of the array * * @return the number of slots used in the array, which will be 2 times the * number of attributes in the stanza * * @ingroup Stanza */ int xmpp_stanza_get_attributes(xmpp_stanza_t * const stanza, const char **attr, int attrlen) { hash_iterator_t *iter; const char *key; int num = 0; if (stanza->attributes == NULL) { return 0; } iter = hash_iter_new(stanza->attributes); while ((key = hash_iter_next(iter)) != NULL && attrlen) { attr[num++] = key; attrlen--; if (attrlen == 0) { hash_iter_release(iter); return num; } attr[num++] = hash_get(stanza->attributes, key); attrlen--; if (attrlen == 0) { hash_iter_release(iter); return num; } } hash_iter_release(iter); return num; }
static int test_hash_iter_after_del(const struct test *t) { struct hash *h = hash_new(8, NULL); struct hash *h2 = hash_new(8, NULL); const char *k1 = "k1", *k2 = "k2", *k3 = "k3"; const char *v1 = "v1", *v2 = "v2", *v3 = "v3"; struct hash_iter iter; const char *k, *v; hash_add(h, k1, v1); hash_add(h2, k1, v1); hash_add(h, k2, v2); hash_add(h2, k2, v2); hash_add(h, k3, v3); hash_add(h2, k3, v3); hash_del(h, k1); for (hash_iter_init(h, &iter); hash_iter_next(&iter, &k, (const void **) &v);) { v2 = hash_find(h2, k); assert_return(v2 != NULL, EXIT_FAILURE); hash_del(h2, k); } assert_return(hash_get_count(h) == 2, EXIT_FAILURE); assert_return(hash_get_count(h2) == 1, EXIT_FAILURE); hash_free(h); hash_free(h2); return 0; }
int hash_iter_init(hash_iter_t *iter, hash_t *ht) { iter->pos = 0; iter->depth = 0; iter->ht = ht; iter->key = NULL; iter->value = NULL; return hash_iter_next(iter); }
/** Copy a stanza and its children. * This function copies a stanza along with all its children and returns * the new stanza and children with a reference count of 1. The returned * stanza will have no parent and no siblings. This function is useful * for extracting a child stanza for inclusion in another tree. * * @param stanza a Strophe stanza object * * @return a new Strophe stanza object * * @ingroup Stanza */ xmpp_stanza_t *xmpp_stanza_copy(const xmpp_stanza_t * const stanza) { xmpp_stanza_t *copy, *child, *copychild, *tail; hash_iterator_t *iter; const char *key; void *val; copy = xmpp_stanza_new(stanza->ctx); if (!copy) goto copy_error; copy->type = stanza->type; if (stanza->data) { copy->data = xmpp_strdup(stanza->ctx, stanza->data); if (!copy->data) goto copy_error; } if (stanza->attributes) { copy->attributes = hash_new(stanza->ctx, 8, xmpp_free); if (!copy->attributes) goto copy_error; iter = hash_iter_new(stanza->attributes); if (!iter) { printf("DEBUG HERE\n"); goto copy_error; } while ((key = hash_iter_next(iter))) { val = xmpp_strdup(stanza->ctx, (char *)hash_get(stanza->attributes, key)); if (!val) goto copy_error; if (hash_add(copy->attributes, key, val)) goto copy_error; } hash_iter_release(iter); } tail = copy->children; for (child = stanza->children; child; child = child->next) { copychild = xmpp_stanza_copy(child); if (!copychild) goto copy_error; copychild->parent = copy; if (tail) { copychild->prev = tail; tail->next = copychild; } else copy->children = copychild; tail = copychild; } return copy; copy_error: /* release all the hitherto allocated memory */ if (copy) xmpp_stanza_release(copy); return NULL; }
static void dump_macro_set(MACRO_SET & set, MyString & str, const char * prefix) { str.clear(); HASHITER it = hash_iter_begin(set, HASHITER_NO_DEFAULTS | HASHITER_SHOW_DUPS); while( ! hash_iter_done(it)) { const char *name = hash_iter_key(it); const char *val = hash_iter_value(it); //const MACRO_META *met = hash_iter_meta(it); if (prefix) str += prefix; str += name; str += "="; str += val ? val : ""; str += "\n"; hash_iter_next(it); } hash_iter_delete(&it); }
void write_sizes(const char * to_file) { FILE *f = fopen(to_file, "wt"); fputs(VFILESIZE_FILE_TYPE /**/ "\n", f); fputs(VFILESIZE_FILE_VERSION /**/ "\n", f); hash_iter_t it; it = vfilesize_hash_iter(SIZE_HASH); while (!hash_iter_end(it)) { vfile_size_t *e = vfilesize_hash_get(SIZE_HASH, hash_iter_key(it) ); if (e != NULL) { fprintf(f, "%s\n%lu\n%lu\n", hash_iter_key(it), (unsigned long) e->size, (unsigned long) e->mtime ); } else { log_debug("Unexpected!"); } it = hash_iter_next(it); } fclose(f); }
static void check_buffer(EFLOWDESC *ex, void *mdl) { /* * lookup for a item in the hash table with sequence number = ex->next_seq. * if found, repeat until not found */ block_t * block; hash_iter_t iterator; block = (block_t *)hash_lookup_ulong(ex->htable, ex->next_seq); while (block != NULL) { if (block->seq == ex->next_seq) { /* must ALWAYS be true :) */ add_block(ex, block, mdl); unbuffer_block(ex, block->seq, block->len); } block = (block_t *)hash_lookup_ulong(ex->htable, ex->next_seq); } /* * in case there are overlapped packets, iterate on the hash table to look * for sequence numbers < ex->next_seq */ hash_iter_init(ex->htable, &iterator); while (hash_iter_next (&iterator)) { block = (block_t *)hash_iter_get_value(&iterator); if (block->seq <= ex->next_seq) { add_block(ex, block, mdl); /* * remove from hash with current key value, because the sequence * number could have changed (in case of overlap with valid data), * so no longer would coincide with the hash key */ unbuffer_block(ex, hash_iter_get_ulong_key(&iterator), block->len); /* start again */ hash_iter_init(ex->htable, &iterator); } } }
static void debug_print_hash_elements(lref_t obj, lref_t port, bool machine_readable) { assert(HASHP(obj)); fixnum_t count = 0; lref_t key, val; hash_iter_t ii; hash_iter_begin(obj, &ii); while (hash_iter_next(obj, &ii, &key, &val)) { count++; write_char(port, _T(' ')); debug_print_object(key, port, machine_readable); write_char(port, _T(' ')); debug_print_object(val, port, machine_readable); } }
int main(int argc, char *argv[]) { char buf[32]; char buf2[32]; int i; int len; hash_t *ht, *htcpy; hash_iter_t *iter; srand(time(NULL)); ht = hash_create(16); HASH_SET_KEYCPY(ht, _demo_dup); HASH_SET_VALCPY(ht, _demo_dup); HASH_SET_FREE_KEY(ht, _demo_destructor); HASH_SET_FREE_VAL(ht, _demo_destructor); HASH_SET_KEYCMP(ht, _demo_cmp); for (i = 0; i < 100000; ++i) { len = randstring(buf, 1, sizeof(buf) - 1); buf[len] = '\0'; len = randstring(buf2, 1, sizeof(buf2) - 1); buf2[len] = '\0'; hash_insert(ht, buf, buf2); } hash_dump(ht); htcpy = hash_dup(ht); hash_free(ht); printf("================================\n\n\n"); iter = hash_iter_new(htcpy); assert(iter); do { printf("%s=>%s\n", (char *)iter->key, (char *)iter->value); } while (hash_iter_next(iter) == 0); hash_free(htcpy); exit(0); }
static void sort_buffer(EFLOWDESC *ex, void *mdl) { /* * this only happens when FIN / RST arrives for a flow that was already * established when sniffing started. so SYN was not captured (initial * sequence number). in this case, just sort what we have captured. */ hash_iter_t iterator; block_t * block, * min_block; min_block = NULL; hash_iter_init(ex->htable, &iterator); while (hash_iter_next(&iterator)) { block = (block_t *)hash_iter_get_value (&iterator); if (min_block == NULL || block->seq < min_block->seq) min_block = block; } /* * min_block is now the 'first' block of all. so set it as the first block, * then call check_buffer to put everything in place. */ if (min_block != NULL) { ex->base_seq = min_block->seq; ex->next_seq = min_block->seq; add_block(ex, min_block, mdl); unbuffer_block(ex, min_block->seq, min_block->len); check_buffer(ex, mdl); } /* now all possible blocks to be ordered (if any) should be in order */ }
/* always returns number of bytes written or that would have been * written if the buffer was large enough * return values < 0 indicate some error occurred, * and return values > buflen indicate buffer was not large enough */ static int _render_stanza_recursive(xmpp_stanza_t *stanza, char * const buf, size_t const buflen) { char *ptr = buf; size_t left = buflen; int ret, written; xmpp_stanza_t *child; hash_iterator_t *iter; const char *key; char *tmp; written = 0; if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TEXT) { if (!stanza->data) return XMPP_EINVOP; tmp = _escape_xml(stanza->ctx, stanza->data); if (tmp == NULL) return XMPP_EMEM; ret = xmpp_snprintf(ptr, left, "%s", tmp); xmpp_free(stanza->ctx, tmp); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } else { /* stanza->type == XMPP_STANZA_TAG */ if (!stanza->data) return XMPP_EINVOP; /* write beginning of tag and attributes */ ret = xmpp_snprintf(ptr, left, "<%s", stanza->data); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) { iter = hash_iter_new(stanza->attributes); while ((key = hash_iter_next(iter))) { if (!strcmp(key, "xmlns")) { /* don't output namespace if parent stanza is the same */ if (stanza->parent && stanza->parent->attributes && hash_get(stanza->parent->attributes, key) && !strcmp((char*)hash_get(stanza->attributes, key), (char*)hash_get(stanza->parent->attributes, key))) continue; /* or if this is the stream namespace */ if (!stanza->parent && !strcmp((char*)hash_get(stanza->attributes, key), XMPP_NS_CLIENT)) continue; } tmp = _escape_xml(stanza->ctx, (char *)hash_get(stanza->attributes, key)); if (tmp == NULL) return XMPP_EMEM; ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, tmp); xmpp_free(stanza->ctx, tmp); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } hash_iter_release(iter); } if (!stanza->children) { /* write end if singleton tag */ ret = xmpp_snprintf(ptr, left, "/>"); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } else { /* this stanza has child stanzas */ /* write end of start tag */ ret = xmpp_snprintf(ptr, left, ">"); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); /* iterate and recurse over child stanzas */ child = stanza->children; while (child) { ret = _render_stanza_recursive(child, ptr, left); if (ret < 0) return ret; _render_update(&written, buflen, ret, &left, &ptr); child = child->next; } /* write end tag */ ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } } return written; }
/* always returns number of bytes written or that would have been * written if the buffer was large enough * return values < 0 indicate some error occured, * and return values > buflen indicate buffer was not large enough */ static int _render_stanza_recursive(xmpp_stanza_t *stanza, char * const buf, size_t const buflen) { char *ptr = buf; size_t left = buflen; int ret, written; xmpp_stanza_t *child; hash_iterator_t *iter; const char *key; assert(stanza); written = 0; if (stanza->type == XMPP_STANZA_UNKNOWN) return XMPP_EINVOP; if (stanza->type == XMPP_STANZA_TEXT) { if (!stanza->data) return XMPP_EINVOP; assert(stanza->data); ret = xmpp_snprintf(ptr, left, "%s", stanza->data); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } else { /* stanza->type == XMPP_STANZA_TAG */ if (!stanza->data) return XMPP_EINVOP; /* write begining of tag and attributes */ assert(stanza->data); ret = xmpp_snprintf(ptr, left, "<%s", stanza->data); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); if (stanza->attributes && hash_num_keys(stanza->attributes) > 0) { iter = hash_iter_new(stanza->attributes); while ((key = hash_iter_next(iter))) { assert(hash_get(stanza->attributes, key)); ret = xmpp_snprintf(ptr, left, " %s=\"%s\"", key, (char *)hash_get(stanza->attributes, key)); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } hash_iter_release(iter); } if (!stanza->children) { /* write end if singleton tag */ ret = xmpp_snprintf(ptr, left, "/>"); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } else { /* this stanza has child stanzas */ /* write end of start tag */ ret = xmpp_snprintf(ptr, left, ">"); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); /* iterate and recurse over child stanzas */ child = stanza->children; while (child) { ret = _render_stanza_recursive(child, ptr, left); if (ret < 0) return ret; _render_update(&written, buflen, ret, &left, &ptr); child = child->next; } /* write end tag */ assert(stanza->data); ret = xmpp_snprintf(ptr, left, "</%s>", stanza->data); if (ret < 0) return XMPP_EMEM; _render_update(&written, buflen, ret, &left, &ptr); } } return written; }
int main(int argc, char **argv) { xmpp_ctx_t *ctx; hash_t *table, *clone; hash_iterator_t *iter; unsigned int seed; const char *key; char *result; int err = 0; int i; /* initialize random numbers */ if (argc > 2) { /* use a seed from the command line */ seed = (unsigned int)atoi(argv[1]); } else { seed = (unsigned int)clock(); } /* using random seed 'seed' */ srand(seed); /* allocate a default context */ ctx = xmpp_ctx_new(NULL, NULL); if (ctx == NULL) { /* ctx allocation failed! */ return -1; } /* allocate a hash table */ table = hash_new(ctx, TABLESIZE, NULL); if (table == NULL) { /* table allocation failed! */ return 1; } /* test insertion */ for (i = 0; i < nkeys; i++) { err = hash_add(table, keys[i], (void*)values[i]); if (err) return err; } /* test key count */ if (hash_num_keys(table) != nkeys) { /* wrong number of keys in table! */ return 1; } /* test cloning */ clone = hash_clone(table); /* test lookup */ for (i = 0; i < nkeys; i++) { result = hash_get(clone, keys[i]); if (result == NULL) { /* lookup failed! */ return 1; } if (strcmp(values[i], result)) { /* lookup returned incorrect value! */ return 1; } } /* test key iterator */ iter = hash_iter_new(clone); if (iter == NULL) { /* iterator allocation failed! */ return 1; } for (i = 0; i < nkeys; i++) { key = hash_iter_next(iter); printf("key: '%s'\n", key); } key = hash_iter_next(iter); if (key != NULL) { /* extra keys returned! */ return 1; } key = hash_iter_next(iter); if (key != NULL) { /* extra keys returned! */ return 1; } hash_iter_release(iter); /* release the hash table */ hash_release(table); /* test drops */ hash_drop(clone, keys[2]); if (hash_get(clone, keys[2]) != NULL) return 1; hash_drop(clone, keys[1]); hash_drop(clone, keys[4]); if (hash_get(clone, keys[4]) != NULL) return 1; if (hash_get(clone, keys[1]) != NULL) return 1; /* keys 0,3 should still be available */ if (hash_get(clone, keys[0]) == NULL) return 1; if (hash_get(clone, keys[3]) == NULL) return 1; /* release our clone */ hash_release(clone); /* release our library context */ xmpp_ctx_free(ctx); return err; }
static void tea_thread_new(int tid, TEA_OBJECT *to, SNODE *command) { THREAD_WORK *tw = NULL; TEA_OBJCFG *ocline; HASH_ITER hi; HASH_NODE *hn; int fatal = 0; DBG("[tea] Creating thread %d.", tid); if((tw = calloc(1, sizeof(THREAD_WORK))) == NULL) FAT("Cannot alloc THREAD_WORK struct for thread %d.", tid); tw->id = tid; tw->pthread_id = 0; tw->to = to; tw->options = hash_copy(command->command.thc.to->options); /* check methods */ if(tw->to->listener || tw->to->sender) tw->mqueue = mqueue_create(); pthreadex_flag_init(&(tw->mwaiting), 0); pthreadex_flag_name(&(tw->mwaiting), "mwaiting"); pthreadex_flag_init(&(tw->cleanup_do), 0); pthreadex_flag_name(&(tw->cleanup_do), "cleanup_do"); pthreadex_flag_init(&(tw->cleanup_done), 0); pthreadex_flag_name(&(tw->cleanup_done), "cleanup_done"); /* global thread initialization here */ if(tw->to->global_init && !tw->to->initialized) { tw->to->initialized = -1; tw->to->global_init(); } /* make space for thread data */ if((tw->data = calloc(1, to->datasize)) == NULL) FAT("%d:%s: No memory for thread data.", command->line, to->name); /* check config params */ if(to->cparams) { /* check only allowed params are defined */ for(hn = hash_iter_first(&hi, command->command.thc.to->options); !hash_iter_finished(&hi); hn = hash_iter_next(&hi)) { /* iterate all allowed params and stop if (1) declared */ /* parameter hn->key is found in allowed paramter list, */ /* or (2) stop if there is not moar allowed params */ for(ocline = to->cparams; ocline->name && strcasecmp(hn->key, ocline->name); ocline++) ; if(!ocline->name) FAT("%d:%s: Parameter %s not allowed here.", command->line, to->name, hn->key); } /* set params (apply configuration) */ for(ocline = to->cparams; ocline->name; ocline++) { SNODE *val; /* get configured value (or set default value if not specified) */ val = tea_thread_param_value_get(tw->options, ocline->name); /* check if parameter is optional */ if(!val && ocline->needed) FAT("%d:%s: Parameter %s is mandatory.", command->line, to->name, ocline->name); /* set value */ if(tea_thread_param_value_set(tw, ocline, val)) FAT("%d:%s: Cannot set parameter %s.", command->line, to->name, ocline->name); } } else { if(command->command.thc.to->options || command->command.thc.to->options->nentries > 0) FAT("%d:%s: Parameters not allowed for this type of thread.", command->line, to->name); } /* once configuration applied, launch thread configuration routine */ if(tw->to->configure && tw->to->configure(tw, command, 1)) FAT("%d:%s: Thread configuration failed.", command->line, to->name); /* add thread to the list */ pthreadex_lock_get_exclusive_n(&ttable_lock, "install-thread"); DBG("[tea] Installing thread %d.", tid); /* build threads */ if(ttable[tid]) FATAL_ERROR("Thread slot %d is used already.", tid); ttable[tid] = tw; /* launch thread */ if(pthread_create(&(tw->pthread_id), NULL, tea_thread, tw) != 0) { ERR_ERRNO("Error creating thread %d", tid); FATAL_ERROR("Fatal error happened during thread creation."); } termination: if(fatal && tw) { if(ttable[tid] == tw) ttable[tid] = NULL; if(tw->mqueue) mqueue_destroy(tw->mqueue); pthreadex_flag_destroy(&(tw->mwaiting)); pthreadex_flag_destroy(&(tw->cleanup_do)); pthreadex_flag_destroy(&(tw->cleanup_done)); free(tw); } pthreadex_lock_release(); if(!fatal) return; FAT("Aborting."); }
/** Release a Strophe connection object. * Decrement the reference count by one for a connection, freeing the * connection object if the count reaches 0. * * @param conn a Strophe connection object * * @return TRUE if the connection object was freed and FALSE otherwise * * @ingroup Connections */ int xmpp_conn_release(xmpp_conn_t * const conn) { xmpp_ctx_t *ctx; xmpp_connlist_t *item, *prev; xmpp_handlist_t *hlitem, *thli; hash_iterator_t *iter; const char *key; int released = 0; if (conn->ref > 1) conn->ref--; else { ctx = conn->ctx; /* remove connection from context's connlist */ if (ctx->connlist->conn == conn) { item = ctx->connlist; ctx->connlist = item->next; xmpp_free(ctx, item); } else { prev = NULL; item = ctx->connlist; while (item && item->conn != conn) { prev = item; item = item->next; } if (!item) { xmpp_error(ctx, "xmpp", "Connection not in context's list\n"); } else { prev->next = item->next; xmpp_free(ctx, item); } } /* free handler stuff * note that userdata is the responsibility of the client * and the handler pointers don't need to be freed since they * are pointers to functions */ hlitem = conn->timed_handlers; while (hlitem) { thli = hlitem; hlitem = hlitem->next; xmpp_free(ctx, thli); } /* id handlers * we have to traverse the hash table freeing list elements * then release the hash table */ iter = hash_iter_new(conn->id_handlers); while ((key = hash_iter_next(iter))) { hlitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, key); while (hlitem) { thli = hlitem; hlitem = hlitem->next; xmpp_free(conn->ctx, thli->id); xmpp_free(conn->ctx, thli); } } hash_iter_release(iter); hash_release(conn->id_handlers); hlitem = conn->handlers; while (hlitem) { thli = hlitem; hlitem = hlitem->next; if (thli->ns) xmpp_free(ctx, thli->ns); if (thli->name) xmpp_free(ctx, thli->name); if (thli->type) xmpp_free(ctx, thli->type); xmpp_free(ctx, thli); } if (conn->stream_error) { xmpp_stanza_release(conn->stream_error->stanza); if (conn->stream_error->text) xmpp_free(ctx, conn->stream_error->text); xmpp_free(ctx, conn->stream_error); } parser_free(conn->parser); if (conn->domain) xmpp_free(ctx, conn->domain); if (conn->jid) xmpp_free(ctx, conn->jid); if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid); if (conn->pass) xmpp_free(ctx, conn->pass); if (conn->stream_id) xmpp_free(ctx, conn->stream_id); if (conn->lang) xmpp_free(ctx, conn->lang); xmpp_free(ctx, conn); released = 1; } return released; }
/** Release a Strophe connection object. * Decrement the reference count by one for a connection, freeing the * connection object if the count reaches 0. * * @param conn a Strophe connection object * * @return TRUE if the connection object was freed and FALSE otherwise * * @ingroup Connections */ int xmpp_conn_release(xmpp_conn_t * const conn) { xmpp_ctx_t *ctx; list_t *item; xmpp_handler_t *temp; xmpp_handlist_t *hlitem, *thli; hash_iterator_t *iter; const char *key; if (conn->ref > 1) { conn->ref--; return 0; } ctx = conn->ctx; /* remove connection from context's connlist */ item = list_pop_by_data(ctx->connlist, (void *)conn); if (item) xmpp_free(ctx, item); else xmpp_error(ctx, "xmpp", "Connection not in context's list\n"); /* free handler stuff * note that userdata is the responsibility of the client * and the handler pointers don't need to be freed since they * are pointers to functions */ while ((item = list_shift(conn->timed_handlers))) { xmpp_free(ctx, item->data); xmpp_free(ctx, item); } list_destroy(conn->timed_handlers); /* id handlers * we have to traverse the hash table freeing list elements * then release the hash table */ iter = hash_iter_new(conn->id_handlers); while ((key = hash_iter_next(iter))) { hlitem = (xmpp_handlist_t *)hash_get(conn->id_handlers, key); while (hlitem) { thli = hlitem; hlitem = hlitem->next; xmpp_free(ctx, thli->id); xmpp_free(ctx, thli); } } hash_iter_release(iter); hash_release(conn->id_handlers); while ((item = list_shift(conn->handlers))) { temp = (xmpp_handler_t *)item->data; if (temp->ns) xmpp_free(ctx, temp->ns); if (temp->name) xmpp_free(ctx, temp->name); if (temp->type) xmpp_free(ctx, temp->type); xmpp_free(ctx, temp); xmpp_free(ctx, item); } list_destroy(conn->handlers); if (conn->stream_error) { xmpp_stanza_release(conn->stream_error->stanza); if (conn->stream_error->text) xmpp_free(ctx, conn->stream_error->text); xmpp_free(ctx, conn->stream_error); } parser_free(conn->parser); /* free send_queue */ list_destroy(conn->send_queue); if (conn->domain) xmpp_free(ctx, conn->domain); if (conn->jid) xmpp_free(ctx, conn->jid); if (conn->bound_jid) xmpp_free(ctx, conn->bound_jid); if (conn->pass) xmpp_free(ctx, conn->pass); if (conn->stream_id) xmpp_free(ctx, conn->stream_id); if (conn->lang) xmpp_free(ctx, conn->lang); if (conn->tls) tls_free(conn->tls); xmpp_free(ctx, conn); return 1; }