/** * @brief duplicate dmq node */ dmq_node_t *shm_dup_node(dmq_node_t *node) { dmq_node_t *newnode; if(!node) { LM_ERR("node is null\n"); return NULL; } if(!node->orig_uri.s) { LM_ERR("nod->orig_uri.s is null\n"); return NULL; } newnode = shm_malloc(sizeof(dmq_node_t)); if(newnode == NULL) { LM_ERR("no more shm\n"); return NULL; } memcpy(newnode, node, sizeof(dmq_node_t)); newnode->orig_uri.s = NULL; if(shm_str_dup(&newnode->orig_uri, &node->orig_uri) < 0) { goto error; } if(parse_uri(newnode->orig_uri.s, newnode->orig_uri.len, &newnode->uri) < 0) { LM_ERR("error in parsing node uri\n"); goto error; } return newnode; error: destroy_dmq_node(newnode, 1); return NULL; }
/** * @brief find dmq node by uri */ dmq_node_t* find_dmq_node_uri(dmq_node_list_t* list, str* uri) { dmq_node_t *ret, *find; find = build_dmq_node(uri, 0); if(find==NULL) return NULL; ret = find_dmq_node(list, find); destroy_dmq_node(find, 0); return ret; }
/** * @brief delete dmq node */ int del_dmq_node(dmq_node_list_t *list, dmq_node_t *node) { dmq_node_t *cur, **prev; lock_get(&list->lock); cur = list->nodes; prev = &list->nodes; while(cur) { if(cmp_dmq_node(cur, node)) { *prev = cur->next; destroy_dmq_node(cur, 1); lock_release(&list->lock); return 1; } prev = &cur->next; cur = cur->next; } lock_release(&list->lock); return 0; }
/** * @brief send a dmq message * * peer - the peer structure on behalf of which we are sending * body - the body of the message * node - we send the message to this node * resp_cback - a response callback that gets called when the transaction is complete */ int dmq_send_message(dmq_peer_t *peer, str *body, dmq_node_t *node, dmq_resp_cback_t *resp_cback, int max_forwards, str *content_type) { uac_req_t uac_r; str str_hdr = {0, 0}; str from = {0, 0}, to = {0, 0}; dmq_cback_param_t *cb_param = NULL; int result = 0; int len = 0; if(!content_type) { LM_ERR("content-type is null\n"); return -1; } /* add Max-Forwards and Content-Type headers */ str_hdr.len = 34 + content_type->len + (CRLF_LEN * 2); str_hdr.s = pkg_malloc(str_hdr.len); if(str_hdr.s == NULL) { LM_ERR("no more pkg\n"); return -1; } len += sprintf(str_hdr.s, "Max-Forwards: %d" CRLF "Content-Type: %.*s" CRLF, max_forwards, content_type->len, content_type->s); str_hdr.len = len; cb_param = shm_malloc(sizeof(*cb_param)); if(cb_param == NULL) { LM_ERR("no more shm for building callback parameter\n"); goto error; } memset(cb_param, 0, sizeof(*cb_param)); cb_param->resp_cback = *resp_cback; cb_param->node = shm_dup_node(node); if(cb_param->node == NULL) { LM_ERR("error building callback parameter\n"); goto error; } if(build_uri_str(&peer->peer_id, &dmq_server_uri, &from) < 0) { LM_ERR("error building from string [username %.*s]\n", STR_FMT(&peer->peer_id)); goto error; } if(build_uri_str(&peer->peer_id, &node->uri, &to) < 0) { LM_ERR("error building to string\n"); goto error; } set_uac_req(&uac_r, &dmq_request_method, &str_hdr, body, NULL, TMCB_LOCAL_COMPLETED, dmq_tm_callback, (void *)cb_param); uac_r.ssock = &dmq_server_socket; result = tmb.t_request(&uac_r, &to, &to, &from, NULL); if(result < 0) { LM_ERR("error in tmb.t_request_within\n"); goto error; } pkg_free(str_hdr.s); pkg_free(from.s); pkg_free(to.s); return 0; error: pkg_free(str_hdr.s); if(from.s != NULL) pkg_free(from.s); if(to.s != NULL) pkg_free(to.s); if(cb_param) { if(cb_param->node) destroy_dmq_node(cb_param->node, 1); shm_free(cb_param); } return -1; }
/** * @brief build a dmq node */ dmq_node_t *build_dmq_node(str *uri, int shm) { dmq_node_t *ret = NULL; param_hooks_t hooks; param_t *params; /* For DNS-Lookups */ static char hn[256]; struct hostent *he; LM_DBG("build_dmq_node %.*s with %s memory\n", STR_FMT(uri), shm ? "shm" : "private"); if(shm) { ret = shm_malloc(sizeof(dmq_node_t)); if(ret == NULL) { LM_ERR("no more shm\n"); goto error; } memset(ret, 0, sizeof(dmq_node_t)); if(shm_str_dup(&ret->orig_uri, uri) < 0) { goto error; } } else { ret = pkg_malloc(sizeof(dmq_node_t)); if(ret == NULL) { LM_ERR("no more pkg\n"); goto error; } memset(ret, 0, sizeof(dmq_node_t)); if(pkg_str_dup(&ret->orig_uri, uri) < 0) { goto error; } } set_default_dmq_node_params(ret); if(parse_uri(ret->orig_uri.s, ret->orig_uri.len, &ret->uri) < 0 || ret->uri.host.len > 254) { LM_ERR("error parsing uri\n"); goto error; } /* if any parameters found, parse them */ if(parse_params(&ret->uri.params, CLASS_ANY, &hooks, ¶ms) < 0) { LM_ERR("error parsing params\n"); goto error; } /* if any params found */ if(params) { if(set_dmq_node_params(ret, params) < 0) { free_params(params); LM_ERR("error setting parameters\n"); goto error; } free_params(params); } else { LM_DBG("no dmqnode params found\n"); } /* resolve hostname */ strncpy(hn, ret->uri.host.s, ret->uri.host.len); hn[ret->uri.host.len] = '\0'; he = resolvehost(hn); if(he == 0) { LM_ERR("could not resolve %.*s\n", ret->uri.host.len, ret->uri.host.s); goto error; } hostent2ip_addr(&ret->ip_address, he, 0); return ret; error: if(ret != NULL) { destroy_dmq_node(ret, shm); } return NULL; }
/** * extract the node list from the body of a notification request SIP message * the SIP request will look something like: * KDMQ sip:10.0.0.0:5062 * To: ... * From: ... * Max-Forwards: ... * Content-Length: 22 * * sip:host1:port1;param1=value1 * sip:host2:port2;param2=value2 * ... */ int extract_node_list(dmq_node_list_t* update_list, struct sip_msg* msg) { int content_length, total_nodes = 0; str body; str tmp_uri; dmq_node_t *cur = NULL; dmq_node_t *ret, *find; char *tmp, *end, *match; if(!msg->content_length && (parse_headers(msg,HDR_CONTENTLENGTH_F,0)<0 || !msg->content_length)) { LM_ERR("no content length header found\n"); return -1; } content_length = get_content_length(msg); if(!content_length) { LM_DBG("content length is 0\n"); return total_nodes; } body.s = get_body(msg); body.len = content_length; tmp = body.s; end = body.s + body.len; /* acquire big list lock */ lock_get(&update_list->lock); while(tmp < end) { match = q_memchr(tmp, '\n', end - tmp); if(match) { match++; } else { /* for the last line - take all of it */ match = end; } /* create the orig_uri from the parsed uri line and trim it */ tmp_uri.s = tmp; tmp_uri.len = match - tmp - 1; tmp = match; /* trim the \r, \n and \0's */ trim_r(tmp_uri); find = build_dmq_node(&tmp_uri, 0); if(find==NULL) return -1; ret = find_dmq_node(update_list, find); if (!ret) { LM_DBG("found new node %.*s\n", STR_FMT(&tmp_uri)); cur = build_dmq_node(&tmp_uri, 1); if(!cur) { LM_ERR("error creating new dmq node\n"); goto error; } cur->next = update_list->nodes; update_list->nodes = cur; update_list->count++; total_nodes++; } else if (find->params && ret->status != find->status) { LM_DBG("updating status on %.*s from %d to %d\n", STR_FMT(&tmp_uri), ret->status, find->status); ret->status = find->status; total_nodes++; } destroy_dmq_node(find, 0); } /* release big list lock */ lock_release(&update_list->lock); return total_nodes; error: lock_release(&update_list->lock); return -1; }