static pj_bool_t my_on_rx_request(pjsip_rx_data *rdata) { /* Check that this is our request. */ if (pj_strcmp2(&rdata->msg_info.cid->id, CALL_ID_HDR) == 0) { /* It is! */ /* Send response. */ pjsip_tx_data *tdata; pjsip_response_addr res_addr; pj_status_t status; status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) { recv_status = status; return PJ_TRUE; } status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); if (status != PJ_SUCCESS) { recv_status = status; pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); if (status != PJ_SUCCESS) { recv_status = status; pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } return PJ_TRUE; } /* Not ours. */ return PJ_FALSE; }
static pj_bool_t rt_on_rx_request(pjsip_rx_data *rdata) { if (!pj_strncmp(&rdata->msg_info.cid->id, &rt_call_id, rt_call_id.slen)) { pjsip_tx_data *tdata; pjsip_response_addr res_addr; pj_status_t status; status = pjsip_endpt_create_response( endpt, rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(" error creating response", status); return PJ_TRUE; } status = pjsip_get_response_addr( tdata->pool, rdata, &res_addr); if (status != PJ_SUCCESS) { app_perror(" error in get response address", status); pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } status = pjsip_endpt_send_response( endpt, &res_addr, tdata, NULL, NULL); if (status != PJ_SUCCESS) { app_perror(" error sending response", status); pjsip_tx_data_dec_ref(tdata); return PJ_TRUE; } return PJ_TRUE; } return PJ_FALSE; }
static pj_bool_t authenticate(pjsip_rx_data *rdata) { RAII_VAR(struct ast_sip_endpoint *, endpoint, ast_pjsip_rdata_get_endpoint(rdata), ao2_cleanup); int is_ack = rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD; ast_assert(endpoint != NULL); if (is_ack) { return PJ_FALSE; } if (ast_sip_requires_authentication(endpoint, rdata)) { pjsip_tx_data *tdata; struct unidentified_request *unid; pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), rdata, 401, NULL, &tdata); switch (ast_sip_check_authentication(endpoint, rdata, tdata)) { case AST_SIP_AUTHENTICATION_CHALLENGE: /* Send the 401 we created for them */ ast_sip_report_auth_challenge_sent(endpoint, rdata, tdata); if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); } return PJ_TRUE; case AST_SIP_AUTHENTICATION_SUCCESS: /* See note in endpoint_lookup about not holding an unnecessary write lock */ unid = ao2_find(unidentified_requests, rdata->pkt_info.src_name, OBJ_SEARCH_KEY); if (unid) { ao2_unlink(unidentified_requests, unid); ao2_ref(unid, -1); } ast_sip_report_auth_success(endpoint, rdata); break; case AST_SIP_AUTHENTICATION_FAILED: log_failed_request(rdata, "Failed to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); if (pjsip_endpt_send_response2(ast_sip_get_pjsip_endpoint(), rdata, tdata, NULL, NULL) != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); } return PJ_TRUE; case AST_SIP_AUTHENTICATION_ERROR: log_failed_request(rdata, "Error to authenticate", 0, 0); ast_sip_report_auth_failed_challenge_response(endpoint, rdata); pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } pjsip_tx_data_dec_ref(tdata); } else if (endpoint == artificial_endpoint) { /* Uh. Oh. The artificial endpoint couldn't challenge so block the request. */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } return PJ_FALSE; }
/* * A simple registrar, invoked by default_mod_on_rx_request() */ static void simple_registrar(pjsip_rx_data *rdata) { pjsip_tx_data *tdata; const pjsip_expires_hdr *exp; const pjsip_hdr *h; unsigned cnt = 0; pjsip_generic_string_hdr *srv; pj_status_t status; status = pjsip_endpt_create_response(pjsua_get_pjsip_endpt(), rdata, 200, NULL, &tdata); if (status != PJ_SUCCESS) return; exp = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); h = rdata->msg_info.msg->hdr.next; while (h != &rdata->msg_info.msg->hdr) { if (h->type == PJSIP_H_CONTACT) { const pjsip_contact_hdr *c = (const pjsip_contact_hdr*)h; int e = c->expires; if (e < 0) { if (exp) e = exp->ivalue; else e = 3600; } if (e > 0) { pjsip_contact_hdr *nc = (pjsip_contact_hdr*) pjsip_hdr_clone(tdata->pool, h); nc->expires = e; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)nc); ++cnt; } } h = h->next; } srv = pjsip_generic_string_hdr_create(tdata->pool, NULL, NULL); srv->name = pj_str((char*)"Server"); srv->hvalue = pj_str((char*)"pjsua simple registrar"); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)srv); pjsip_endpt_send_response2(pjsua_get_pjsip_endpt(), rdata, tdata, NULL, NULL); }
pj_status_t PJUtils::create_response(pjsip_endpoint* endpt, const pjsip_rx_data* rdata, int st_code, const pj_str_t* st_text, pjsip_tx_data** p_tdata) { pj_status_t status = pjsip_endpt_create_response(endpt, rdata, st_code, st_text, p_tdata); if (status == PJ_SUCCESS) { // Copy the SAS trail across from the request. set_trail(*p_tdata, get_trail(rdata)); } return status; }
/* Schedule timer to send response for the specified UAS transaction */ static void schedule_send_response( pjsip_rx_data *rdata, const pj_str_t *tsx_key, int status_code, int msec_delay ) { pj_status_t status; pjsip_tx_data *tdata; pj_timer_entry *t; struct response *r; pj_time_val delay; status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(" error: unable to create response", status); test_complete = -198; return; } r = PJ_POOL_ALLOC_T(tdata->pool, struct response); pj_strdup(tdata->pool, &r->tsx_key, tsx_key); r->tdata = tdata; delay.sec = 0; delay.msec = msec_delay; pj_time_val_normalize(&delay); t = PJ_POOL_ZALLOC_T(tdata->pool, pj_timer_entry); t->user_data = r; t->cb = &send_response_timer; status = pjsip_endpt_schedule_timer(endpt, t, &delay); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); app_perror(" error: unable to schedule timer", status); test_complete = -199; return; } }
/* Utility to send response. */ static void send_response( pjsip_rx_data *rdata, pjsip_transaction *tsx, int status_code ) { pj_status_t status; pjsip_tx_data *tdata; status = pjsip_endpt_create_response( endpt, rdata, status_code, NULL, &tdata); if (status != PJ_SUCCESS) { app_perror(" error: unable to create response", status); test_complete = -196; return; } status = pjsip_tsx_send_msg(tsx, tdata); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); // Some tests do expect failure! //app_perror(" error: unable to send response", status); //test_complete = -197; return; } }
pj_status_t PJUtils::create_response(pjsip_endpoint* endpt, const pjsip_rx_data* rdata, int st_code, const pj_str_t* st_text, pjsip_tx_data** p_tdata) { pj_status_t status = pjsip_endpt_create_response(endpt, rdata, st_code, st_text, p_tdata); if (status == PJ_SUCCESS) { // Copy the SAS trail across from the request. set_trail(*p_tdata, get_trail(rdata)); // Some headers should always be copied onto responses, like // charging headers PJUtils::clone_header(&STR_P_C_V, rdata->msg_info.msg, (*p_tdata)->msg, (*p_tdata)->pool); PJUtils::clone_header(&STR_P_C_F_A, rdata->msg_info.msg, (*p_tdata)->msg, (*p_tdata)->pool); } return status; }
/* * create response benchmark */ static int create_response_bench(pj_timestamp *p_elapsed) { enum { COUNT = 100 }; unsigned i, j; pjsip_via_hdr *via; pjsip_rx_data rdata; pjsip_tx_data *request; pjsip_tx_data *tdata[COUNT]; pj_timestamp t1, t2, elapsed; pj_status_t status; /* Create the request first. */ pj_str_t str_target = pj_str("sip:[email protected]"); pj_str_t str_from = pj_str("\"Local User\" <sip:[email protected]>"); pj_str_t str_to = pj_str("\"Remote User\" <sip:[email protected]>"); pj_str_t str_contact = str_from; status = pjsip_endpt_create_request(endpt, &pjsip_invite_method, &str_target, &str_from, &str_to, &str_contact, NULL, -1, NULL, &request); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); return status; } /* Create several Via headers */ via = pjsip_via_hdr_create(request->pool); via->sent_by.host = pj_str("192.168.0.7"); via->sent_by.port = 5061; via->transport = pj_str("udp"); via->rport_param = 0; via->branch_param = pj_str("012345678901234567890123456789"); via->recvd_param = pj_str("192.168.0.7"); pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*) pjsip_hdr_clone(request->pool, via)); pjsip_msg_insert_first_hdr(request->msg, (pjsip_hdr*)via); /* Create "dummy" rdata from the tdata */ pj_bzero(&rdata, sizeof(pjsip_rx_data)); rdata.tp_info.pool = request->pool; rdata.msg_info.msg = request->msg; rdata.msg_info.from = (pjsip_from_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); rdata.msg_info.to = (pjsip_to_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_TO, NULL); rdata.msg_info.cseq = (pjsip_cseq_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_CSEQ, NULL); rdata.msg_info.cid = (pjsip_cid_hdr*) pjsip_msg_find_hdr(request->msg, PJSIP_H_FROM, NULL); rdata.msg_info.via = via; /* * Now benchmark create_response */ elapsed.u64 = 0; for (i=0; i<LOOP; i+=COUNT) { pj_bzero(tdata, sizeof(tdata)); pj_get_timestamp(&t1); for (j=0; j<COUNT; ++j) { status = pjsip_endpt_create_response(endpt, &rdata, 200, NULL, &tdata[j]); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); goto on_error; } } pj_get_timestamp(&t2); pj_sub_timestamp(&t2, &t1); pj_add_timestamp(&elapsed, &t2); for (j=0; j<COUNT; ++j) pjsip_tx_data_dec_ref(tdata[j]); } p_elapsed->u64 = elapsed.u64; pjsip_tx_data_dec_ref(request); return PJ_SUCCESS; on_error: for (i=0; i<COUNT; ++i) { if (tdata[i]) pjsip_tx_data_dec_ref(tdata[i]); } return -400; }
/* * This tests various core message creation functions. */ static int core_txdata_test(void) { pj_status_t status; pj_str_t target, from, to, contact, body; pjsip_rx_data dummy_rdata; pjsip_tx_data *invite, *invite2, *cancel, *response, *ack; PJ_LOG(3,(THIS_FILE, " core transmit data test")); /* Create INVITE request. */ target = pj_str("tel:+1"); from = pj_str("tel:+0"); to = pj_str("tel:+1"); contact = pj_str("Bob <sip:[email protected];user=phone>"); body = pj_str("Hello world!"); status = pjsip_endpt_create_request( endpt, &pjsip_invite_method, &target, &from, &to, &contact, NULL, 10, &body, &invite); if (status != PJ_SUCCESS) { app_perror(" error: unable to create request", status); return -10; } /* Buffer must be invalid. */ if (pjsip_tx_data_is_valid(invite) != 0) { PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); return -14; } /* Reference counter must be set to 1. */ if (pj_atomic_get(invite->ref_cnt) != 1) { PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); return -15; } /* Check message type. */ if (invite->msg->type != PJSIP_REQUEST_MSG) return -16; /* Check method. */ if (invite->msg->line.req.method.id != PJSIP_INVITE_METHOD) return -17; /* Check that mandatory headers are present. */ if (HFIND(invite->msg, from, FROM) == 0) return -20; if (HFIND(invite->msg, to, TO) == 0) return -21; if (HFIND(invite->msg, contact, CONTACT) == 0) return -22; if (HFIND(invite->msg, cid, CALL_ID) == 0) return -23; if (HFIND(invite->msg, cseq, CSEQ) == 0) return -24; do { pjsip_via_hdr *via = HFIND(invite->msg, via, VIA); if (via == NULL) return -25; /* Branch param must be empty. */ if (via->branch_param.slen != 0) return -26; } while (0); if (invite->msg->body == NULL) return -28; /* Create another INVITE request from first request. */ status = pjsip_endpt_create_request_from_hdr( endpt, &pjsip_invite_method, invite->msg->line.req.uri, HFIND(invite->msg,from,FROM), HFIND(invite->msg,to,TO), HFIND(invite->msg,contact,CONTACT), HFIND(invite->msg,cid,CALL_ID), 10, &body, &invite2); if (status != PJ_SUCCESS) { app_perror(" error: create second request failed", status); return -30; } /* Buffer must be invalid. */ if (pjsip_tx_data_is_valid(invite2) != 0) { PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); return -34; } /* Reference counter must be set to 1. */ if (pj_atomic_get(invite2->ref_cnt) != 1) { PJ_LOG(3,(THIS_FILE, " error: invalid reference counter")); return -35; } /* Check message type. */ if (invite2->msg->type != PJSIP_REQUEST_MSG) return -36; /* Check method. */ if (invite2->msg->line.req.method.id != PJSIP_INVITE_METHOD) return -37; /* Check that mandatory headers are again present. */ if (HFIND(invite2->msg, from, FROM) == 0) return -40; if (HFIND(invite2->msg, to, TO) == 0) return -41; if (HFIND(invite2->msg, contact, CONTACT) == 0) return -42; if (HFIND(invite2->msg, cid, CALL_ID) == 0) return -43; if (HFIND(invite2->msg, cseq, CSEQ) == 0) return -44; if (HFIND(invite2->msg, via, VIA) == 0) return -45; /* if (HFIND(invite2->msg, ctype, CONTENT_TYPE) == 0) return -46; if (HFIND(invite2->msg, clen, CONTENT_LENGTH) == 0) return -47; */ if (invite2->msg->body == NULL) return -48; /* Done checking invite2. We can delete this. */ if (pjsip_tx_data_dec_ref(invite2) != PJSIP_EBUFDESTROYED) { PJ_LOG(3,(THIS_FILE, " error: request buffer not destroyed!")); return -49; } /* Initialize dummy rdata (to simulate receiving a request) * We should never do this in real application, as there are many * many more fields need to be initialized!! */ dummy_rdata.msg_info.cid = HFIND(invite->msg, cid, CALL_ID); dummy_rdata.msg_info.clen = NULL; dummy_rdata.msg_info.cseq = HFIND(invite->msg, cseq, CSEQ); dummy_rdata.msg_info.ctype = NULL; dummy_rdata.msg_info.from = HFIND(invite->msg, from, FROM); dummy_rdata.msg_info.max_fwd = NULL; dummy_rdata.msg_info.msg = invite->msg; dummy_rdata.msg_info.record_route = NULL; dummy_rdata.msg_info.require = NULL; dummy_rdata.msg_info.route = NULL; dummy_rdata.msg_info.to = HFIND(invite->msg, to, TO); dummy_rdata.msg_info.via = HFIND(invite->msg, via, VIA); /* Create a response message for the request. */ status = pjsip_endpt_create_response( endpt, &dummy_rdata, 301, NULL, &response); if (status != PJ_SUCCESS) { app_perror(" error: unable to create response", status); return -50; } /* Buffer must be invalid. */ if (pjsip_tx_data_is_valid(response) != 0) { PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); return -54; } /* Check reference counter. */ if (pj_atomic_get(response->ref_cnt) != 1) { PJ_LOG(3,(THIS_FILE, " error: invalid ref count in response")); return -55; } /* Check message type. */ if (response->msg->type != PJSIP_RESPONSE_MSG) return -56; /* Check correct status is set. */ if (response->msg->line.status.code != 301) return -57; /* Check that mandatory headers are again present. */ if (HFIND(response->msg, from, FROM) == 0) return -60; if (HFIND(response->msg, to, TO) == 0) return -61; /* if (HFIND(response->msg, contact, CONTACT) == 0) return -62; */ if (HFIND(response->msg, cid, CALL_ID) == 0) return -63; if (HFIND(response->msg, cseq, CSEQ) == 0) return -64; if (HFIND(response->msg, via, VIA) == 0) return -65; /* This response message will be used later when creating ACK */ /* Create CANCEL request for the original request. */ status = pjsip_endpt_create_cancel( endpt, invite, &cancel); if (status != PJ_SUCCESS) { app_perror(" error: unable to create CANCEL request", status); return -80; } /* Buffer must be invalid. */ if (pjsip_tx_data_is_valid(cancel) != 0) { PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); return -84; } /* Check reference counter. */ if (pj_atomic_get(cancel->ref_cnt) != 1) { PJ_LOG(3,(THIS_FILE, " error: invalid ref count in CANCEL request")); return -85; } /* Check message type. */ if (cancel->msg->type != PJSIP_REQUEST_MSG) return -86; /* Check method. */ if (cancel->msg->line.req.method.id != PJSIP_CANCEL_METHOD) return -87; /* Check that mandatory headers are again present. */ if (HFIND(cancel->msg, from, FROM) == 0) return -90; if (HFIND(cancel->msg, to, TO) == 0) return -91; /* if (HFIND(cancel->msg, contact, CONTACT) == 0) return -92; */ if (HFIND(cancel->msg, cid, CALL_ID) == 0) return -93; if (HFIND(cancel->msg, cseq, CSEQ) == 0) return -94; if (HFIND(cancel->msg, via, VIA) == 0) return -95; /* Done checking CANCEL request. */ if (pjsip_tx_data_dec_ref(cancel) != PJSIP_EBUFDESTROYED) { PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); return -99; } /* Modify dummy_rdata to simulate receiving response. */ pj_bzero(&dummy_rdata, sizeof(dummy_rdata)); dummy_rdata.msg_info.msg = response->msg; dummy_rdata.msg_info.to = HFIND(response->msg, to, TO); /* Create ACK request */ status = pjsip_endpt_create_ack( endpt, invite, &dummy_rdata, &ack ); if (status != PJ_SUCCESS) { PJ_LOG(3,(THIS_FILE, " error: unable to create ACK")); return -100; } /* Buffer must be invalid. */ if (pjsip_tx_data_is_valid(ack) != 0) { PJ_LOG(3,(THIS_FILE, " error: buffer must be invalid")); return -104; } /* Check reference counter. */ if (pj_atomic_get(ack->ref_cnt) != 1) { PJ_LOG(3,(THIS_FILE, " error: invalid ref count in ACK request")); return -105; } /* Check message type. */ if (ack->msg->type != PJSIP_REQUEST_MSG) return -106; /* Check method. */ if (ack->msg->line.req.method.id != PJSIP_ACK_METHOD) return -107; /* Check Request-URI is present. */ if (ack->msg->line.req.uri == NULL) return -108; /* Check that mandatory headers are again present. */ if (HFIND(ack->msg, from, FROM) == 0) return -110; if (HFIND(ack->msg, to, TO) == 0) return -111; if (HFIND(ack->msg, cid, CALL_ID) == 0) return -112; if (HFIND(ack->msg, cseq, CSEQ) == 0) return -113; if (HFIND(ack->msg, via, VIA) == 0) return -114; if (ack->msg->body != NULL) return -115; /* Done checking invite message. */ if (pjsip_tx_data_dec_ref(invite) != PJSIP_EBUFDESTROYED) { PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); return -120; } /* Done checking response message. */ if (pjsip_tx_data_dec_ref(response) != PJSIP_EBUFDESTROYED) { PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); return -130; } /* Done checking ack message. */ if (pjsip_tx_data_dec_ref(ack) != PJSIP_EBUFDESTROYED) { PJ_LOG(3,(THIS_FILE, " error: response buffer not destroyed!")); return -140; } /* Done. */ return 0; }
static int rx_task(void *data) { RAII_VAR(struct rx_task_data *, task_data, data, ao2_cleanup); RAII_VAR(struct ao2_container *, contacts, NULL, ao2_cleanup); int added = 0, updated = 0, deleted = 0; pjsip_contact_hdr *contact_hdr = NULL; struct registrar_contact_details details = { 0, }; pjsip_tx_data *tdata; pjsip_response_addr addr; const char *aor_name = ast_sorcery_object_get_id(task_data->aor); /* Retrieve the current contacts, we'll need to know whether to update or not */ contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor); /* So we don't count static contacts against max_contacts we prune them out from the container */ ao2_callback(contacts, OBJ_NODATA | OBJ_UNLINK | OBJ_MULTIPLE, registrar_prune_static, NULL); if (registrar_validate_contacts(task_data->rdata, contacts, task_data->aor, &added, &updated, &deleted)) { /* The provided Contact headers do not conform to the specification */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 400, NULL, NULL, NULL); ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_invalid_contacts_provided"); ast_log(LOG_WARNING, "Failed to validate contacts in REGISTER request from '%s'\n", ast_sorcery_object_get_id(task_data->endpoint)); return PJ_TRUE; } if ((MAX(added - deleted, 0) + (!task_data->aor->remove_existing ? ao2_container_count(contacts) : 0)) > task_data->aor->max_contacts) { /* Enforce the maximum number of contacts */ pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 403, NULL, NULL, NULL); ast_sip_report_failed_acl(task_data->endpoint, task_data->rdata, "registrar_attempt_exceeds_maximum_configured_contacts"); ast_log(LOG_WARNING, "Registration attempt from endpoint '%s' to AOR '%s' will exceed max contacts of %d\n", ast_sorcery_object_get_id(task_data->endpoint), ast_sorcery_object_get_id(task_data->aor), task_data->aor->max_contacts); return PJ_TRUE; } if (!(details.pool = pjsip_endpt_create_pool(ast_sip_get_pjsip_endpoint(), "Contact Comparison", 256, 256))) { pjsip_endpt_respond_stateless(ast_sip_get_pjsip_endpoint(), task_data->rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } /* Iterate each provided Contact header and add, update, or delete */ while ((contact_hdr = pjsip_msg_find_hdr(task_data->rdata->msg_info.msg, PJSIP_H_CONTACT, contact_hdr ? contact_hdr->next : NULL))) { int expiration; char contact_uri[PJSIP_MAX_URL_SIZE]; RAII_VAR(struct ast_sip_contact *, contact, NULL, ao2_cleanup); if (contact_hdr->star) { /* A star means to unregister everything, so do so for the possible contacts */ ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, (void *)aor_name); break; } if (!PJSIP_URI_SCHEME_IS_SIP(contact_hdr->uri) && !PJSIP_URI_SCHEME_IS_SIPS(contact_hdr->uri)) { /* This registrar only currently supports sip: and sips: URI schemes */ continue; } expiration = registrar_get_expiration(task_data->aor, contact_hdr, task_data->rdata); details.uri = pjsip_uri_get_uri(contact_hdr->uri); pjsip_uri_print(PJSIP_URI_IN_CONTACT_HDR, details.uri, contact_uri, sizeof(contact_uri)); if (!(contact = ao2_callback(contacts, OBJ_UNLINK, registrar_find_contact, &details))) { /* If they are actually trying to delete a contact that does not exist... be forgiving */ if (!expiration) { ast_verb(3, "Attempted to remove non-existent contact '%s' from AOR '%s' by request\n", contact_uri, aor_name); continue; } ast_sip_location_add_contact(task_data->aor, contact_uri, ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1))); ast_verb(3, "Added contact '%s' to AOR '%s' with expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_ADDED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d", contact_uri, aor_name, expiration); } else if (expiration) { RAII_VAR(struct ast_sip_contact *, updated, ast_sorcery_copy(ast_sip_get_sorcery(), contact), ao2_cleanup); updated->expiration_time = ast_tvadd(ast_tvnow(), ast_samp2tv(expiration, 1)); updated->qualify_frequency = task_data->aor->qualify_frequency; updated->authenticate_qualify = task_data->aor->authenticate_qualify; ast_sip_location_update_contact(updated); ast_debug(3, "Refreshed contact '%s' on AOR '%s' with new expiration of %d seconds\n", contact_uri, aor_name, expiration); ast_test_suite_event_notify("AOR_CONTACT_REFRESHED", "Contact: %s\r\n" "AOR: %s\r\n" "Expiration: %d", contact_uri, aor_name, expiration); } else { ast_sip_location_delete_contact(contact); ast_verb(3, "Removed contact '%s' from AOR '%s' due to request\n", contact_uri, aor_name); ast_test_suite_event_notify("AOR_CONTACT_REMOVED", "Contact: %s\r\n" "AOR: %s", contact_uri, aor_name); } } pjsip_endpt_release_pool(ast_sip_get_pjsip_endpoint(), details.pool); /* If the AOR is configured to remove any existing contacts that have not been updated/added as a result of this REGISTER * do so */ if (task_data->aor->remove_existing) { ao2_callback(contacts, OBJ_NODATA | OBJ_MULTIPLE, registrar_delete_contact, NULL); } /* Update the contacts as things will probably have changed */ ao2_cleanup(contacts); contacts = ast_sip_location_retrieve_aor_contacts(task_data->aor); /* Send a response containing all of the contacts (including static) that are present on this AOR */ if (pjsip_endpt_create_response(ast_sip_get_pjsip_endpoint(), task_data->rdata, 200, NULL, &tdata) != PJ_SUCCESS) { return PJ_TRUE; } /* Add the date header to the response, some UAs use this to set their date and time */ registrar_add_date_header(tdata); ao2_callback(contacts, 0, registrar_add_contact, tdata); if (pjsip_get_response_addr(tdata->pool, task_data->rdata, &addr) == PJ_SUCCESS) { pjsip_endpt_send_response(ast_sip_get_pjsip_endpoint(), &addr, tdata, NULL, NULL); } else { pjsip_tx_data_dec_ref(tdata); } return PJ_TRUE; }
/* Callback to be called to handle new incoming requests. */ static pj_bool_t proxy_on_rx_request( pjsip_rx_data *rdata ) { pjsip_transaction *uas_tsx, *uac_tsx; struct uac_data *uac_data; struct uas_data *uas_data; pjsip_tx_data *tdata; pj_status_t status; if (rdata->msg_info.msg->line.req.method.id != PJSIP_CANCEL_METHOD) { /* Verify incoming request */ status = proxy_verify_request(rdata); if (status != PJ_SUCCESS) { app_perror("RX invalid request", status); return PJ_TRUE; } /* * Request looks sane, next clone the request to create transmit data. */ status = pjsip_endpt_create_request_fwd(global.endpt, rdata, NULL, NULL, 0, &tdata); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); return PJ_TRUE; } /* Process routing */ status = proxy_process_routing(tdata); if (status != PJ_SUCCESS) { app_perror("Error processing route", status); return PJ_TRUE; } /* Calculate target */ status = proxy_calculate_target(rdata, tdata); if (status != PJ_SUCCESS) { app_perror("Error calculating target", status); return PJ_TRUE; } /* Everything is set to forward the request. */ /* If this is an ACK request, forward statelessly. * This happens if the proxy records route and this ACK * is sent for 2xx response. An ACK that is sent for non-2xx * final response will be absorbed by transaction layer, and * it will not be received by on_rx_request() callback. */ if (tdata->msg->line.req.method.id == PJSIP_ACK_METHOD) { status = pjsip_endpt_send_request_stateless(global.endpt, tdata, NULL, NULL); if (status != PJ_SUCCESS) { app_perror("Error forwarding request", status); return PJ_TRUE; } return PJ_TRUE; } /* Create UAC transaction for forwarding the request. * Set our module as the transaction user to receive further * events from this transaction. */ status = pjsip_tsx_create_uac(&mod_tu, tdata, &uac_tsx); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); return PJ_TRUE; } /* Create UAS transaction to handle incoming request */ status = pjsip_tsx_create_uas(&mod_tu, rdata, &uas_tsx); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); pjsip_endpt_respond_stateless(global.endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR, NULL, NULL, NULL); pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); return PJ_TRUE; } /* Feed the request to the UAS transaction to drive it's state * out of NULL state. */ pjsip_tsx_recv_msg(uas_tsx, rdata); /* Attach a data to the UAC transaction, to be used to find the * UAS transaction when we receive response in the UAC side. */ uac_data = (struct uac_data*) pj_pool_alloc(uac_tsx->pool, sizeof(struct uac_data)); uac_data->uas_tsx = uas_tsx; uac_tsx->mod_data[mod_tu.id] = (void*)uac_data; /* Attach data to the UAS transaction, to find the UAC transaction * when cancelling INVITE request. */ uas_data = (struct uas_data*) pj_pool_alloc(uas_tsx->pool, sizeof(struct uas_data)); uas_data->uac_tsx = uac_tsx; uas_tsx->mod_data[mod_tu.id] = (void*)uas_data; /* Everything is setup, forward the request */ status = pjsip_tsx_send_msg(uac_tsx, tdata); if (status != PJ_SUCCESS) { pjsip_tx_data *err_res; /* Fail to send request, for some reason */ /* Destroy transmit data */ pjsip_tx_data_dec_ref(tdata); /* I think UAC transaction should have been destroyed when * it fails to send request, so no need to destroy it. pjsip_tsx_terminate(uac_tsx, PJSIP_SC_INTERNAL_SERVER_ERROR); */ /* Send 500/Internal Server Error to UAS transaction */ pjsip_endpt_create_response(global.endpt, rdata, 500, NULL, &err_res); pjsip_tsx_send_msg(uas_tsx, err_res); return PJ_TRUE; } /* Send 100/Trying if this is an INVITE */ if (rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { pjsip_tx_data *res100; pjsip_endpt_create_response(global.endpt, rdata, 100, NULL, &res100); pjsip_tsx_send_msg(uas_tsx, res100); } } else { /* This is CANCEL request */ pjsip_transaction *invite_uas; struct uas_data *uas_data; pj_str_t key; /* Find the UAS INVITE transaction */ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_UAS_ROLE, pjsip_get_invite_method(), rdata); invite_uas = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); if (!invite_uas) { /* Invite transaction not found, respond CANCEL with 481 */ pjsip_endpt_respond_stateless(global.endpt, rdata, 481, NULL, NULL, NULL); return PJ_TRUE; } /* Respond 200 OK to CANCEL */ pjsip_endpt_respond(global.endpt, NULL, rdata, 200, NULL, NULL, NULL, NULL); /* Send CANCEL to cancel the UAC transaction. * The UAS INVITE transaction will get final response when * we receive final response from the UAC INVITE transaction. */ uas_data = (struct uas_data*) invite_uas->mod_data[mod_tu.id]; if (uas_data->uac_tsx && uas_data->uac_tsx->status_code < 200) { pjsip_tx_data *cancel; pj_mutex_lock(uas_data->uac_tsx->mutex); pjsip_endpt_create_cancel(global.endpt, uas_data->uac_tsx->last_tx, &cancel); pjsip_endpt_send_request(global.endpt, cancel, -1, NULL, NULL); pj_mutex_unlock(uas_data->uac_tsx->mutex); } /* Unlock UAS tsx because it is locked in find_tsx() */ pj_mutex_unlock(invite_uas->mutex); } return PJ_TRUE; }
/* * This is the handler to receive message for this test. It is used to * control and verify the behavior of the message transmitted by the * transaction. */ static pj_bool_t msg_receiver_on_rx_request(pjsip_rx_data *rdata) { if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST1_BRANCH_ID) == 0) { /* * The TEST1_BRANCH_ID test performs the verifications for transaction * retransmission mechanism. It will not answer the incoming request * with any response. */ pjsip_msg *msg = rdata->msg_info.msg; PJ_LOG(4,(THIS_FILE, " received request")); /* Only wants to take INVITE or OPTIONS method. */ if (msg->line.req.method.id != PJSIP_INVITE_METHOD && msg->line.req.method.id != PJSIP_OPTIONS_METHOD) { PJ_LOG(3,(THIS_FILE, " error: received unexpected method %.*s", msg->line.req.method.name.slen, msg->line.req.method.name.ptr)); test_complete = -600; return PJ_TRUE; } if (recv_count == 0) { recv_count++; //pj_gettimeofday(&recv_last); recv_last = rdata->pkt_info.timestamp; } else { pj_time_val now; unsigned msec_expected, msec_elapsed; int max_received; //pj_gettimeofday(&now); now = rdata->pkt_info.timestamp; PJ_TIME_VAL_SUB(now, recv_last); msec_elapsed = now.sec*1000 + now.msec; ++recv_count; msec_expected = (1<<(recv_count-2))*PJSIP_T1_TIMEOUT; if (msg->line.req.method.id != PJSIP_INVITE_METHOD) { if (msec_expected > PJSIP_T2_TIMEOUT) msec_expected = PJSIP_T2_TIMEOUT; max_received = 11; } else { max_received = 7; } if (DIFF(msec_expected, msec_elapsed) > TEST1_ALLOWED_DIFF) { PJ_LOG(3,(THIS_FILE, " error: expecting retransmission no. %d in %d " "ms, received in %d ms", recv_count-1, msec_expected, msec_elapsed)); test_complete = -610; } if (recv_count > max_received) { PJ_LOG(3,(THIS_FILE, " error: too many messages (%d) received", recv_count)); test_complete = -620; } //pj_gettimeofday(&recv_last); recv_last = rdata->pkt_info.timestamp; } return PJ_TRUE; } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST4_BRANCH_ID) == 0) { /* * The TEST4_BRANCH_ID test simulates transport failure after several * retransmissions. */ recv_count++; if (recv_count == TEST4_RETRANSMIT_CNT) { /* Simulate transport failure. */ pjsip_loop_set_failure(loop, 2, NULL); } else if (recv_count > TEST4_RETRANSMIT_CNT) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -631; } return PJ_TRUE; } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST5_BRANCH_ID) == 0) { /* * The TEST5_BRANCH_ID test simulates user terminating the transaction * after several retransmissions. */ recv_count++; if (recv_count == TEST5_RETRANSMIT_CNT+1) { pj_str_t key; pjsip_transaction *tsx; pjsip_tsx_create_key( rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, &rdata->msg_info.msg->line.req.method, rdata); tsx = pjsip_tsx_layer_find_tsx(&key, PJ_TRUE); if (tsx) { pjsip_tsx_terminate(tsx, PJSIP_SC_REQUEST_TERMINATED); pj_mutex_unlock(tsx->mutex); } else { PJ_LOG(3,(THIS_FILE, " error: uac transaction not found!")); test_complete = -633; } } else if (recv_count > TEST5_RETRANSMIT_CNT+1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -634; } return PJ_TRUE; } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST6_BRANCH_ID) == 0) { /* * The TEST6_BRANCH_ID test successfull non-INVITE transaction. */ pj_status_t status; recv_count++; if (recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -635; } status = pjsip_endpt_respond_stateless(endpt, rdata, 202, NULL, NULL, NULL); if (status != PJ_SUCCESS) { app_perror(" error: unable to send response", status); test_complete = -636; } return PJ_TRUE; } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST7_BRANCH_ID) == 0) { /* * The TEST7_BRANCH_ID test successfull non-INVITE transaction * with provisional response. */ pj_status_t status; pjsip_response_addr res_addr; struct response *r; pjsip_tx_data *tdata; pj_time_val delay = { 2, 0 }; recv_count++; if (recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -640; return PJ_TRUE; } /* Respond with provisional response */ status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata); pj_assert(status == PJ_SUCCESS); status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); pj_assert(status == PJ_SUCCESS); status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL); pj_assert(status == PJ_SUCCESS); /* Create the final response. */ status = pjsip_endpt_create_response(endpt, rdata, 202, NULL, &tdata); pj_assert(status == PJ_SUCCESS); /* Schedule sending final response in couple of of secs. */ r = pj_pool_alloc(tdata->pool, sizeof(*r)); r->res_addr = res_addr; r->tdata = tdata; if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); timer.entry.cb = &send_response_callback; timer.entry.user_data = r; pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); return PJ_TRUE; } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST8_BRANCH_ID) == 0) { /* * The TEST8_BRANCH_ID test failed INVITE transaction. */ pjsip_method *method; pj_status_t status; method = &rdata->msg_info.msg->line.req.method; recv_count++; if (method->id == PJSIP_INVITE_METHOD) { if (recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -635; } status = pjsip_endpt_respond_stateless(endpt, rdata, 301, NULL, NULL, NULL); if (status != PJ_SUCCESS) { app_perror(" error: unable to send response", status); test_complete = -636; } } else if (method->id == PJSIP_ACK_METHOD) { if (recv_count == 2) { pj_str_t key; pj_time_val delay = { 5, 0 }; /* Schedule timer to destroy transaction after 5 seconds. * This is to make sure that transaction does not * retransmit ACK. */ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); pj_strcpy(&timer.tsx_key, &key); timer.entry.id = 301; timer.entry.cb = &terminate_tsx_callback; pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -638; } } else { PJ_LOG(3,(THIS_FILE," error: not expecting %s", pjsip_rx_data_get_info(rdata))); test_complete = -639; } } else if (pj_strcmp2(&rdata->msg_info.via->branch_param, TEST9_BRANCH_ID) == 0) { /* * The TEST9_BRANCH_ID test failed INVITE transaction with * provisional response. */ pjsip_method *method; pj_status_t status; method = &rdata->msg_info.msg->line.req.method; recv_count++; if (method->id == PJSIP_INVITE_METHOD) { pjsip_response_addr res_addr; struct response *r; pjsip_tx_data *tdata; pj_time_val delay = { 2, 0 }; if (recv_count > 1) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -650; return PJ_TRUE; } /* Respond with provisional response */ status = pjsip_endpt_create_response(endpt, rdata, 100, NULL, &tdata); pj_assert(status == PJ_SUCCESS); status = pjsip_get_response_addr(tdata->pool, rdata, &res_addr); pj_assert(status == PJ_SUCCESS); status = pjsip_endpt_send_response(endpt, &res_addr, tdata, NULL, NULL); pj_assert(status == PJ_SUCCESS); /* Create the final response. */ status = pjsip_endpt_create_response(endpt, rdata, 302, NULL, &tdata); pj_assert(status == PJ_SUCCESS); /* Schedule sending final response in couple of of secs. */ r = pj_pool_alloc(tdata->pool, sizeof(*r)); r->res_addr = res_addr; r->tdata = tdata; if (r->res_addr.transport) pjsip_transport_add_ref(r->res_addr.transport); timer.entry.cb = &send_response_callback; timer.entry.user_data = r; pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } else if (method->id == PJSIP_ACK_METHOD) { if (recv_count == 2) { pj_str_t key; pj_time_val delay = { 5, 0 }; /* Schedule timer to destroy transaction after 5 seconds. * This is to make sure that transaction does not * retransmit ACK. */ pjsip_tsx_create_key(rdata->tp_info.pool, &key, PJSIP_ROLE_UAC, &pjsip_invite_method, rdata); pj_strcpy(&timer.tsx_key, &key); timer.entry.id = 302; timer.entry.cb = &terminate_tsx_callback; pjsip_endpt_schedule_timer(endpt, &timer.entry, &delay); } if (recv_count > 2) { PJ_LOG(3,(THIS_FILE," error: not expecting %d-th packet!", recv_count)); test_complete = -638; } } else { PJ_LOG(3,(THIS_FILE," error: not expecting %s", pjsip_rx_data_get_info(rdata))); test_complete = -639; } return PJ_TRUE; } return PJ_FALSE; }
/* * This callback called when we receive incoming NOTIFY request. */ static void on_notify_request(pjsip_transaction *tsx, pjsip_rx_data *rdata) { pjsip_event_sub *sub; pjsip_tx_data *tdata; int status = 200; int old_state; pj_str_t reason = { NULL, 0 }; pj_str_t reason_phrase = { NULL, 0 }; int new_state = PJSIP_EVENT_SUB_STATE_NULL; /* Find subscription based on Call-ID and From tag. * This will also automatically lock the subscription, if it's found. */ sub = find_sub(rdata); if (!sub) { /* RFC 3265: Section 3.2 Description of NOTIFY Behavior: * Answer with 481 Subscription does not exist. */ PJ_LOG(4,(THIS_FILE, "Unable to find subscription for incoming NOTIFY!")); status = 481; reason_phrase = pj_str("Subscription does not exist"); } else { pj_assert(sub->role == PJSIP_ROLE_UAC); PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received NOTIFY", sub, state[sub->state].ptr)); } new_state = old_state = sub->state; /* RFC 3265: Section 3.2.1 * Check that the Event header match the subscription. */ if (status == 200) { pjsip_event_hdr *hdr; pj_str_t hname = { "Event", 5 }; hdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); if (!hdr) { status = PJSIP_SC_BAD_REQUEST; reason_phrase = pj_str("No Event header found"); } else if (pj_stricmp(&hdr->event_type, &sub->event->event_type) != 0 || pj_stricmp(&hdr->id_param, &sub->event->id_param) != 0) { status = 481; reason_phrase = pj_str("Subscription does not exist"); } } /* Update subscription state and timer. */ if (status == 200) { pjsip_sub_state_hdr *hdr; const pj_str_t hname = { "Subscription-State", 18 }; const pj_str_t state_active = { "active", 6 }, state_pending = { "pending", 7}, state_terminated = { "terminated", 10 }; hdr = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); if (!hdr) { status = PJSIP_SC_BAD_REQUEST; reason_phrase = pj_str("No Subscription-State header found"); goto process; } /* * Update subscription state. */ if (pj_stricmp(&hdr->sub_state, &state_active) == 0) { if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) new_state = PJSIP_EVENT_SUB_STATE_ACTIVE; } else if (pj_stricmp(&hdr->sub_state, &state_pending) == 0) { if (sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) new_state = PJSIP_EVENT_SUB_STATE_PENDING; } else if (pj_stricmp(&hdr->sub_state, &state_terminated) == 0) { new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; } else { new_state = PJSIP_EVENT_SUB_STATE_UNKNOWN; } reason = hdr->reason_param; if (new_state != sub->state && new_state != PJSIP_EVENT_SUB_STATE_NULL && sub->state != PJSIP_EVENT_SUB_STATE_TERMINATED) { sub_set_state(sub, new_state); if (new_state == PJSIP_EVENT_SUB_STATE_UNKNOWN) { pj_strdup_with_null(sub->pool, &sub->state_str, &hdr->sub_state); } else { sub->state_str = state[new_state]; } } /* * Update timeout timer in required, just in case notifier changed the * expiration to shorter time. * Section 3.2.2: the expires param can only shorten the interval. */ if ((sub->state==PJSIP_EVENT_SUB_STATE_ACTIVE || sub->state==PJSIP_EVENT_SUB_STATE_PENDING) && hdr->expires_param > 0) { pj_time_val now, new_expiry; pj_gettimeofday(&now); new_expiry.sec = now.sec + hdr->expires_param; if (sub->timer.id==0 || new_expiry.sec < sub->expiry_time.sec-SECONDS_BEFORE_EXPIRY/2) { update_next_refresh(sub, hdr->expires_param); } } } process: /* Note: here we sub MAY BE NULL! */ /* Send response to NOTIFY */ tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status ); if (tdata) { if (reason_phrase.slen) tdata->msg->line.status.reason = reason_phrase; if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { pjsip_hdr *hdr; hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); pjsip_msg_add_hdr( tdata->msg, hdr); } pjsip_tsx_on_tx_msg(tsx, tdata); } /* Call NOTIFY callback, if any. */ if (sub && PJSIP_IS_STATUS_IN_CLASS(status,200) && sub->cb.on_received_notify) { sub->pending_tsx++; (*sub->cb.on_received_notify)(sub, rdata); sub->pending_tsx--; } /* Check if subscription is terminated and call callback. */ if (sub && new_state!=old_state && new_state==PJSIP_EVENT_SUB_STATE_TERMINATED) { if (sub->cb.on_sub_terminated) { sub->pending_tsx++; (*sub->cb.on_sub_terminated)(sub, &reason); sub->pending_tsx--; } } /* Check if application has requested deletion. */ if (sub && sub->delete_flag && sub->pending_tsx <= 0) { pjsip_event_sub_destroy(sub); } else if (sub) { pj_mutex_unlock(sub->mutex); } }
/* * Handler when a transaction within a call has changed state. */ static void on_call_tsx_state(pjsua_call_id call_id, pjsip_transaction *tsx, pjsip_event *e) { const pjsip_method info_method = { PJSIP_OTHER_METHOD, { "INFO", 4 } }; if (pjsip_method_cmp(&tsx->method, &info_method)==0) { /* * Handle INFO method. */ if (tsx->role == PJSIP_ROLE_UAC && (tsx->state == PJSIP_TSX_STATE_COMPLETED || (tsx->state == PJSIP_TSX_STATE_TERMINATED && e->body.tsx_state.prev_state != PJSIP_TSX_STATE_COMPLETED))) { /* Status of outgoing INFO request */ if (tsx->status_code >= 200 && tsx->status_code < 300) { PJ_LOG(4,(THIS_FILE, "Call %d: DTMF sent successfully with INFO", call_id)); } else if (tsx->status_code >= 300) { PJ_LOG(4,(THIS_FILE, "Call %d: Failed to send DTMF with INFO: %d/%.*s", call_id, tsx->status_code, (int)tsx->status_text.slen, tsx->status_text.ptr)); } } else if (tsx->role == PJSIP_ROLE_UAS && tsx->state == PJSIP_TSX_STATE_TRYING) { /* Answer incoming INFO with 200/OK */ pjsip_rx_data *rdata; pjsip_tx_data *tdata; pj_status_t status; rdata = e->body.tsx_state.src.rdata; if (rdata->msg_info.msg->body) { status = pjsip_endpt_create_response(tsx->endpt, rdata, 200, NULL, &tdata); if (status == PJ_SUCCESS) status = pjsip_tsx_send_msg(tsx, tdata); PJ_LOG(3,(THIS_FILE, "Call %d: incoming INFO:\n%.*s", call_id, (int)rdata->msg_info.msg->body->len, rdata->msg_info.msg->body->data)); } else { status = pjsip_endpt_create_response(tsx->endpt, rdata, 400, NULL, &tdata); if (status == PJ_SUCCESS) status = pjsip_tsx_send_msg(tsx, tdata); } } } }
/* This function is called when we receive SUBSCRIBE request message * to refresh existing subscription. */ static void on_received_sub_refresh( pjsip_event_sub *sub, pjsip_transaction *tsx, pjsip_rx_data *rdata) { pjsip_event_hdr *e; pjsip_expires_hdr *expires; pj_str_t hname; int status = 200; pj_str_t reason_phrase = { NULL, 0 }; int new_state = sub->state; int old_state = sub->state; int new_interval = 0; pjsip_tx_data *tdata; PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): received target refresh", sub, state[sub->state].ptr)); /* Check that the event matches. */ hname = pj_str("Event"); e = pjsip_msg_find_hdr_by_name( rdata->msg, &hname, NULL); if (!e) { status = 400; reason_phrase = pj_str("Missing Event header"); goto send_response; } if (pj_stricmp(&e->event_type, &sub->event->event_type) != 0 || pj_stricmp(&e->id_param, &sub->event->id_param) != 0) { status = 481; reason_phrase = pj_str("Subscription does not exist"); goto send_response; } /* Check server state. */ if (sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED) { status = 481; reason_phrase = pj_str("Subscription does not exist"); goto send_response; } /* Check expires header. */ expires = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_EXPIRES, NULL); if (!expires) { /* status = 400; reason_phrase = pj_str("Missing Expires header"); goto send_response; */ new_interval = sub->default_interval; } else { /* Check that interval is not too short. * Note that expires time may be zero (for unsubscription). */ new_interval = expires->ivalue; if (new_interval != 0 && new_interval < SECONDS_BEFORE_EXPIRY) { status = PJSIP_SC_INTERVAL_TOO_BRIEF; goto send_response; } } /* Update interval. */ sub->default_interval = new_interval; pj_gettimeofday(&sub->expiry_time); sub->expiry_time.sec += new_interval; /* Update timer only if this is not unsubscription. */ if (new_interval > 0) { sub->default_interval = new_interval; sub_schedule_uas_expire( sub, new_interval ); /* Call callback. */ if (sub->cb.on_received_refresh) { sub->pending_tsx++; (*sub->cb.on_received_refresh)(sub, rdata); sub->pending_tsx--; } } send_response: tdata = pjsip_endpt_create_response( sub->endpt, rdata, status); if (tdata) { if (reason_phrase.slen) tdata->msg->line.status.reason = reason_phrase; /* Add Expires header. */ expires = pjsip_expires_hdr_create(tdata->pool); expires->ivalue = sub->default_interval; pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)expires); if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { pjsip_msg_add_hdr(tdata->msg, pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events)); } /* Send down to transaction. */ pjsip_tsx_on_tx_msg(tsx, tdata); } if (sub->default_interval==0 || !PJSIP_IS_STATUS_IN_CLASS(status,200)) { /* Notify application if sub is terminated. */ new_state = PJSIP_EVENT_SUB_STATE_TERMINATED; sub_set_state(sub, new_state); if (new_state!=old_state && sub->cb.on_sub_terminated) { pj_str_t reason = {"", 0}; if (reason_phrase.slen) reason = reason_phrase; else reason = *pjsip_get_status_text(status); sub->pending_tsx++; (*sub->cb.on_sub_terminated)(sub, &reason); sub->pending_tsx--; } } pj_mutex_unlock(sub->mutex); /* Prefer to call log when we're not holding the mutex. */ PJ_LOG(4,(THIS_FILE, "event_sub%p (%s): sent refresh response %s, status=%d", sub, state[sub->state].ptr, (tdata ? tdata->obj_name : "null"), status)); /* Check if application has requested deletion. */ if (sub->delete_flag && sub->pending_tsx <= 0) { pjsip_event_sub_destroy(sub); } }
/* * Verify that incoming request with Replaces header can be processed. */ PJ_DEF(pj_status_t) pjsip_replaces_verify_request( pjsip_rx_data *rdata, pjsip_dialog **p_dlg, pj_bool_t lock_dlg, pjsip_tx_data **p_tdata) { const pj_str_t STR_REPLACES = { "Replaces", 8 }; pjsip_replaces_hdr *rep_hdr; int code = 200; const char *warn_text = NULL; pjsip_hdr res_hdr_list; pjsip_dialog *dlg = NULL; pjsip_inv_session *inv; pj_status_t status = PJ_SUCCESS; PJ_ASSERT_RETURN(rdata && p_dlg, PJ_EINVAL); /* Check that pjsip_replaces_init_module() has been called. */ PJ_ASSERT_RETURN(the_endpt != NULL, PJ_EINVALIDOP); /* Init output arguments */ *p_dlg = NULL; if (p_tdata) *p_tdata = NULL; pj_list_init(&res_hdr_list); /* Find Replaces header */ rep_hdr = (pjsip_replaces_hdr*) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES, NULL); if (!rep_hdr) { /* No Replaces header. No further processing is necessary. */ return PJ_SUCCESS; } /* Check that there's no other Replaces header and return 400 Bad Request * if not. */ if (pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &STR_REPLACES, rep_hdr->next)) { code = PJSIP_SC_BAD_REQUEST; warn_text = "Found multiple Replaces headers"; goto on_return; } /* Find the dialog identified by Replaces header (and always lock the * dialog no matter what application wants). */ dlg = pjsip_ua_find_dialog(&rep_hdr->call_id, &rep_hdr->to_tag, &rep_hdr->from_tag, PJ_TRUE); /* Respond with 481 "Call/Transaction Does Not Exist" response if * no dialog is found. */ if (dlg == NULL) { code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST; warn_text = "No dialog found for Replaces request"; goto on_return; } /* Get the invite session within the dialog */ inv = pjsip_dlg_get_inv_session(dlg); /* Return 481 if no invite session is present. */ if (inv == NULL) { code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST; warn_text = "No INVITE session found for Replaces request"; goto on_return; } /* Return 603 Declined response if invite session has already * terminated */ if (inv->state >= PJSIP_INV_STATE_DISCONNECTED) { code = PJSIP_SC_DECLINE; warn_text = "INVITE session already terminated"; goto on_return; } /* If "early-only" flag is present, check that the invite session * has not been confirmed yet. If the session has been confirmed, * return 486 "Busy Here" response. */ if (rep_hdr->early_only && inv->state >= PJSIP_INV_STATE_CONNECTING) { code = PJSIP_SC_BUSY_HERE; warn_text = "INVITE session already established"; goto on_return; } /* If the Replaces header field matches an early dialog that was not * initiated by this UA, it returns a 481 (Call/Transaction Does Not * Exist) response to the new INVITE. */ if (inv->state <= PJSIP_INV_STATE_EARLY && inv->role != PJSIP_ROLE_UAC) { code = PJSIP_SC_CALL_TSX_DOES_NOT_EXIST; warn_text = "Found early INVITE session but not initiated by this UA"; goto on_return; } /* * Looks like everything is okay!! */ *p_dlg = dlg; status = PJ_SUCCESS; code = 200; on_return: /* Create response if necessary */ if (code != 200) { /* If we have dialog we must unlock it */ if (dlg) pjsip_dlg_dec_lock(dlg); /* Create response */ if (p_tdata) { pjsip_tx_data *tdata; const pjsip_hdr *h; status = pjsip_endpt_create_response(the_endpt, rdata, code, NULL, &tdata); if (status != PJ_SUCCESS) return status; /* Add response headers. */ h = res_hdr_list.next; while (h != &res_hdr_list) { pjsip_hdr *cloned; cloned = (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, h); PJ_ASSERT_RETURN(cloned, PJ_ENOMEM); pjsip_msg_add_hdr(tdata->msg, cloned); h = h->next; } /* Add warn text, if any */ if (warn_text) { pjsip_warning_hdr *warn_hdr; pj_str_t warn_value = pj_str((char*)warn_text); warn_hdr=pjsip_warning_hdr_create(tdata->pool, 399, pjsip_endpt_name(the_endpt), &warn_value); pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*)warn_hdr); } *p_tdata = tdata; } /* Can not return PJ_SUCCESS when response message is produced. * Ref: PROTOS test ~#2490 */ if (status == PJ_SUCCESS) status = PJSIP_ERRNO_FROM_SIP_STATUS(code); } else { /* If application doesn't want to lock the dialog, unlock it */ if (!lock_dlg) pjsip_dlg_dec_lock(dlg); } return status; }
/* * Send response statefully. */ PJ_DEF(pj_status_t) pjsip_endpt_respond( pjsip_endpoint *endpt, pjsip_module *tsx_user, pjsip_rx_data *rdata, int st_code, const pj_str_t *st_text, const pjsip_hdr *hdr_list, const pjsip_msg_body *body, pjsip_transaction **p_tsx ) { pj_status_t status; pjsip_tx_data *tdata; pjsip_transaction *tsx; /* Validate arguments. */ PJ_ASSERT_RETURN(endpt && rdata, PJ_EINVAL); if (p_tsx) *p_tsx = NULL; /* Create response message */ status = pjsip_endpt_create_response( endpt, rdata, st_code, st_text, &tdata); if (status != PJ_SUCCESS) return status; /* Add the message headers, if any */ if (hdr_list) { const pjsip_hdr *hdr = hdr_list->next; while (hdr != hdr_list) { pjsip_msg_add_hdr(tdata->msg, (pjsip_hdr*) pjsip_hdr_clone(tdata->pool, hdr) ); hdr = hdr->next; } } /* Add the message body, if any. */ if (body) { tdata->msg->body = pjsip_msg_body_clone( tdata->pool, body ); if (tdata->msg->body == NULL) { pjsip_tx_data_dec_ref(tdata); return status; } } /* Create UAS transaction. */ status = pjsip_tsx_create_uas(tsx_user, rdata, &tsx); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); return status; } /* Feed the request to the transaction. */ pjsip_tsx_recv_msg(tsx, rdata); /* Send the message. */ status = pjsip_tsx_send_msg(tsx, tdata); if (status != PJ_SUCCESS) { pjsip_tx_data_dec_ref(tdata); } else if (p_tsx) { *p_tsx = tsx; } return status; }
/* This function is called when we receive SUBSCRIBE request message for * a new subscription. */ static void on_new_subscription( pjsip_transaction *tsx, pjsip_rx_data *rdata ) { package *pkg; pj_pool_t *pool; pjsip_event_sub *sub = NULL; pj_str_t hname; int status = 200; pj_str_t reason = { NULL, 0 }; pjsip_tx_data *tdata; pjsip_expires_hdr *expires; pjsip_accept_hdr *accept; pjsip_event_hdr *evhdr; /* Get the Event header. */ hname = pj_str("Event"); evhdr = pjsip_msg_find_hdr_by_name(rdata->msg, &hname, NULL); if (!evhdr) { status = 400; reason = pj_str("No Event header in request"); goto send_response; } /* Find corresponding package. * We don't lock the manager's mutex since we assume the package list * won't change once the application is running! */ pkg = mgr.pkg_list.next; while (pkg != &mgr.pkg_list) { if (pj_stricmp(&pkg->event, &evhdr->event_type) == 0) break; pkg = pkg->next; } if (pkg == &mgr.pkg_list) { /* Event type is not supported by any packages! */ status = 489; reason = pj_str("Bad Event"); goto send_response; } /* First check that the Accept specification matches the * package's Accept types. */ accept = pjsip_msg_find_hdr(rdata->msg, PJSIP_H_ACCEPT, NULL); if (accept) { unsigned i; pj_str_t *content_type = NULL; for (i=0; i<accept->count && !content_type; ++i) { int j; for (j=0; j<pkg->accept_cnt; ++j) { if (pj_stricmp(&accept->values[i], &pkg->accept[j])==0) { content_type = &pkg->accept[j]; break; } } } if (!content_type) { status = PJSIP_SC_NOT_ACCEPTABLE_HERE; goto send_response; } } /* Check whether the package wants to accept the subscription. */ pj_assert(pkg->cb.on_query_subscribe != NULL); (*pkg->cb.on_query_subscribe)(rdata, &status); if (!PJSIP_IS_STATUS_IN_CLASS(status,200)) goto send_response; /* Create new subscription record. */ pool = pjsip_endpt_create_pool(tsx->endpt, "esub", SUB_POOL_SIZE, SUB_POOL_INC); if (!pool) { status = 500; goto send_response; } sub = pj_pool_calloc(pool, 1, sizeof(*sub)); sub->pool = pool; sub->mutex = pj_mutex_create(pool, "esub", PJ_MUTEX_RECURSE); if (!sub->mutex) { status = 500; goto send_response; } PJ_LOG(4,(THIS_FILE, "event_sub%p: notifier is created.", sub)); /* Start locking mutex. */ pj_mutex_lock(sub->mutex); /* Init UAS subscription */ sub->endpt = tsx->endpt; sub->role = PJSIP_ROLE_UAS; sub->state = PJSIP_EVENT_SUB_STATE_PENDING; sub->state_str = state[sub->state]; pj_list_init(&sub->auth_sess); pj_list_init(&sub->route_set); sub->from = pjsip_hdr_clone(pool, rdata->to); pjsip_fromto_set_from(sub->from); if (sub->from->tag.slen == 0) { pj_create_unique_string(pool, &sub->from->tag); rdata->to->tag = sub->from->tag; } sub->to = pjsip_hdr_clone(pool, rdata->from); pjsip_fromto_set_to(sub->to); sub->contact = pjsip_contact_hdr_create(pool); sub->contact->uri = sub->from->uri; sub->call_id = pjsip_cid_hdr_create(pool); pj_strdup(pool, &sub->call_id->id, &rdata->call_id); sub->cseq = pj_rand() % 0xFFFF; expires = pjsip_msg_find_hdr( rdata->msg, PJSIP_H_EXPIRES, NULL); if (expires) { sub->default_interval = expires->ivalue; if (sub->default_interval > 0 && sub->default_interval < SECONDS_BEFORE_EXPIRY) { status = 423; /* Interval too short. */ goto send_response; } } else { sub->default_interval = 600; } /* Clone Event header. */ sub->event = pjsip_hdr_clone(pool, evhdr); /* Register to hash table. */ create_subscriber_key(&sub->key, pool, PJSIP_ROLE_UAS, &sub->call_id->id, &sub->from->tag); pj_mutex_lock(mgr.mutex); pj_hash_set(pool, mgr.ht, sub->key.ptr, sub->key.slen, sub); pj_mutex_unlock(mgr.mutex); /* Set timer where subscription will expire only when expires<>0. * Subscriber may send new subscription with expires==0. */ if (sub->default_interval != 0) { sub_schedule_uas_expire( sub, sub->default_interval-SECONDS_BEFORE_EXPIRY); } /* Notify application. */ if (pkg->cb.on_subscribe) { pjsip_event_sub_cb *cb = NULL; sub->pending_tsx++; (*pkg->cb.on_subscribe)(sub, rdata, &cb, &sub->default_interval); sub->pending_tsx--; if (cb == NULL) pj_memset(&sub->cb, 0, sizeof(*cb)); else pj_memcpy(&sub->cb, cb, sizeof(*cb)); } send_response: PJ_LOG(4,(THIS_FILE, "event_sub%p (%s)(UAS): status=%d", sub, state[sub->state].ptr, status)); tdata = pjsip_endpt_create_response( tsx->endpt, rdata, status); if (tdata) { if (reason.slen) { /* Customize reason text. */ tdata->msg->line.status.reason = reason; } if (PJSIP_IS_STATUS_IN_CLASS(status,200)) { /* Add Expires header. */ pjsip_expires_hdr *hdr; hdr = pjsip_expires_hdr_create(tdata->pool); hdr->ivalue = sub->default_interval; pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr ); } if (status == 423) { /* Add Min-Expires header. */ pjsip_min_expires_hdr *hdr; hdr = pjsip_min_expires_hdr_create(tdata->pool); hdr->ivalue = SECONDS_BEFORE_EXPIRY; pjsip_msg_add_hdr( tdata->msg, (pjsip_hdr*)hdr); } if (status == 489 || status==PJSIP_SC_NOT_ACCEPTABLE_HERE || PJSIP_IS_STATUS_IN_CLASS(status,200)) { /* Add Allow-Events header. */ pjsip_hdr *hdr; hdr = pjsip_hdr_shallow_clone(tdata->pool, mgr.allow_events); pjsip_msg_add_hdr(tdata->msg, hdr); /* Should add Accept header?. */ } pjsip_tsx_on_tx_msg(tsx, tdata); } /* If received new subscription with expires=0, terminate. */ if (sub && sub->default_interval == 0) { pj_assert(sub->state == PJSIP_EVENT_SUB_STATE_TERMINATED); if (sub->cb.on_sub_terminated) { pj_str_t reason = { "timeout", 7 }; (*sub->cb.on_sub_terminated)(sub, &reason); } } if (!PJSIP_IS_STATUS_IN_CLASS(status,200) || (sub && sub->delete_flag)) { if (sub && sub->mutex) { pjsip_event_sub_destroy(sub); } else if (sub) { pjsip_endpt_destroy_pool(tsx->endpt, sub->pool); } } else { pj_assert(status >= 200); pj_mutex_unlock(sub->mutex); } }
int dummy_function() { pj_caching_pool cp; sprintf(NULL, "%d", 0); rand(); #ifdef HAS_PJLIB pj_init(); pj_caching_pool_init(&cp, NULL, 0); pj_array_erase(NULL, 0, 0, 0); pj_create_unique_string(NULL, NULL); pj_hash_create(NULL, 0); pj_hash_get(NULL, NULL, 0, NULL); pj_hash_set(NULL, NULL, NULL, 0, 0, NULL); pj_ioqueue_create(NULL, 0, NULL); pj_ioqueue_register_sock(NULL, NULL, 0, NULL, NULL, NULL); pj_pool_alloc(NULL, 0); pj_timer_heap_create(NULL, 0, NULL); #endif #ifdef HAS_PJLIB_STUN pjstun_get_mapped_addr(&cp.factory, 0, NULL, NULL, 80, NULL, 80, NULL); #endif #ifdef HAS_PJLIB_GETOPT pj_getopt_long(0, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJLIB_XML pj_xml_parse(NULL, NULL, 100); pj_xml_print(NULL, NULL, 10, PJ_FALSE); pj_xml_clone(NULL, NULL); pj_xml_node_new(NULL, NULL); pj_xml_attr_new(NULL, NULL, NULL); pj_xml_add_node(NULL, NULL); pj_xml_add_attr(NULL, NULL); pj_xml_find_node(NULL, NULL); pj_xml_find_next_node(NULL, NULL, NULL); pj_xml_find_attr(NULL, NULL, NULL); pj_xml_find(NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJLIB_SCANNER pj_cis_buf_init(NULL); pj_cis_init(NULL, NULL); pj_cis_dup(NULL, NULL); pj_cis_add_alpha(NULL); pj_cis_add_str(NULL, NULL); pj_scan_init(NULL, NULL, 0, 0, NULL); pj_scan_fini(NULL); pj_scan_peek(NULL, NULL, NULL); pj_scan_peek_n(NULL, 0, NULL); pj_scan_peek_until(NULL, NULL, NULL); pj_scan_get(NULL, NULL, NULL); pj_scan_get_unescape(NULL, NULL, NULL); pj_scan_get_quote(NULL, 0, 0, NULL); pj_scan_get_n(NULL, 0, NULL); pj_scan_get_char(NULL); pj_scan_get_until(NULL, NULL, NULL); pj_scan_strcmp(NULL, NULL, 0); pj_scan_stricmp(NULL, NULL, 0); pj_scan_stricmp_alnum(NULL, NULL, 0); pj_scan_get_newline(NULL); pj_scan_restore_state(NULL, NULL); #endif #ifdef HAS_PJLIB_DNS pj_dns_make_query(NULL, NULL, 0, 0, NULL); pj_dns_parse_packet(NULL, NULL, 0, NULL); pj_dns_packet_dup(NULL, NULL, 0, NULL); #endif #ifdef HAS_PJLIB_RESOLVER pj_dns_resolver_create(NULL, NULL, 0, NULL, NULL, NULL); pj_dns_resolver_set_ns(NULL, 0, NULL, NULL); pj_dns_resolver_handle_events(NULL, NULL); pj_dns_resolver_destroy(NULL, 0); pj_dns_resolver_start_query(NULL, NULL, 0, 0, NULL, NULL, NULL); pj_dns_resolver_cancel_query(NULL, 0); pj_dns_resolver_add_entry(NULL, NULL, 0); #endif #ifdef HAS_PJLIB_SRV_RESOLVER pj_dns_srv_resolve(NULL, NULL, 0, NULL, NULL, PJ_FALSE, NULL, NULL); #endif #ifdef HAS_PJLIB_CRC32 pj_crc32_init(NULL); pj_crc32_update(NULL, NULL, 0); pj_crc32_final(NULL); #endif #ifdef HAS_PJLIB_HMAC_MD5 pj_hmac_md5(NULL, 0, NULL, 0, NULL); #endif #ifdef HAS_PJLIB_HMAC_SHA1 pj_hmac_sha1(NULL, 0, NULL, 0, NULL); #endif #ifdef HAS_PJNATH_STUN pj_stun_session_create(NULL, NULL, NULL, PJ_FALSE, NULL); pj_stun_session_destroy(NULL); pj_stun_session_set_credential(NULL, NULL); pj_stun_session_create_req(NULL, 0, NULL, NULL); pj_stun_session_create_ind(NULL, 0, NULL); pj_stun_session_create_res(NULL, NULL, 0, NULL, NULL); pj_stun_session_send_msg(NULL, PJ_FALSE, NULL, 0, NULL); #endif #ifdef HAS_PJNATH_ICE pj_ice_strans_create(NULL, NULL, 0, NULL, NULL, NULL); pj_ice_strans_set_stun_domain(NULL, NULL, NULL); pj_ice_strans_create_comp(NULL, 0, 0, NULL); pj_ice_strans_add_cand(NULL, 0, PJ_ICE_CAND_TYPE_HOST, 0, NULL, PJ_FALSE); pj_ice_strans_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); pj_ice_strans_start_ice(NULL, NULL, NULL, 0, NULL); pj_ice_strans_stop_ice(NULL); pj_ice_strans_sendto(NULL, 0, NULL, 0, NULL, 0); #endif #ifdef HAS_PJSIP_CORE_MSG_ELEM /* Parameter container */ pjsip_param_find(NULL, NULL); pjsip_param_print_on(NULL, NULL, 0, NULL, NULL, 0); /* SIP URI */ pjsip_sip_uri_create(NULL, 0); pjsip_name_addr_create(NULL); /* TEL URI */ pjsip_tel_uri_create(NULL); /* Message and headers */ pjsip_msg_create(NULL, PJSIP_REQUEST_MSG); pjsip_msg_print(NULL, NULL, 0); pjsip_accept_hdr_create(NULL); pjsip_allow_hdr_create(NULL); pjsip_cid_hdr_create(NULL); pjsip_clen_hdr_create(NULL); pjsip_cseq_hdr_create(NULL); pjsip_contact_hdr_create(NULL); pjsip_ctype_hdr_create(NULL); pjsip_expires_hdr_create(NULL, 0); pjsip_from_hdr_create(NULL); pjsip_max_fwd_hdr_create(NULL, 0); pjsip_min_expires_hdr_create(NULL, 0); pjsip_rr_hdr_create(NULL); pjsip_require_hdr_create(NULL); pjsip_retry_after_hdr_create(NULL, 0); pjsip_supported_hdr_create(NULL); pjsip_unsupported_hdr_create(NULL); pjsip_via_hdr_create(NULL); pjsip_warning_hdr_create(NULL, 0, NULL, NULL); pjsip_parse_uri(NULL, NULL, 0, 0); pjsip_parse_msg(NULL, NULL, 0, NULL); pjsip_parse_rdata(NULL, 0, NULL); pjsip_find_msg(NULL, 0, 0, NULL); #endif #ifdef HAS_PJSIP_CORE pjsip_endpt_create(NULL, NULL, NULL); pjsip_tpmgr_create(NULL, NULL, NULL, NULL, NULL); pjsip_tpmgr_destroy(NULL); pjsip_transport_send(NULL, NULL, NULL, 0, NULL, NULL); #endif #ifdef HAS_PJSIP_CORE_MSG_UTIL pjsip_endpt_create_request(NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_request_from_hdr(NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_response(NULL, NULL, -1, NULL, NULL); pjsip_endpt_create_ack(NULL, NULL, NULL, NULL); pjsip_endpt_create_cancel(NULL, NULL, NULL); pjsip_get_request_dest(NULL, NULL); pjsip_endpt_send_request_stateless(NULL, NULL, NULL, NULL); pjsip_get_response_addr(NULL, NULL, NULL); pjsip_endpt_send_response(NULL, NULL, NULL, NULL, NULL); pjsip_endpt_respond_stateless(NULL, NULL, -1, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_UDP_TRANSPORT pjsip_udp_transport_start(NULL, NULL, NULL, 1, NULL); #endif #ifdef HAS_PJSIP_TCP_TRANSPORT pjsip_tcp_transport_start(NULL, NULL, 1, NULL); #endif #ifdef HAS_PJSIP_TLS_TRANSPORT pjsip_tls_transport_start(NULL, NULL, NULL, NULL, 0, NULL); #endif #ifdef HAS_PJSIP_TRANSACTION pjsip_tsx_layer_init_module(NULL); pjsip_tsx_layer_destroy(); pjsip_tsx_create_uac(NULL, NULL, NULL); pjsip_tsx_create_uas(NULL, NULL, NULL); pjsip_tsx_recv_msg(NULL, NULL); pjsip_tsx_send_msg(NULL, NULL); pjsip_tsx_terminate(NULL, 200); pjsip_endpt_send_request(NULL, NULL, -1, NULL, NULL); pjsip_endpt_respond(NULL, NULL, NULL, -1, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SDP pjmedia_sdp_parse(NULL, NULL, 1024, NULL); pjmedia_sdp_print(NULL, NULL, 1024); pjmedia_sdp_validate(NULL); pjmedia_sdp_session_clone(NULL, NULL); pjmedia_sdp_session_cmp(NULL, NULL, 0); pjmedia_sdp_attr_to_rtpmap(NULL, NULL, NULL); pjmedia_sdp_attr_get_fmtp(NULL, NULL); pjmedia_sdp_attr_get_rtcp(NULL, NULL); pjmedia_sdp_conn_clone(NULL, NULL); pjmedia_sdp_media_clone(NULL, NULL); pjmedia_sdp_media_find_attr(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SDP_NEGOTIATOR pjmedia_sdp_neg_create_w_local_offer(NULL, NULL, NULL); pjmedia_sdp_neg_create_w_remote_offer(NULL, NULL, NULL, NULL); pjmedia_sdp_neg_get_state(NULL); pjmedia_sdp_neg_negotiate(NULL, NULL, PJ_FALSE); #endif #ifdef HAS_PJSIP_UA_LAYER pjsip_ua_init_module(NULL, NULL); pjsip_ua_destroy(); pjsip_dlg_create_uac(NULL, NULL, NULL, NULL, NULL, NULL); pjsip_dlg_create_uas_and_inc_lock(NULL, NULL, NULL, NULL); pjsip_dlg_terminate(NULL); pjsip_dlg_set_route_set(NULL, NULL); pjsip_dlg_create_request(NULL, NULL, -1, NULL); pjsip_dlg_send_request(NULL, NULL, -1, NULL); pjsip_dlg_create_response(NULL, NULL, -1, NULL, NULL); pjsip_dlg_modify_response(NULL, NULL, -1, NULL); pjsip_dlg_send_response(NULL, NULL, NULL); pjsip_dlg_respond(NULL, NULL, -1, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_AUTH_CLIENT pjsip_auth_clt_init(NULL, NULL, NULL, 0); pjsip_auth_clt_clone(NULL, NULL, NULL); pjsip_auth_clt_set_credentials(NULL, 0, NULL); pjsip_auth_clt_init_req(NULL, NULL); pjsip_auth_clt_reinit_req(NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJSIP_INV_SESSION pjsip_inv_usage_init(NULL, NULL); pjsip_inv_create_uac(NULL, NULL, 0, NULL); pjsip_inv_verify_request(NULL, NULL, NULL, NULL, NULL, NULL); pjsip_inv_create_uas(NULL, NULL, NULL, 0, NULL); pjsip_inv_terminate(NULL, 200, PJ_FALSE); pjsip_inv_invite(NULL, NULL); pjsip_inv_initial_answer(NULL, NULL, 200, NULL, NULL, NULL); pjsip_inv_answer(NULL, 200, NULL, NULL, NULL); pjsip_inv_end_session(NULL, 200, NULL, NULL); pjsip_inv_reinvite(NULL, NULL, NULL, NULL); pjsip_inv_update(NULL, NULL, NULL, NULL); pjsip_inv_send_msg(NULL, NULL); pjsip_dlg_get_inv_session(NULL); //pjsip_tsx_get_inv_session(NULL); pjsip_inv_state_name(PJSIP_INV_STATE_NULL); #endif #ifdef HAS_PJSIP_REGC //pjsip_regc_get_module(); pjsip_regc_create(NULL, NULL, NULL, NULL); pjsip_regc_destroy(NULL); pjsip_regc_get_info(NULL, NULL); pjsip_regc_get_pool(NULL); pjsip_regc_init(NULL, NULL, NULL, NULL, 0, NULL, 600); pjsip_regc_set_credentials(NULL, 1, NULL); pjsip_regc_set_route_set(NULL, NULL); pjsip_regc_register(NULL, PJ_TRUE, NULL); pjsip_regc_unregister(NULL, NULL); pjsip_regc_update_contact(NULL, 10, NULL); pjsip_regc_update_expires(NULL, 600); pjsip_regc_send(NULL, NULL); #endif #ifdef HAS_PJSIP_EVENT_FRAMEWORK pjsip_evsub_init_module(NULL); pjsip_evsub_instance(); pjsip_evsub_register_pkg(NULL, NULL, 30, 10, NULL); pjsip_evsub_create_uac(NULL, NULL, NULL, 10, NULL); pjsip_evsub_create_uas(NULL, NULL, NULL, 10, NULL); pjsip_evsub_terminate(NULL, PJ_FALSE); pjsip_evsub_get_state(NULL); pjsip_evsub_get_state_name(NULL); pjsip_evsub_initiate(NULL, NULL, -1, NULL); pjsip_evsub_accept(NULL, NULL, 200, NULL); pjsip_evsub_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL); pjsip_evsub_current_notify(NULL, NULL); pjsip_evsub_send_request(NULL, NULL); pjsip_tsx_get_evsub(NULL); pjsip_evsub_set_mod_data(NULL, 1, NULL); pjsip_evsub_get_mod_data(NULL, 1); #endif #ifdef HAS_PJSIP_CALL_TRANSFER pjsip_xfer_init_module(NULL); pjsip_xfer_create_uac(NULL, NULL, NULL); pjsip_xfer_create_uas(NULL, NULL, NULL, NULL); pjsip_xfer_initiate(NULL, NULL, NULL); pjsip_xfer_accept(NULL, NULL, 200, NULL); pjsip_xfer_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, 200, NULL, NULL); pjsip_xfer_current_notify(NULL, NULL); pjsip_xfer_send_request(NULL, NULL); #endif #ifdef HAS_PJSIP_PRESENCE pjsip_pres_init_module(NULL, NULL); pjsip_pres_instance(); pjsip_pres_create_uac(NULL, NULL, 0, NULL); pjsip_pres_create_uas(NULL, NULL, NULL, NULL); pjsip_pres_terminate(NULL, PJ_FALSE); pjsip_pres_initiate(NULL, 100, NULL); pjsip_pres_accept(NULL, NULL, 200, NULL); pjsip_pres_notify(NULL, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, NULL); pjsip_pres_current_notify(NULL, NULL); pjsip_pres_send_request(NULL, NULL); pjsip_pres_get_status(NULL, NULL); pjsip_pres_set_status(NULL, NULL); #endif #ifdef HAS_PJSIP_IS_COMPOSING pjsip_iscomposing_create_xml(NULL, PJ_TRUE, NULL, NULL, 0); pjsip_iscomposing_create_body(NULL, PJ_TRUE, NULL, NULL, 0); pjsip_iscomposing_parse(NULL, NULL, 0, NULL, NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA pjmedia_endpt_create(NULL, NULL, 1, NULL); pjmedia_endpt_destroy(NULL); pjmedia_endpt_create_sdp(NULL, NULL, 1, NULL, NULL); #endif #ifdef HAS_PJMEDIA_EC pjmedia_echo_create(NULL, 0, 0, 0, 0, 0, NULL); pjmedia_echo_destroy(NULL); pjmedia_echo_playback(NULL, NULL); pjmedia_echo_capture(NULL, NULL, 0); pjmedia_echo_cancel(NULL, NULL, NULL, 0, NULL); #endif #ifdef HAS_PJMEDIA_SND_DEV pjmedia_snd_init(NULL); pjmedia_snd_get_dev_count(); pjmedia_snd_get_dev_info(0); pjmedia_snd_open(-1, -1, 8000, 1, 80, 16, NULL, NULL, NULL, NULL); pjmedia_snd_open_rec(-1, 8000, 1, 160, 16, NULL, NULL, NULL); pjmedia_snd_open_player(-1, 8000, 1, 160, 16, NULL, NULL, NULL); pjmedia_snd_stream_start(NULL); pjmedia_snd_stream_stop(NULL); pjmedia_snd_stream_close(NULL); pjmedia_snd_deinit(); #endif #ifdef HAS_PJMEDIA_SND_PORT pjmedia_snd_port_create(NULL, -1, -1, 8000, 1, 180, 16, 0, NULL); pjmedia_snd_port_create_rec(NULL, -1, 8000, 1, 160, 16, 0, NULL); pjmedia_snd_port_create_player(NULL, -1, 8000, 1, 160, 16, 0, NULL); pjmedia_snd_port_destroy(NULL); pjmedia_snd_port_get_snd_stream(NULL); pjmedia_snd_port_connect(NULL, NULL); pjmedia_snd_port_get_port(NULL); pjmedia_snd_port_disconnect(NULL); #endif #ifdef HAS_PJMEDIA_RESAMPLE pjmedia_resample_create(NULL, PJ_TRUE, PJ_TRUE, 0, 0, 0, 0, NULL); pjmedia_resample_run(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_SILENCE_DET pjmedia_silence_det_create(NULL, 8000, 80, NULL); pjmedia_silence_det_detect(NULL, NULL, 0, NULL); pjmedia_silence_det_apply(NULL, 0); #endif #ifdef HAS_PJMEDIA_PLC pjmedia_plc_create(NULL, 8000, 80, 0, NULL); pjmedia_plc_save(NULL, NULL); pjmedia_plc_generate(NULL, NULL); #endif #ifdef HAS_PJMEDIA_CONFERENCE pjmedia_conf_create(NULL, 10, 8000, 1, 160, 16, 0, NULL); pjmedia_conf_destroy(NULL); pjmedia_conf_get_master_port(NULL); pjmedia_conf_add_port(NULL, NULL, NULL, NULL, NULL); pjmedia_conf_configure_port(NULL, 1, 0, 0); pjmedia_conf_connect_port(NULL, 0, 0, 0); pjmedia_conf_disconnect_port(NULL, 0, 0); pjmedia_conf_remove_port(NULL, 0); pjmedia_conf_enum_ports(NULL, NULL, NULL); pjmedia_conf_get_port_info(NULL, 0, NULL); pjmedia_conf_get_ports_info(NULL, NULL, NULL); pjmedia_conf_get_signal_level(NULL, 0, NULL, NULL); pjmedia_conf_adjust_rx_level(NULL, 0, 0); pjmedia_conf_adjust_tx_level(NULL, 0, 0); #endif #ifdef HAS_PJMEDIA_MASTER_PORT pjmedia_master_port_create(NULL, NULL, NULL, 0, NULL); pjmedia_master_port_start(NULL); pjmedia_master_port_stop(NULL); pjmedia_master_port_set_uport(NULL, NULL); pjmedia_master_port_get_uport(NULL); pjmedia_master_port_set_dport(NULL, NULL); pjmedia_master_port_get_dport(NULL); pjmedia_master_port_destroy(NULL, PJ_FALSE); #endif #ifdef HAS_PJMEDIA_RTP pjmedia_rtp_session_init(NULL, 0, 0); pjmedia_rtp_encode_rtp(NULL, 0, 0, 0, 0, NULL, NULL); pjmedia_rtp_decode_rtp(NULL, NULL, 0, NULL, NULL, NULL); pjmedia_rtp_session_update(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_RTCP pjmedia_rtcp_init(NULL, NULL, 0, 0, 0); pjmedia_rtcp_get_ntp_time(NULL, NULL); pjmedia_rtcp_fini(NULL); pjmedia_rtcp_rx_rtp(NULL, 0, 0, 0); pjmedia_rtcp_tx_rtp(NULL, 0); pjmedia_rtcp_rx_rtcp(NULL, NULL, 0); pjmedia_rtcp_build_rtcp(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_JBUF pjmedia_jbuf_create(NULL, NULL, 0, 0, 0, NULL); pjmedia_jbuf_set_fixed(NULL, 0); pjmedia_jbuf_set_adaptive(NULL, 0, 0, 0); pjmedia_jbuf_destroy(NULL); pjmedia_jbuf_put_frame(NULL, NULL, 0, 0); pjmedia_jbuf_get_frame(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_STREAM pjmedia_stream_create(NULL, NULL, NULL, NULL, NULL, NULL); pjmedia_stream_destroy(NULL); pjmedia_stream_get_port(NULL, NULL); pjmedia_stream_get_transport(NULL); pjmedia_stream_start(NULL); pjmedia_stream_get_stat(NULL, NULL); pjmedia_stream_pause(NULL, PJMEDIA_DIR_ENCODING); pjmedia_stream_resume(NULL, PJMEDIA_DIR_ENCODING); pjmedia_stream_dial_dtmf(NULL, NULL); pjmedia_stream_check_dtmf(NULL); pjmedia_stream_get_dtmf(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_TONEGEN pjmedia_tonegen_create(NULL, 0, 0, 0, 0, 0, NULL); pjmedia_tonegen_is_busy(NULL); pjmedia_tonegen_stop(NULL); pjmedia_tonegen_play(NULL, 0, NULL, 0); pjmedia_tonegen_play_digits(NULL, 0, NULL, 0); pjmedia_tonegen_get_digit_map(NULL, NULL); pjmedia_tonegen_set_digit_map(NULL, NULL); #endif #ifdef HAS_PJMEDIA_UDP_TRANSPORT pjmedia_transport_udp_create(NULL, NULL, 0, 0, NULL); pjmedia_transport_udp_close(NULL); #endif #ifdef HAS_PJMEDIA_FILE_PLAYER pjmedia_wav_player_port_create(NULL, NULL, 0, 0, 0, NULL); pjmedia_wav_player_port_set_pos(NULL, 0); pjmedia_wav_player_port_get_pos(NULL); pjmedia_wav_player_set_eof_cb(NULL, NULL, NULL); #endif #ifdef HAS_PJMEDIA_FILE_CAPTURE pjmedia_wav_writer_port_create(NULL, NULL, 8000, 1, 80, 16, 0, 0, NULL); pjmedia_wav_writer_port_get_pos(NULL); pjmedia_wav_writer_port_set_cb(NULL, 0, NULL, NULL); #endif #ifdef HAS_PJMEDIA_MEM_PLAYER pjmedia_mem_player_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL); #endif #ifdef HAS_PJMEDIA_MEM_CAPTURE pjmedia_mem_capture_create(NULL, NULL, 1000, 8000, 1, 80, 16, 0, NULL); #endif #ifdef HAS_PJMEDIA_ICE pjmedia_ice_create(NULL, NULL, 0, NULL, NULL); pjmedia_ice_destroy(NULL); pjmedia_ice_start_init(NULL, 0, NULL, NULL, NULL); pjmedia_ice_init_ice(NULL, PJ_ICE_SESS_ROLE_CONTROLLED, NULL, NULL); pjmedia_ice_modify_sdp(NULL, NULL, NULL); pjmedia_ice_start_ice(NULL, NULL, NULL, 0); pjmedia_ice_stop_ice(NULL); #endif #ifdef HAS_PJMEDIA_G711_CODEC pjmedia_codec_g711_init(NULL); pjmedia_codec_g711_deinit(); #endif #ifdef HAS_PJMEDIA_GSM_CODEC pjmedia_codec_gsm_init(NULL); pjmedia_codec_gsm_deinit(); #endif #ifdef HAS_PJMEDIA_SPEEX_CODEC pjmedia_codec_speex_init(NULL, 0, 0, 0); pjmedia_codec_speex_deinit(); #endif #ifdef HAS_PJMEDIA_ILBC_CODEC pjmedia_codec_ilbc_init(NULL, 0); pjmedia_codec_ilbc_deinit(); #endif return 0; }