/// Worker threads handle most SIP message processing. static int worker_thread(void* p) { // Set up data to always process incoming messages at the first PJSIP // module after our module. pjsip_process_rdata_param rp; pjsip_process_rdata_param_default(&rp); rp.start_mod = &mod_stack; rp.idx_after_start = 1; LOG_DEBUG("Worker thread started"); struct rx_msg_qe qe = {0}; while (rx_msg_q.pop(qe)) { pjsip_rx_data* rdata = qe.rdata; if (rdata) { LOG_DEBUG("Worker thread dequeue message %p", rdata); pjsip_endpt_process_rx_data(stack_data.endpt, rdata, &rp, NULL); LOG_DEBUG("Worker thread completed processing message %p", rdata); pjsip_rx_data_free_cloned(rdata); struct timespec done_time; if (clock_gettime(CLOCK_MONOTONIC, &done_time) == 0) { long latency_us = (done_time.tv_nsec - qe.rx_time.tv_nsec) / 1000L + (done_time.tv_sec - qe.rx_time.tv_sec) * 1000000L; LOG_DEBUG("Request latency = %ldus", latency_us); latency_accumulator->accumulate(latency_us); latency_accumulator->refresh(); } else { LOG_ERROR("Failed to get done timestamp: %s", strerror(errno)); } } } LOG_DEBUG("Worker thread ended"); return 0; }
/// Worker threads handle most SIP message processing. static int worker_thread(void* p) { // Set up data to always process incoming messages at the first PJSIP // module after our module. pjsip_process_rdata_param rp; pjsip_process_rdata_param_default(&rp); rp.start_mod = &mod_stack; rp.idx_after_start = 1; LOG_DEBUG("Worker thread started"); struct rx_msg_qe qe = {0}; while (rx_msg_q.pop(qe)) { pjsip_rx_data* rdata = qe.rdata; if (rdata) { LOG_DEBUG("Worker thread dequeue message %p", rdata); pjsip_endpt_process_rx_data(stack_data.endpt, rdata, &rp, NULL); LOG_DEBUG("Worker thread completed processing message %p", rdata); pjsip_rx_data_free_cloned(rdata); unsigned long latency_us; if (qe.stop_watch.read(latency_us)) { LOG_DEBUG("Request latency = %ldus", latency_us); latency_accumulator->accumulate(latency_us); load_monitor->request_complete(latency_us); } else { LOG_ERROR("Failed to get done timestamp: %s", strerror(errno)); } } } LOG_DEBUG("Worker thread ended"); return 0; }
static int distribute(void *data) { static pjsip_process_rdata_param param = { .start_mod = &distributor_mod, .idx_after_start = 1, }; pj_bool_t handled = PJ_FALSE; pjsip_rx_data *rdata = data; int is_request = rdata->msg_info.msg->type == PJSIP_REQUEST_MSG; int is_ack = is_request ? rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD : 0; struct ast_sip_endpoint *endpoint; pjsip_endpt_process_rx_data(ast_sip_get_pjsip_endpoint(), rdata, ¶m, &handled); if (!handled && is_request && !is_ack) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 501, NULL, NULL, NULL); } /* The endpoint_mod stores an endpoint reference in the mod_data of rdata. This * is the only appropriate spot to actually decrement the reference. */ endpoint = rdata->endpt_info.mod_data[endpoint_mod.id]; ao2_cleanup(endpoint); pjsip_rx_data_free_cloned(rdata); return 0; } struct ast_sip_endpoint *ast_pjsip_rdata_get_endpoint(pjsip_rx_data *rdata) { struct ast_sip_endpoint *endpoint = rdata->endpt_info.mod_data[endpoint_mod.id]; if (endpoint) { ao2_ref(endpoint, +1); } return endpoint; } static int suspects_sort(const void *obj, const void *arg, int flags) { const struct unidentified_request *object_left = obj; const struct unidentified_request *object_right = arg; const char *right_key = arg; int cmp; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_OBJECT: right_key = object_right->src_name; /* Fall through */ case OBJ_SEARCH_KEY: cmp = strcmp(object_left->src_name, right_key); break; case OBJ_SEARCH_PARTIAL_KEY: cmp = strncmp(object_left->src_name, right_key, strlen(right_key)); break; default: cmp = 0; break; } return cmp; } static int suspects_compare(void *obj, void *arg, int flags) { const struct unidentified_request *object_left = obj; const struct unidentified_request *object_right = arg; const char *right_key = arg; int cmp = 0; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_OBJECT: right_key = object_right->src_name; /* Fall through */ case OBJ_SEARCH_KEY: if (strcmp(object_left->src_name, right_key) == 0) { cmp = CMP_MATCH; } break; case OBJ_SEARCH_PARTIAL_KEY: if (strncmp(object_left->src_name, right_key, strlen(right_key)) == 0) { cmp = CMP_MATCH; } break; default: cmp = 0; break; } return cmp; } static int suspects_hash(const void *obj, int flags) { const struct unidentified_request *object; const char *key; switch (flags & OBJ_SEARCH_MASK) { case OBJ_SEARCH_KEY: key = obj; break; case OBJ_SEARCH_OBJECT: object = obj; key = object->src_name; break; default: /* Hash can only work on something with a full key. */ ast_assert(0); return 0; } return ast_str_hash(key); } static struct ao2_container *cli_unid_get_container(const char *regex) { struct ao2_container *s_container; s_container = ao2_container_alloc_list(AO2_ALLOC_OPT_LOCK_NOLOCK, 0, suspects_sort, suspects_compare); if (!s_container) { return NULL; } if (ao2_container_dup(s_container, unidentified_requests, 0)) { ao2_ref(s_container, -1); return NULL; } return s_container; } static int cli_unid_iterate(void *container, ao2_callback_fn callback, void *args) { ao2_callback(container, 0, callback, args); return 0; }