struct list* define(char* name, char* replacement) { struct list* node; unsigned hash_value; if ((node = lookup(name)) == NULL) { node = malloc(sizeof(struct list)); if (node == NULL || (node->name = str_duplicate(name)) == NULL) { return NULL; } hash_value = hash(name); node->next = hash_table[hash_value]; hash_table[hash_value] = node; } else { free(node->replacement); } if ((node->replacement = str_duplicate(replacement)) == NULL) { return NULL; } return node; }
/* inserts an item to table, and removes the least item if the table is full */ int addcert2table(ttable *ptable, tcert_item *pcert) { tcert_item *pshmcert; unsigned int uhash; if (!(pshmcert=(tcert_item *)shm_malloc(sizeof(*pshmcert)))) { LOG(L_ERR, "AUTH_IDENTITY:addcert2table: No enough shared memory\n"); return -1; } memset(pshmcert, 0, sizeof(*pshmcert)); if (str_duplicate(&pshmcert->surl, &pcert->surl)) return -2; if (str_duplicate(&pshmcert->scertpem, &pcert->scertpem)) return -3; pshmcert->ivalidbefore=pcert->ivalidbefore; pshmcert->uaccessed=1; uhash=get_hash1_raw(pcert->surl.s, pcert->surl.len) & (CERTIFICATE_TABLE_ENTRIES-1); if (insert_into_table(ptable, (void*)pshmcert, uhash)) return -4; return 0; }
/* * set dialog's request uri and destination uri (optional) */ int set_dlg_target(dlg_t* _d, str* _ruri, str* _duri) { if (!_d || !_ruri) { LOG(L_ERR, "set_dlg_target(): Invalid parameter value\n"); return -1; } if (_d->rem_target.s) shm_free(_d->rem_target.s); if (_d->dst_uri.s) { shm_free(_d->dst_uri.s); _d->dst_uri.s = 0; _d->dst_uri.len = 0; } if (str_duplicate(&_d->rem_target, _ruri)) return -1; if (_duri && _duri->len) { if (str_duplicate(&_d->dst_uri, _duri)) return -1; } if (calculate_hooks(_d) < 0) { LOG(L_ERR, "set_dlg_target(): Error while calculating hooks\n"); return -1; } return 0; }
/* * Create a new dialog */ int new_dlg_uac(str* _cid, str* _ltag, unsigned int _lseq, str* _luri, str* _ruri, dlg_t** _d) { dlg_t* res; str generated_cid; str generated_ltag; if (!_cid) { /* if not given, compute new one */ generate_callid(&generated_cid); _cid = &generated_cid; } if (_cid && (!_ltag)) { /* if not given, compute new one */ generate_fromtag(&generated_ltag, _cid); _ltag = &generated_ltag; } if (_lseq == 0) _lseq = DEFAULT_CSEQ; if (!_cid || !_ltag || !_luri || !_ruri || !_d) { LOG(L_ERR, "new_dlg_uac(): Invalid parameter value\n"); return -1; } res = (dlg_t*)shm_malloc(sizeof(dlg_t)); if (res == 0) { LOG(L_ERR, "new_dlg_uac(): No memory left\n"); return -2; } /* Clear everything */ memset(res, 0, sizeof(dlg_t)); /* Make a copy of Call-ID */ if (str_duplicate(&res->id.call_id, _cid) < 0) return -3; /* Make a copy of local tag (usually From tag) */ if (str_duplicate(&res->id.loc_tag, _ltag) < 0) return -4; /* Make a copy of local URI (usually From) */ if (str_duplicate(&res->loc_uri, _luri) < 0) return -5; /* Make a copy of remote URI (usually To) */ if (str_duplicate(&res->rem_uri, _ruri) < 0) return -6; /* Make a copy of local sequence (usually CSeq) */ res->loc_seq.value = _lseq; /* And mark it as set */ res->loc_seq.is_set = 1; *_d = res; if (calculate_hooks(*_d) < 0) { LOG(L_ERR, "new_dlg_uac(): Error while calculating hooks\n"); /* FIXME: free everything here */ shm_free(res); return -2; } #ifdef DIALOG_CALLBACKS run_new_dlg_callbacks(DLG_CB_UAC, res, 0); #endif return 0; }
/* * Extract all information from a request * and update a dialog structure */ static inline int request2dlg(struct sip_msg* _m, dlg_t* _d) { str contact, rtag, callid; if (parse_headers(_m, HDR_EOH_F, 0) == -1) { LOG(L_ERR, "request2dlg(): Error while parsing headers"); return -1; } if (get_contact_uri(_m, &contact) < 0) return -2; if (contact.len) { if (_d->rem_target.s) shm_free(_d->rem_target.s); if (_d->dst_uri.s) { shm_free(_d->dst_uri.s); _d->dst_uri.s = 0; _d->dst_uri.len = 0; } if (str_duplicate(&_d->rem_target, &contact) < 0) return -3; } if (get_from_tag(_m, &rtag) < 0) goto err1; if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1; if (get_callid(_m, &callid) < 0) goto err2; if (callid.len && str_duplicate(&_d->id.call_id, &callid) < 0) goto err2; if (get_cseq_value(_m, &_d->rem_seq.value) < 0) goto err3; _d->rem_seq.is_set = 1; if (get_dlg_uri(_m->from, &_d->rem_uri) < 0) goto err3; if (get_dlg_uri(_m->to, &_d->loc_uri) < 0) goto err4; if (get_route_set(_m, &_d->route_set, NORMAL_ORDER) < 0) goto err5; return 0; err5: if (_d->loc_uri.s) shm_free(_d->loc_uri.s); _d->loc_uri.s = 0; _d->loc_uri.len = 0; err4: if (_d->rem_uri.s) shm_free(_d->rem_uri.s); _d->rem_uri.s = 0; _d->rem_uri.len = 0; err3: if (_d->id.call_id.s) shm_free(_d->id.call_id.s); _d->id.call_id.s = 0; _d->id.call_id.len = 0; err2: if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); _d->id.rem_tag.s = 0; _d->id.rem_tag.len = 0; err1: if (_d->rem_target.s) shm_free(_d->rem_target.s); _d->rem_target.s = 0; _d->rem_target.len = 0; return -4; }
/* * Establishing a new dialog, UAS side */ int new_dlg_uas(struct sip_msg* _req, int _code, /*str* _tag,*/ dlg_t** _d) { dlg_t* res; str tag; if (!_req || /*!_tag ||*/ !_d) { LOG(L_ERR, "new_dlg_uas(): Invalid parameter value\n"); return -1; } if (_code > 299) { DBG("new_dlg_uas(): Status code >= 300, no dialog created\n"); } res = (dlg_t*)shm_malloc(sizeof(dlg_t)); if (res == 0) { LOG(L_ERR, "new_dlg_uac(): No memory left\n"); return -3; } /* Clear everything */ memset(res, 0, sizeof(dlg_t)); if (request2dlg(_req, res) < 0) { LOG(L_ERR, "new_dlg_uas(): Error while converting request to dialog\n"); free_dlg(res); return -4; } if (_code > 100) { tag.s = tm_tags; tag.len = TOTAG_VALUE_LEN; calc_crc_suffix(_req, tm_tag_suffix); if (str_duplicate(&res->id.loc_tag, &tag) < 0) { free_dlg(res); return -5; } } *_d = res; if (_code < 100) (*_d)->state = DLG_NEW; else if (_code < 200) (*_d)->state = DLG_EARLY; else (*_d)->state = DLG_CONFIRMED; if (calculate_hooks(*_d) < 0) { LOG(L_ERR, "new_dlg_uas(): Error while calculating hooks\n"); free_dlg(res); return -6; } #ifdef DIALOG_CALLBACKS run_new_dlg_callbacks(DLG_CB_UAS, res, _req); #endif return 0; }
/* * Extract all necessary information from a response and put it * in a dialog structure */ static inline int response2dlg(struct sip_msg* _m, dlg_t* _d) { str contact, rtag; rtag.s=0; /* Parse the whole message, we will need all Record-Route headers */ if (parse_headers(_m, HDR_EOH_F, 0) == -1) { LOG(L_ERR, "response2dlg(): Error while parsing headers\n"); return -1; } if (get_contact_uri(_m, &contact) < 0) return -2; if (_d->rem_target.s) { shm_free(_d->rem_target.s); _d->rem_target.s = 0; _d->rem_target.len = 0; } if (_d->dst_uri.s) { shm_free(_d->dst_uri.s); _d->dst_uri.s = 0; _d->dst_uri.len = 0; } if (contact.len && str_duplicate(&_d->rem_target, &contact) < 0) return -3; if (get_to_tag(_m, &rtag) < 0) goto err1; //Its unlikely needed to update the tag with responses but for some reason i do it if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); if (rtag.len && str_duplicate(&_d->id.rem_tag, &rtag) < 0) goto err1; if (_d->route_set) shm_free_rr(&_d->route_set); if (get_route_set(_m, &_d->route_set, REVERSE_ORDER) < 0) goto err2; return 0; err2: if (_d->id.rem_tag.s) shm_free(_d->id.rem_tag.s); _d->id.rem_tag.s = 0; _d->id.rem_tag.len = 0; err1: if (_d->rem_target.s) shm_free(_d->rem_target.s); _d->rem_target.s = 0; _d->rem_target.len = 0; return -4; }
/* * Handle dialog in DLG_CONFIRMED state, we will be processing * a response to a request sent within a dialog */ static inline int dlg_confirmed_resp_uac(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh) { int code; str contact; code = _m->first_line.u.reply.statuscode; /* Dialog has been already confirmed, that means we received * a response to a request sent within the dialog. We will * update remote target URI if and only if the message sent was * a target refresher. */ /* IF we receive a 481 response, terminate the dialog because * the remote peer indicated that it didn't have the dialog * state anymore, signal this termination with a positive return * value */ if (code == 481) { _d->state = DLG_DESTROYED; return 1; } /* Do nothing if not 2xx */ if ((code < 200) || (code >= 300)) return 0; if (refresh_dialog_resp(_m, is_target_refresh)) { /* Get contact if any and update remote target */ if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) { LOG(L_ERR, "dlg_confirmed_resp_uac(): Error while parsing headers\n"); return -2; } /* Try to extract contact URI */ if (get_contact_uri(_m, &contact) < 0) return -3; /* If there is a contact URI */ if (contact.len) { /* Free old remote target and destination uri if any */ if (_d->rem_target.s) shm_free(_d->rem_target.s); if (_d->dst_uri.s) { shm_free(_d->dst_uri.s); _d->dst_uri.s = 0; _d->dst_uri.len = 0; } /* Duplicate new remote target */ if (str_duplicate(&_d->rem_target, &contact) < 0) return -4; } if (calculate_hooks(_d) < 0) return -1; } return 0; }
/* Parse and insert output fields from format string */ void parse_format_string(char *str) { char *name, *tmp, *i; int num_nodes = 0; size_t len; #ifdef DEBUG ASSERT(str); #endif len = strlen(str); if (len == 0) LOG_DIE("Empty format string provided"); /* Make a temporary copy of the string so we don't modify the original */ if ((tmp = str_duplicate(str)) == NULL) LOG_DIE("Cannot allocate memory for format string buffer"); for (i = tmp; (name = strtok(i, ",")); i = NULL) { /* Normalize input field text */ name = str_strip_whitespace(name); name = str_tolower(name); len = strlen(name); if (len == 0) continue; if (insert_field(name, len)) num_nodes++; } free(tmp); if (num_nodes == 0) LOG_DIE("No valid fields found in format string"); #ifdef DEBUG int j, num_buckets = 0, num_chain, max_chain = 0; FORMAT_NODE *node; for (j = 0; j < HASHSIZE; j++) { if (fields[j]) num_buckets++; num_chain = 0; for (node = fields[j]; node != NULL; node = node->next) num_chain++; if (num_chain > max_chain) max_chain = num_chain; } PRINT("----------------------------"); PRINT("Hash buckets: %d", HASHSIZE); PRINT("Nodes inserted: %d", num_nodes); PRINT("Buckets in use: %d", num_buckets); PRINT("Hash collisions: %d", num_nodes - num_buckets); PRINT("Longest hash chain: %d", max_chain); PRINT("----------------------------"); #endif return; }
void *parser(void *arg) { struct input_args *in_args = (struct input_args *)arg; while (1) { struct page *page = (struct page *)unbounded_buffer_get(in_args->page_queue); if (page == NULL) break; char *start = page->content; while ((start = strstr(start, "link:")) != NULL) { if (start > page->content && *(start - 1) != ' ' && *(start - 1) != '\n') { start = start + 5; continue; } char *end = start + 5; while (*end != ' ' && *end != '\n' && *end != '\0') end++; if (*end == '\0') { char *url = str_duplicate(start + 5); in_args->edge(page->url, url); bounded_buffer_put(in_args->url_queue, (void *)url); break; } else { char tmp = *end; *end = '\0'; char *url = str_duplicate(start + 5); in_args->edge(page->url, url); bounded_buffer_put(in_args->url_queue, (void *)url); *end = tmp; start = end + 1; } } mem_free(page->url); mem_free(page->content); mem_free(page); unbounded_buffer_done(in_args->page_queue); mutex_lock(in_args->done_mutex); cond_signal(in_args->done_cond); mutex_unlock(in_args->done_mutex); } return NULL; }
/* * UAS side - update a dialog from a request */ int dlg_request_uas(dlg_t* _d, struct sip_msg* _m, target_refresh_t is_target_refresh) { str contact; int cseq; if (!_d || !_m) { LOG(L_ERR, "dlg_request_uas(): Invalid parameter value\n"); return -1; } /* We must check if the request is not out of order or retransmission * first, if so then we will not update anything */ if (parse_headers(_m, HDR_CSEQ_F, 0) == -1) { LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n"); return -2; } if (get_cseq_value(_m, (unsigned int*)&cseq) < 0) return -3; if (_d->rem_seq.is_set && (cseq <= _d->rem_seq.value)) return 0; /* Neither out of order nor retransmission -> update */ _d->rem_seq.value = cseq; _d->rem_seq.is_set = 1; /* We will als update remote target URI if the message * is target refresher */ if (refresh_dialog_req(_m, is_target_refresh)) { /* target refresher */ if (parse_headers(_m, HDR_CONTACT_F, 0) == -1) { LOG(L_ERR, "dlg_request_uas(): Error while parsing headers\n"); return -4; } if (get_contact_uri(_m, &contact) < 0) return -5; if (contact.len) { if (_d->rem_target.s) shm_free(_d->rem_target.s); if (_d->dst_uri.s) { shm_free(_d->dst_uri.s); _d->dst_uri.s = 0; _d->dst_uri.len = 0; } if (str_duplicate(&_d->rem_target, &contact) < 0) return -6; } if (calculate_hooks(_d) < 0) return -1; } return 0; }
BOOL str_creationinfo_set(CreationInfo *info, CSTR creator, CSTR reason, time_t time_set) { if (IS_NULL(info) || IS_NULL(creator) || IS_NULL(reason)) return FALSE; str_creator_set(&(info->creator), creator, time_set); if (IS_NOT_NULL(info->reason)) mem_free(info->reason); info->reason = str_duplicate(reason); return TRUE; }
void hashset_insert(hashset_t *h, char *str) { size_t bucket = hashset_hash(str) % h->buckets; mutex_lock(&h->mutexes[bucket]); node_t *node = h->heads[bucket]; while (node != NULL) { if (strcmp((char *)node->ptr, str) == 0) break; node = node->next; } if (node == NULL) { node = (node_t *)mem_malloc(sizeof(node_t)); node->ptr = (void *)str_duplicate(str); node->next = h->heads[bucket]; h->heads[bucket] = node; } mutex_unlock(&h->mutexes[bucket]); }
BOOL str_creator_set(Creator *creator, CSTR name, time_t time_set) { if (IS_NOT_NULL(creator)) { if (IS_NOT_NULL(name)) { if (IS_NOT_NULL(creator->name)) mem_free(creator->name); creator->name = str_duplicate(name); } creator->time = time_set != 0 ? time_set : NOW; return TRUE; } else return FALSE; }
/* * UAS side - update dialog state and to tag */ int update_dlg_uas(dlg_t *_d, int _code, str* _tag) { if (_d->state == DLG_CONFIRMED) { LOG(L_ERR, "update_dlg_uas(): Dialog is already confirmed\n"); return -1; } else if (_d->state == DLG_DESTROYED) { LOG(L_ERR, "update_dlg_uas(): Dialog is already destroyed\n"); return -2; } if (_tag && _tag->s) { if (_d->id.loc_tag.s) { if ((_tag->len == _d->id.loc_tag.len) && (!memcmp(_tag->s, _d->id.loc_tag.s, _tag->len))) { LOG(L_DBG, "update_dlg_uas(): Local tag is already set\n"); } else { LOG(L_ERR, "update_dlg_uas(): ERROR: trying to rewrite local tag\n"); return -3; } } else { if (str_duplicate(&_d->id.loc_tag, _tag) < 0) { LOG(L_ERR, "update_dlg_uas(): Not enough memory\n"); return -4; } } } if ((100 < _code) && (_code < 200)) _d->state = DLG_EARLY; else if (_code < 300) _d->state = DLG_CONFIRMED; else _d->state = DLG_DESTROYED; return 0; }
int crawl(char *start_url, int download_workers, int parse_workers, int queue_size, char *(*_fetch_fn)(char *url), void (*_edge_fn)(char *from, char *to)) { int i; bounded_buffer_t url_queue; unbounded_buffer_t page_queue; hashset_t url_set; bounded_buffer_init(&url_queue, queue_size); unbounded_buffer_init(&page_queue); hashset_init(&url_set, HASHSET_BUCKETS); bounded_buffer_put(&url_queue, (void *)str_duplicate(start_url)); mutex_t done_mutex; cond_t done_cond; mutex_init(&done_mutex); cond_init(&done_cond); struct input_args in_args; in_args.url_queue = &url_queue; in_args.page_queue = &page_queue; in_args.url_set = &url_set; in_args.fetch = _fetch_fn; in_args.edge = _edge_fn; in_args.done_mutex = &done_mutex; in_args.done_cond = &done_cond; thread_t downloaders[download_workers]; thread_t parsers[parse_workers]; for (i = 0; i < download_workers; i++) thread_create(&downloaders[i], downloader, (void *)&in_args); for (i = 0; i < parse_workers; i++) thread_create(&parsers[i], parser, (void *)&in_args); while (1) { mutex_lock(&done_mutex); mutex_lock(&url_queue.mutex); mutex_lock(&url_queue.worker_mutex); mutex_lock(&page_queue.mutex); mutex_lock(&page_queue.worker_mutex); if (url_queue.count == 0 && url_queue.workers == 0 && page_queue.count == 0 && page_queue.workers == 0) { url_queue.done = 1; page_queue.done = 1; cond_broadcast(&url_queue.empty); cond_broadcast(&url_queue.fill); cond_broadcast(&page_queue.fill); mutex_unlock(&url_queue.mutex); mutex_unlock(&url_queue.worker_mutex); mutex_unlock(&page_queue.mutex); mutex_unlock(&page_queue.worker_mutex); mutex_unlock(&done_mutex); break; } else { mutex_unlock(&url_queue.mutex); mutex_unlock(&url_queue.worker_mutex); mutex_unlock(&page_queue.mutex); mutex_unlock(&page_queue.worker_mutex); cond_wait(&done_cond, &done_mutex); mutex_unlock(&done_mutex); } } for (i = 0; i < download_workers; i++) thread_join(downloaders[i], NULL); for (i = 0; i < parse_workers; i++) thread_join(parsers[i], NULL); bounded_buffer_destroy(&url_queue); unbounded_buffer_destroy(&page_queue); hashset_destroy(&url_set); return 0; }
/* inserts a callid item to table, and removes the least item if the table is full */ int proc_cid(ttable *ptable, str *scid, str *sftag, unsigned int ucseq, time_t ivalidbefore) { tcid_item *pshmcid, *pcid_item; tdlg_item *pshmdlg, *pdlg_item, *pdlg_item_prev; unsigned int uhash; /* we suppose that this SIP request is not replayed so it doesn't exist in the table so we prepare to insert */ if (!(pshmdlg=(tdlg_item *)shm_malloc(sizeof(*pshmdlg)))) { LOG(L_ERR, "AUTH_IDENTITY:addcid2table: No enough shared memory\n"); return -1; } memset(pshmdlg, 0, sizeof(*pshmdlg)); if (str_duplicate(&pshmdlg->sftag, sftag)) return -2; pshmdlg->ucseq=ucseq; /* we're looking for this call-id item if exists */ uhash=get_hash1_raw(scid->s, scid->len) & (CALLID_TABLE_ENTRIES-1); lock_element(&ptable->entries[uhash]); pcid_item = search_item_in_table_unsafe(ptable, (const void *)scid, /* Call-id is the key */ uhash); /* we've found one call-id so we're looking for the required SIP request */ if (pcid_item) { for (pdlg_item=pcid_item->pdlgs, pdlg_item_prev=NULL; pdlg_item; pdlg_item=pdlg_item->pnext) { if (pdlg_item->sftag.len==sftag->len && !memcmp(pdlg_item->sftag.s, sftag->s, sftag->len)) { /* we found this call with this from tag */ if (pdlg_item->ucseq>=ucseq) { /* we've found this or older request in the table! this call is replayed! */ release_element(&ptable->entries[uhash]); shm_free(pshmdlg->sftag.s); shm_free(pshmdlg); return AUTH_FOUND; } else { /* this is another later request whithin this dialog so we update the saved cseq */ pdlg_item->ucseq=ucseq; release_element(&ptable->entries[uhash]); shm_free(pshmdlg->sftag.s); shm_free(pshmdlg); return 0; } } /* we save the previous dialog item in order to append a new item more easily */ pdlg_item_prev ? (pdlg_item_prev=pdlg_item_prev->pnext) : (pdlg_item_prev=pdlg_item); } /* we append this to item dialogs*/ pdlg_item_prev->pnext=pshmdlg; /* this is the latest request; we hold all request concerned this call-id until the latest request is valid */ pcid_item->ivalidbefore=ivalidbefore; } release_element(&ptable->entries[uhash]); if (!pcid_item) { /* this is the first request with this call-id */ if (!(pshmcid=(tcid_item *)shm_malloc(sizeof(*pshmcid)))) { LOG(L_ERR, "AUTH_IDENTITY:addcid2table: No enough shared memory\n"); return -4; } memset(pshmcid, 0, sizeof(*pshmcid)); if (str_duplicate(&pshmcid->scid, scid)) { return -5; } pshmcid->ivalidbefore=ivalidbefore; pshmcid->pdlgs=pshmdlg; if (insert_into_table(ptable, (void*)pshmcid, uhash)) return -6; } return 0; }