void gui_release() { int i=0; for (i=0; i<gui->search_num;i++) free(gui->search_path[i]); free(gui->search_path); hash_release ( gui->signal_hash ); hash_release ( gui->font_hash ); hash_release ( gui->image_hash ); stack_release( gui->win_stack ); free(gui); gui = NULL; }
/** Release a stanza object and all of its children. * This function releases a stanza object and potentially all of its * children, which may cause the object(s) to be freed. * * @param stanza a Strophe stanza object * * @return TRUE if the object was freed and FALSE otherwise * * @ingroup Stanza */ int xmpp_stanza_release(xmpp_stanza_t * const stanza) { int released = 0; xmpp_stanza_t *child, *tchild; /* release stanza */ if (stanza->ref > 1) stanza->ref--; else { /* release all children */ child = stanza->children; while (child) { tchild = child; child = child->next; xmpp_stanza_release(tchild); } if (stanza->attributes) hash_release(stanza->attributes); if (stanza->data) xmpp_free(stanza->ctx, stanza->data); xmpp_free(stanza->ctx, stanza); released = 1; } return released; }
/* * 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; }
/** Set an attribute for a stanza object. * * @param stanza a Strophe stanza object * @param key a string with the attribute name * @param value a string with the attribute value * * @return XMPP_EOK (0) on success or a number less than 0 on failure * * @ingroup Stanza */ int xmpp_stanza_set_attribute(xmpp_stanza_t * const stanza, const char * const key, const char * const value) { char *val; int rc; if (stanza->type != XMPP_STANZA_TAG) return XMPP_EINVOP; if (!stanza->attributes) { stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free); if (!stanza->attributes) return XMPP_EMEM; } val = xmpp_strdup(stanza->ctx, value); if (!val) { hash_release(stanza->attributes); return XMPP_EMEM; } rc = hash_add(stanza->attributes, key, val); if (rc < 0) { xmpp_free(stanza->ctx, val); return XMPP_EMEM; } return XMPP_EOK; }
/* * 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; }
void hash_iter_release(hash_iterator_t *iter) { iter->ref--; if (iter->ref <= 0) { hash_release(iter->table); safe_mem_free(iter); } }
static void distribute_free_if_empty(struct distribute *dist) { int i; for (i=0; i < DISTRIBUTE_MAX; i++) if (dist->list[i] != NULL || dist->prefix[i] != NULL) return; hash_release (disthash, dist); distribute_free (dist); }
/** release an iterator that is no longer needed */ void hash_iter_release(hash_iterator_t *iter) { xmpp_ctx_t *ctx = iter->table->ctx; iter->ref--; if (iter->ref <= 0) { hash_release(iter->table); xmpp_free(ctx, iter); } }
/* Unset distribute-list. If matched distribute-list exist then return 1. */ static int distribute_list_prefix_unset (const char *ifname, enum distribute_type type, const char *plist_name) { struct distribute *dist; dist = distribute_lookup (ifname); if (!dist) return 0; if (type == DISTRIBUTE_IN) { if (!dist->prefix[DISTRIBUTE_IN]) return 0; if (strcmp (dist->prefix[DISTRIBUTE_IN], plist_name) != 0) return 0; free (dist->prefix[DISTRIBUTE_IN]); dist->prefix[DISTRIBUTE_IN] = NULL; } if (type == DISTRIBUTE_OUT) { if (!dist->prefix[DISTRIBUTE_OUT]) return 0; if (strcmp (dist->prefix[DISTRIBUTE_OUT], plist_name) != 0) return 0; free (dist->prefix[DISTRIBUTE_OUT]); dist->prefix[DISTRIBUTE_OUT] = NULL; } /* Apply this distribute-list to the interface. */ (*distribute_delete_hook) (dist); /* If both out and in is NULL then free distribute list. */ if (dist->list[DISTRIBUTE_IN] == NULL && dist->list[DISTRIBUTE_OUT] == NULL && dist->prefix[DISTRIBUTE_IN] == NULL && dist->prefix[DISTRIBUTE_OUT] == NULL) { hash_release (disthash, dist); distribute_free (dist); } return 1; }
void curlp_release(curlp_t* cp) { if (cp) { if (cp->free_list) { slist_release(cp->free_list); } if (cp->clients) { hash_loop(cp->clients, _curl_loop_release, cp); hash_release(cp->clients); } if (cp->mhandle) { curl_multi_cleanup(cp->mhandle); cp->mhandle = NULL; } FREE(cp); } }
static void bgp_address_del (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_lookup (bgp_address_hash, &tmp); addr->refcnt--; if (addr->refcnt == 0) { hash_release (bgp_address_hash, addr); XFREE (MTYPE_BGP_ADDR, addr); } }
static void bgp_advertise_unintern (struct hash *hash, struct bgp_advertise_attr *baa) { if (baa->refcnt) baa->refcnt--; if (baa->refcnt && baa->attr) bgp_attr_unintern (baa->attr); else { if (baa->attr) { hash_release (hash, baa); bgp_attr_unintern (baa->attr); } baa_free (baa); } }
/* delete the peer config */ static enum pim_msdp_err pim_msdp_peer_do_del(struct pim_msdp_peer *mp) { /* stop the tcp connection and shutdown all timers */ pim_msdp_peer_stop_tcp_conn(mp, true /* chg_state */); /* remove the session from various tables */ listnode_delete(mp->pim->msdp.peer_list, mp); hash_release(mp->pim->msdp.peer_hash, mp); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP peer %s deleted", mp->key_str); } /* free up any associated memory */ pim_msdp_peer_free(mp); return PIM_MSDP_ERR_NONE; }
static void pim_msdp_sa_del(struct pim_msdp_sa *sa) { /* this is somewhat redundant - still want to be careful not to leave * stale upstream references */ pim_msdp_sa_upstream_del(sa); /* stop timers */ pim_msdp_sa_state_timer_setup(sa, false /* start */); /* remove the entry from various tables */ listnode_delete(sa->pim->msdp.sa_list, sa); hash_release(sa->pim->msdp.sa_hash, sa); if (PIM_DEBUG_MSDP_EVENTS) { zlog_debug("MSDP SA %s deleted", sa->sg_str); } /* free up any associated memory */ pim_msdp_sa_free(sa); }
static void bgp_address_del (struct prefix *p) { struct bgp_addr tmp; struct bgp_addr *addr; tmp.addr = p->u.prefix4; addr = hash_lookup (bgp_address_hash, &tmp); /* may have been deleted earlier by bgp_interface_down() */ if (addr == NULL) return; addr->refcnt--; if (addr->refcnt == 0) { hash_release (bgp_address_hash, addr); XFREE (MTYPE_BGP_ADDR, addr); } }
curl_pool_t* curl_pool_init() { int32_t i = 0; struct curl_client_t* cc = NULL; curl_pool_t* cp = (curl_pool_t*)MALLOC(sizeof(*cp)); if (!cp) goto CURL_FAIL; memset(cp, 0, sizeof(*cp)); cp->size = CURL_POOL_DEFAULT_SIZE; cp->free_list = slist_init(); if (!cp->free_list) goto CURL_FAIL1; cp->clients = hash_init(_curl_pool_hash, _curl_pool_cmp, cp->size * 13); if (!cp->clients) goto CURL_FAIL2; cp->mhandle = curl_multi_init(); if (!cp->mhandle) goto CURL_FAIL3; // pre allocate client for (i = 0; i < cp->size; ++ i) { cc = curl_client_init(); if (cc) { slist_push_front(cp->free_list, cc); hash_insert(cp->clients, cc); } } return cp; CURL_FAIL3: hash_release(cp->clients); CURL_FAIL2: slist_release(cp->free_list); CURL_FAIL1: FREE(cp); CURL_FAIL: return NULL; }
/** Set or replace attributes on a stanza. * This function replaces all previous attributes (if any) with the * attributes given. It is used primarily by the XML parser during * stanza creation. All strings in the array are copied before placing them * inside the stanza object. * * @param stanza a Strophe stanza object * @param attr an array of strings with the attributes in the following * format: attr[i] = attribute name, attr[i+1] = attribute value * * @return XMPP_EOK on success, a number less than 0 on failure (XMPP_EMEM, * XMPP_EINVOP) * * @ingroup Stanza */ int xmpp_stanza_set_attributes(xmpp_stanza_t * const stanza, const char * const * const attr) { int i; char *value; if (stanza->attributes != NULL) hash_release(stanza->attributes); stanza->attributes = hash_new(stanza->ctx, 8, xmpp_free); if (!stanza->attributes) return XMPP_EMEM; for (i = 0; attr[i]; i += 2) { value = xmpp_strdup(stanza->ctx, attr[i + 1]); if (!value) { /* FIXME: memory allocation error */ continue; } hash_add(stanza->attributes, attr[i], value); } return XMPP_EOK; }
void pim_vxlan_sg_del(struct pim_instance *pim, struct prefix_sg *sg) { struct pim_vxlan_sg *vxlan_sg; vxlan_sg = pim_vxlan_sg_find(pim, sg); if (!vxlan_sg) return; vxlan_sg->flags |= PIM_VXLAN_SGF_DEL_IN_PROG; pim_vxlan_del_work(vxlan_sg); if (pim_vxlan_is_orig_mroute(vxlan_sg)) pim_vxlan_orig_mr_del(vxlan_sg); else pim_vxlan_term_mr_del(vxlan_sg); hash_release(vxlan_sg->pim->vxlan.sg_hash, vxlan_sg); if (PIM_DEBUG_VXLAN) zlog_debug("vxlan SG %s free", vxlan_sg->sg_str); XFREE(MTYPE_PIM_VXLAN_SG, vxlan_sg); }
/** generate auth response string for the SASL DIGEST-MD5 mechanism */ char *sasl_digest_md5(xmpp_ctx_t *ctx, const char *challenge, const char *jid, const char *password) { hash_t *table; char *result = NULL; char *node, *domain, *realm; char *value; char *response; int rlen; struct MD5Context MD5; unsigned char digest[16], HA1[16], HA2[16]; char hex[32]; char cnonce[13]; /* our digest response is Hex( KD( HEX(MD5(A1)), nonce ':' nc ':' cnonce ':' qop ':' HEX(MD5(A2)) )) where KD(k, s) = MD5(k ':' s), A1 = MD5( node ':' realm ':' password ) ':' nonce ':' cnonce A2 = "AUTHENTICATE" ':' "xmpp/" domain If there is an authzid it is ':'-appended to A1 */ /* parse the challenge */ table = _parse_digest_challenge(ctx, challenge); if (table == NULL) { xmpp_error(ctx, "SASL", "couldn't parse digest challenge"); return NULL; } node = xmpp_jid_node(ctx, jid); domain = xmpp_jid_domain(ctx, jid); /* generate default realm of domain if one didn't come from the server */ realm = hash_get(table, "realm"); if (realm == NULL || strlen(realm) == 0) { hash_add(table, "realm", xmpp_strdup(ctx, domain)); realm = hash_get(table, "realm"); } /* add our response fields */ hash_add(table, "username", xmpp_strdup(ctx, node)); xmpp_rand_nonce(ctx->rand, cnonce, sizeof(cnonce)); hash_add(table, "cnonce", xmpp_strdup(ctx, cnonce)); hash_add(table, "nc", xmpp_strdup(ctx, "00000001")); hash_add(table, "qop", xmpp_strdup(ctx, "auth")); value = xmpp_alloc(ctx, 5 + strlen(domain) + 1); memcpy(value, "xmpp/", 5); memcpy(value+5, domain, strlen(domain)); value[5+strlen(domain)] = '\0'; hash_add(table, "digest-uri", value); /* generate response */ /* construct MD5(node : realm : password) */ MD5Init(&MD5); MD5Update(&MD5, (unsigned char *)node, strlen(node)); MD5Update(&MD5, (unsigned char *)":", 1); MD5Update(&MD5, (unsigned char *)realm, strlen(realm)); MD5Update(&MD5, (unsigned char *)":", 1); MD5Update(&MD5, (unsigned char *)password, strlen(password)); MD5Final(digest, &MD5); /* digest now contains the first field of A1 */ MD5Init(&MD5); MD5Update(&MD5, digest, 16); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "nonce"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "cnonce"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Final(digest, &MD5); /* now digest is MD5(A1) */ memcpy(HA1, digest, 16); /* construct MD5(A2) */ MD5Init(&MD5); MD5Update(&MD5, (unsigned char *)"AUTHENTICATE:", 13); value = hash_get(table, "digest-uri"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); if (strcmp(hash_get(table, "qop"), "auth") != 0) { MD5Update(&MD5, (unsigned char *)":00000000000000000000000000000000", 33); } MD5Final(digest, &MD5); memcpy(HA2, digest, 16); /* construct response */ MD5Init(&MD5); _digest_to_hex((char *)HA1, hex); MD5Update(&MD5, (unsigned char *)hex, 32); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "nonce"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "nc"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "cnonce"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)":", 1); value = hash_get(table, "qop"); MD5Update(&MD5, (unsigned char *)value, strlen(value)); MD5Update(&MD5, (unsigned char *)":", 1); _digest_to_hex((char *)HA2, hex); MD5Update(&MD5, (unsigned char *)hex, 32); MD5Final(digest, &MD5); response = xmpp_alloc(ctx, 32+1); _digest_to_hex((char *)digest, hex); memcpy(response, hex, 32); response[32] = '\0'; hash_add(table, "response", response); /* construct reply */ result = NULL; rlen = 0; result = _add_key(ctx, table, "username", result, &rlen, 1); result = _add_key(ctx, table, "realm", result, &rlen, 1); result = _add_key(ctx, table, "nonce", result, &rlen, 1); result = _add_key(ctx, table, "cnonce", result, &rlen, 1); result = _add_key(ctx, table, "nc", result, &rlen, 0); result = _add_key(ctx, table, "qop", result, &rlen, 0); result = _add_key(ctx, table, "digest-uri", result, &rlen, 1); result = _add_key(ctx, table, "response", result, &rlen, 0); result = _add_key(ctx, table, "charset", result, &rlen, 0); xmpp_free(ctx, node); xmpp_free(ctx, domain); hash_release(table); /* also frees value strings */ /* reuse response for the base64 encode of our result */ response = xmpp_base64_encode(ctx, (unsigned char *)result, strlen(result)); xmpp_free(ctx, result); return response; }
void hash_free(void* hash, void* pool_handle) { hash_release(hash, FALSE, pool_handle); }
void hash_destroy(void* hash, void* pool_handle) { hash_release(hash, TRUE, pool_handle); }
/* Accept bgp connection. */ static int bgp_accept(struct thread *thread) { int bgp_sock; int accept_sock; union sockunion su; struct bgp_listener *listener = THREAD_ARG(thread); struct peer *peer; struct peer *peer1; char buf[SU_ADDRSTRLEN]; struct bgp *bgp = NULL; sockunion_init(&su); /* Register accept thread. */ accept_sock = THREAD_FD(thread); if (accept_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "accept_sock is nevative value %d", accept_sock); return -1; } listener->thread = NULL; thread_add_read(bm->master, bgp_accept, listener, accept_sock, &listener->thread); /* Accept client connection. */ bgp_sock = sockunion_accept(accept_sock, &su); if (bgp_sock < 0) { flog_err_sys(EC_LIB_SOCKET, "[Error] BGP socket accept failed (%s)", safe_strerror(errno)); return -1; } set_nonblocking(bgp_sock); /* Obtain BGP instance this connection is meant for. * - if it is a VRF netns sock, then BGP is in listener structure * - otherwise, the bgp instance need to be demultiplexed */ if (listener->bgp) bgp = listener->bgp; else if (bgp_get_instance_for_inc_conn(bgp_sock, &bgp)) { if (bgp_debug_neighbor_events(NULL)) zlog_debug( "[Event] Could not get instance for incoming conn from %s", inet_sutop(&su, buf)); close(bgp_sock); return -1; } /* Set socket send buffer size */ setsockopt_so_sendbuf(bgp_sock, BGP_SOCKET_SNDBUF_SIZE); /* Check remote IP address */ peer1 = peer_lookup(bgp, &su); if (!peer1) { peer1 = peer_lookup_dynamic_neighbor(bgp, &su); if (peer1) { /* Dynamic neighbor has been created, let it proceed */ peer1->fd = bgp_sock; bgp_fsm_change_status(peer1, Active); BGP_TIMER_OFF( peer1->t_start); /* created in peer_create() */ if (peer_active(peer1)) BGP_EVENT_ADD(peer1, TCP_connection_open); return 0; } } if (!peer1) { if (bgp_debug_neighbor_events(NULL)) { zlog_debug( "[Event] %s connection rejected - not configured" " and not valid for dynamic", inet_sutop(&su, buf)); } close(bgp_sock); return -1; } if (CHECK_FLAG(peer1->flags, PEER_FLAG_SHUTDOWN)) { if (bgp_debug_neighbor_events(peer1)) zlog_debug( "[Event] connection from %s rejected due to admin shutdown", inet_sutop(&su, buf)); close(bgp_sock); return -1; } /* * Do not accept incoming connections in Clearing state. This can result * in incorect state transitions - e.g., the connection goes back to * Established and then the Clearing_Completed event is generated. Also, * block incoming connection in Deleted state. */ if (peer1->status == Clearing || peer1->status == Deleted) { if (bgp_debug_neighbor_events(peer1)) zlog_debug( "[Event] Closing incoming conn for %s (%p) state %d", peer1->host, peer1, peer1->status); close(bgp_sock); return -1; } /* Check that at least one AF is activated for the peer. */ if (!peer_active(peer1)) { if (bgp_debug_neighbor_events(peer1)) zlog_debug( "%s - incoming conn rejected - no AF activated for peer", peer1->host); close(bgp_sock); return -1; } if (bgp_debug_neighbor_events(peer1)) zlog_debug("[Event] BGP connection from host %s fd %d", inet_sutop(&su, buf), bgp_sock); if (peer1->doppelganger) { /* We have an existing connection. Kill the existing one and run with this one. */ if (bgp_debug_neighbor_events(peer1)) zlog_debug( "[Event] New active connection from peer %s, Killing" " previous active connection", peer1->host); peer_delete(peer1->doppelganger); } if (bgp_set_socket_ttl(peer1, bgp_sock) < 0) if (bgp_debug_neighbor_events(peer1)) zlog_debug( "[Event] Unable to set min/max TTL on peer %s, Continuing", peer1->host); peer = peer_create(&su, peer1->conf_if, peer1->bgp, peer1->local_as, peer1->as, peer1->as_type, 0, 0, NULL); hash_release(peer->bgp->peerhash, peer); hash_get(peer->bgp->peerhash, peer, hash_alloc_intern); peer_xfer_config(peer, peer1); UNSET_FLAG(peer->flags, PEER_FLAG_CONFIG_NODE); peer->doppelganger = peer1; peer1->doppelganger = peer; peer->fd = bgp_sock; vrf_bind(peer->bgp->vrf_id, bgp_sock, bgp_get_bound_name(peer)); bgp_fsm_change_status(peer, Active); BGP_TIMER_OFF(peer->t_start); /* created in peer_create() */ SET_FLAG(peer->sflags, PEER_STATUS_ACCEPT_PEER); /* Make dummy peer until read Open packet. */ if (peer1->status == Established && CHECK_FLAG(peer1->sflags, PEER_STATUS_NSF_MODE)) { /* If we have an existing established connection with graceful * restart * capability announced with one or more address families, then * drop * existing established connection and move state to connect. */ peer1->last_reset = PEER_DOWN_NSF_CLOSE_SESSION; SET_FLAG(peer1->sflags, PEER_STATUS_NSF_WAIT); bgp_event_update(peer1, TCP_connection_closed); } if (peer_active(peer)) { BGP_EVENT_ADD(peer, TCP_connection_open); } return 0; }
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; }
/** 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; }