/* * Make outgoing call. */ static pj_status_t make_call(const pj_str_t *dst_uri) { struct call *call; pjsip_dialog *dlg; pjmedia_sdp_session *sdp; pjsip_tx_data *tdata; pj_status_t status; /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &app.local_uri, /* local URI */ &app.local_contact, /* local Contact */ dst_uri, /* remote URI */ dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { return status; } /* Create call */ call = pj_pool_zalloc(dlg->pool, sizeof(struct call)); /* Create SDP */ if (app.real_sdp) { status = pjmedia_endpt_create_sdp(app.med_endpt, dlg->pool, 1, app.skinfo, &sdp); if (status != PJ_SUCCESS) { pjsip_dlg_terminate(dlg); return status; } } else sdp = app.dummy_sdp; /* Create the INVITE session. */ status = pjsip_inv_create_uac( dlg, sdp, 0, &call->inv); if (status != PJ_SUCCESS) { pjsip_dlg_terminate(dlg); return status; } /* Create initial INVITE request. * This INVITE request will contain a perfectly good request and * an SDP body as well. */ status = pjsip_inv_invite(call->inv, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* Send initial INVITE request. * From now on, the invite session's state will be reported to us * via the invite session callbacks. */ status = pjsip_inv_send_msg(call->inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); return PJ_SUCCESS; }
int inv_offer_answer_test(void) { unsigned i; int rc = 0; /* Init UA layer */ if (pjsip_ua_instance()->id == -1) { pjsip_ua_init_param ua_param; pj_bzero(&ua_param, sizeof(ua_param)); ua_param.on_dlg_forked = &on_dlg_forked; pjsip_ua_init_module(endpt, &ua_param); } /* Init inv-usage */ if (pjsip_inv_usage_instance()->id == -1) { pjsip_inv_callback inv_cb; pj_bzero(&inv_cb, sizeof(inv_cb)); inv_cb.on_media_update = &on_media_update; inv_cb.on_rx_offer = &on_rx_offer; inv_cb.on_create_offer = &on_create_offer; inv_cb.on_state_changed = &on_state_changed; inv_cb.on_new_session = &on_new_session; pjsip_inv_usage_init(endpt, &inv_cb); } /* 100rel module */ pjsip_100rel_init_module(endpt); /* Our module */ pjsip_endpt_register_module(endpt, &mod_inv_oa_test); pjsip_endpt_register_module(endpt, &mod_msg_logger); /* Create SIP UDP transport */ { pj_sockaddr_in addr; pjsip_transport *tp; pj_status_t status; pj_sockaddr_in_init(&addr, NULL, PORT); status = pjsip_udp_transport_start(endpt, &addr, NULL, 1, &tp); pj_assert(status == PJ_SUCCESS); } /* Do tests */ for (i=0; i<PJ_ARRAY_SIZE(test_params); ++i) { rc = perform_test(&test_params[i]); if (rc != 0) goto on_return; } on_return: return rc; }
static pj_bool_t on_rx_request(pjsip_rx_data *rdata) { if (rdata->msg_info.msg->type == PJSIP_REQUEST_MSG && rdata->msg_info.msg->line.req.method.id == PJSIP_INVITE_METHOD) { pjsip_dialog *dlg; pjmedia_sdp_session *sdp = NULL; pj_str_t uri; pjsip_tx_data *tdata; pj_status_t status; /* * Create UAS */ uri = pj_str(CONTACT); status = pjsip_dlg_create_uas_and_inc_lock(pjsip_ua_instance(), rdata, &uri, &dlg); pj_assert(status == PJ_SUCCESS); if (inv_test.param.oa[0] == OFFERER_UAC) sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].answer); else if (inv_test.param.oa[0] == OFFERER_UAS) sdp = create_sdp(rdata->tp_info.pool, oa_sdp[0].offer); else pj_assert(!"Invalid offerer type"); status = pjsip_inv_create_uas(dlg, rdata, sdp, inv_test.param.inv_option, &inv_test.uas); pj_assert(status == PJ_SUCCESS); pjsip_dlg_dec_lock(dlg); TRACE_((THIS_FILE, " Sending 183 with SDP")); /* * Answer with 183 */ status = pjsip_inv_initial_answer(inv_test.uas, rdata, 183, NULL, NULL, &tdata); pj_assert(status == PJ_SUCCESS); status = pjsip_inv_send_msg(inv_test.uas, tdata); pj_assert(status == PJ_SUCCESS); return PJ_TRUE; } return PJ_FALSE; }
/* make call */ void make_call(char *uri, pj_bool_t with_offer) { pj_str_t local = pj_str("sip:localhost" PORT_STR); pj_str_t remote = pj_str(uri); pj_status_t status; status = pjsip_dlg_create_uac(pjsip_ua_instance(), &local, &local, &remote, &remote, &dlg); pj_assert(status == PJ_SUCCESS); pjsip_dlg_inc_lock(dlg); status = pjsip_dlg_add_usage(dlg, &mod_app, NULL); pj_assert(status == PJ_SUCCESS); pjsip_dlg_inc_session(dlg, &mod_app); send_request(&pjsip_invite_method, -1, NULL, with_offer); pjsip_dlg_dec_lock(dlg); }
////////////////////////////////////////////////////////////////////////// // Request handler to receive out-of-dialog NOTIFY (from Asterisk) static pj_bool_t on_rx_request(pjsip_rx_data *rdata) { if (strstr(pj_strbuf(&rdata->msg_info.msg->line.req.method.name), "NOTIFY")) { pjsip_generic_string_hdr * hdr; pj_str_t did_str = pj_str("Event"); hdr = (pjsip_generic_string_hdr*) pjsip_msg_find_hdr_by_name(rdata->msg_info.msg, &did_str, NULL); if (!hdr) return false; // We have an event header, now determine if it's contents are "message-summary" if (pj_strcmp2(&hdr->hvalue, "message-summary")) return false; pjsip_msg_body * body_p = rdata->msg_info.msg->body; wchar_t* buf = (wchar_t*)pj_pool_alloc(app_config.pool, body_p->len); buf = PJ_STRING_TO_NATIVE((char*)body_p->data, buf, body_p->len); // Process body message as desired... if (strncmp((char*)body_p->data, "Messages-Waiting: yes", body_p->len) != 0) { if (cb_mwi != 0) cb_mwi(1, buf); } else { if (cb_mwi != 0) cb_mwi(0, buf); } PJ_LOG(3,(THIS_FILE,"MWI message: %s", buf)); } pjsip_endpt_respond_stateless(pjsip_ua_get_endpt(pjsip_ua_instance()), rdata, 200, NULL, NULL, NULL); return PJ_TRUE; }
static int perform_test(inv_test_param_t *param) { pj_str_t uri; pjsip_dialog *dlg; pjmedia_sdp_session *sdp; pjsip_tx_data *tdata; pj_status_t status; PJ_LOG(3,(THIS_FILE, " %s", param->title)); pj_bzero(&inv_test, sizeof(inv_test)); pj_memcpy(&inv_test.param, param, sizeof(*param)); job_cnt = 0; uri = pj_str(CONTACT); /* * Create UAC */ status = pjsip_dlg_create_uac(pjsip_ua_instance(), &uri, &uri, &uri, &uri, &dlg); PJ_ASSERT_RETURN(status==PJ_SUCCESS, -10); if (inv_test.param.oa[0] == OFFERER_UAC) sdp = create_sdp(dlg->pool, oa_sdp[0].offer); else sdp = NULL; status = pjsip_inv_create_uac(dlg, sdp, inv_test.param.inv_option, &inv_test.uac); PJ_ASSERT_RETURN(status==PJ_SUCCESS, -20); TRACE_((THIS_FILE, " Sending INVITE %s offer", (sdp ? "with" : "without"))); /* * Make call! */ status = pjsip_inv_invite(inv_test.uac, &tdata); PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); status = pjsip_inv_send_msg(inv_test.uac, tdata); PJ_ASSERT_RETURN(status==PJ_SUCCESS, -30); /* * Wait until test completes */ while (!inv_test.complete) { pj_time_val delay = {0, 20}; pjsip_endpt_handle_events(endpt, &delay); while (job_cnt) { job_t j; j = jobs[0]; pj_array_erase(jobs, sizeof(jobs[0]), job_cnt, 0); --job_cnt; run_job(&j); } } flush_events(100); /* * Hangup */ TRACE_((THIS_FILE, " Disconnecting call")); status = pjsip_inv_end_session(inv_test.uas, PJSIP_SC_DECLINE, 0, &tdata); pj_assert(status == PJ_SUCCESS); status = pjsip_inv_send_msg(inv_test.uas, tdata); pj_assert(status == PJ_SUCCESS); flush_events(500); return 0; }
/* * Callback when incoming requests outside any transactions and any * dialogs are received. We're only interested to hande incoming INVITE * request, and we'll reject any other requests with 500 response. */ static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) { pj_sockaddr hostaddr; char temp[80], hostip[PJ_INET6_ADDRSTRLEN]; pj_str_t local_uri; pjsip_dialog *dlg; pjmedia_sdp_session *local_sdp; pjsip_tx_data *tdata; unsigned options = 0; pj_status_t status; /* * Respond (statelessly) any non-INVITE requests with 500 */ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) { pj_str_t reason = pj_str("Simple UA unable to handle " "this request"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); } return PJ_TRUE; } /* * Reject INVITE if we already have an INVITE session in progress. */ if (g_inv) { pj_str_t reason = pj_str("Another call is in progress"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* Verify that we can handle the request. */ status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, g_endpt, NULL); if (status != PJ_SUCCESS) { pj_str_t reason = pj_str("Sorry Simple UA can not handle this INVITE"); pjsip_endpt_respond_stateless( g_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* * Generate Contact URI */ if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to retrieve local host IP", status); return PJ_TRUE; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:simpleuas@%s:%d>", hostip, SIP_PORT); local_uri = pj_str(temp); /* * Create UAS dialog. */ status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, &local_uri, /* contact */ &dlg); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless(g_endpt, rdata, 500, NULL, NULL, NULL); return PJ_TRUE; } /* * Get media capability from media endpoint: */ status = pjmedia_endpt_create_sdp( g_med_endpt, rdata->tp_info.pool, MAX_MEDIA_CNT, g_sock_info, &local_sdp); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Create invite session, and pass both the UAS dialog and the SDP * capability to the session. */ status = pjsip_inv_create_uas( dlg, rdata, local_sdp, 0, &g_inv); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Initially send 180 response. * * The very first response to an INVITE must be created with * pjsip_inv_initial_answer(). Subsequent responses to the same * transaction MUST use pjsip_inv_answer(). */ status = pjsip_inv_initial_answer(g_inv, rdata, 180, NULL, NULL, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* Send the 180 response. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Now create 200 response. */ status = pjsip_inv_answer( g_inv, 200, NULL, /* st_code and st_text */ NULL, /* SDP already specified */ &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* * Send the 200 response. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, PJ_TRUE); /* Done. * When the call is disconnected, it will be reported via the callback. */ return PJ_TRUE; }
/* * main() * * If called with argument, treat argument as SIP URL to be called. * Otherwise wait for incoming calls. */ int main(int argc, char *argv[]) { pj_pool_t *pool = NULL; pj_status_t status; unsigned i; /* Must init PJLIB first: */ status = pj_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); pj_log_set_level(5); /* Then init PJLIB-UTIL: */ status = pjlib_util_init(); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Must create a pool factory before we can allocate any memory. */ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0); /* Create global endpoint: */ { const pj_str_t *hostname; const char *endpt_name; /* Endpoint MUST be assigned a globally unique name. * The name will be used as the hostname in Warning header. */ /* For this implementation, we'll use hostname for simplicity */ hostname = pj_gethostname(); endpt_name = hostname->ptr; /* Create the endpoint: */ status = pjsip_endpt_create(&cp.factory, endpt_name, &g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* * Add UDP transport, with hard-coded port * Alternatively, application can use pjsip_udp_transport_attach() to * start UDP transport, if it already has an UDP socket (e.g. after it * resolves the address with STUN). */ { pj_sockaddr addr; pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT); if (AF == pj_AF_INET()) { status = pjsip_udp_transport_start( g_endpt, &addr.ipv4, NULL, 1, NULL); } else if (AF == pj_AF_INET6()) { status = pjsip_udp_transport_start6(g_endpt, &addr.ipv6, NULL, 1, NULL); } else { status = PJ_EAFNOTSUP; } if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to start UDP transport", status); return 1; } } /* * Init transaction layer. * This will create/initialize transaction hash tables etc. */ status = pjsip_tsx_layer_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Initialize UA layer module. * This will create/initialize dialog hash tables etc. */ status = pjsip_ua_init_module( g_endpt, NULL ); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Init invite session module. * The invite session module initialization takes additional argument, * i.e. a structure containing callbacks to be called on specific * occurence of events. * * The on_state_changed and on_new_session callbacks are mandatory. * Application must supply the callback function. * * We use on_media_update() callback in this application to start * media transmission. */ { pjsip_inv_callback inv_cb; /* Init the callback for INVITE session: */ pj_bzero(&inv_cb, sizeof(inv_cb)); inv_cb.on_state_changed = &call_on_state_changed; inv_cb.on_new_session = &call_on_forked; inv_cb.on_media_update = &call_on_media_update; /* Initialize invite session module: */ status = pjsip_inv_usage_init(g_endpt, &inv_cb); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } /* Initialize 100rel support */ status = pjsip_100rel_init_module(g_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, status); /* * Register our module to receive incoming requests. */ status = pjsip_endpt_register_module( g_endpt, &mod_simpleua); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Register message logger module. */ status = pjsip_endpt_register_module( g_endpt, &msg_logger); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Initialize media endpoint. * This will implicitly initialize PJMEDIA too. */ #if PJ_HAS_THREADS status = pjmedia_endpt_create(&cp.factory, NULL, 1, &g_med_endpt); #else status = pjmedia_endpt_create(&cp.factory, pjsip_endpt_get_ioqueue(g_endpt), 0, &g_med_endpt); #endif PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* * Add PCMA/PCMU codec to the media endpoint. */ #if defined(PJMEDIA_HAS_G711_CODEC) && PJMEDIA_HAS_G711_CODEC!=0 status = pjmedia_codec_g711_init(g_med_endpt); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); #endif #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) /* Init video subsystem */ pool = pjmedia_endpt_create_pool(g_med_endpt, "Video subsystem", 512, 512); status = pjmedia_video_format_mgr_create(pool, 64, 0, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_converter_mgr_create(pool, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_vid_codec_mgr_create(pool, NULL); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); status = pjmedia_vid_dev_subsys_init(&cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); # if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0 /* Init ffmpeg video codecs */ status = pjmedia_codec_ffmpeg_vid_init(NULL, &cp.factory); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); # endif /* PJMEDIA_HAS_FFMPEG_VID_CODEC */ #endif /* PJMEDIA_HAS_VIDEO */ /* * Create media transport used to send/receive RTP/RTCP socket. * One media transport is needed for each call. Application may * opt to re-use the same media transport for subsequent calls. */ for (i = 0; i < PJ_ARRAY_SIZE(g_med_transport); ++i) { status = pjmedia_transport_udp_create3(g_med_endpt, AF, NULL, NULL, RTP_PORT + i*2, 0, &g_med_transport[i]); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create media transport", status); return 1; } /* * Get socket info (address, port) of the media transport. We will * need this info to create SDP (i.e. the address and port info in * the SDP). */ pjmedia_transport_info_init(&g_med_tpinfo[i]); pjmedia_transport_get_info(g_med_transport[i], &g_med_tpinfo[i]); pj_memcpy(&g_sock_info[i], &g_med_tpinfo[i].sock_info, sizeof(pjmedia_sock_info)); } /* * If URL is specified, then make call immediately. */ if (argc > 1) { pj_sockaddr hostaddr; char hostip[PJ_INET6_ADDRSTRLEN+2]; char temp[80]; pj_str_t dst_uri = pj_str(argv[1]); pj_str_t local_uri; pjsip_dialog *dlg; pjmedia_sdp_session *local_sdp; pjsip_tx_data *tdata; if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to retrieve local host IP", status); return 1; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:simpleuac@%s:%d>", hostip, SIP_PORT); local_uri = pj_str(temp); /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &local_uri, /* local URI */ &local_uri, /* local Contact */ &dst_uri, /* remote URI */ &dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create UAC dialog", status); return 1; } /* If we expect the outgoing INVITE to be challenged, then we should * put the credentials in the dialog here, with something like this: * { pjsip_cred_info cred[1]; cred[0].realm = pj_str("sip.server.realm"); cred[0].scheme = pj_str("digest"); cred[0].username = pj_str("theuser"); cred[0].data_type = PJSIP_CRED_DATA_PLAIN_PASSWD; cred[0].data = pj_str("thepassword"); pjsip_auth_clt_set_credentials( &dlg->auth_sess, 1, cred); } * */ /* Get the SDP body to be put in the outgoing INVITE, by asking * media endpoint to create one for us. */ status = pjmedia_endpt_create_sdp( g_med_endpt, /* the media endpt */ dlg->pool, /* pool. */ MAX_MEDIA_CNT, /* # of streams */ g_sock_info, /* RTP sock info */ &local_sdp); /* the SDP result */ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Create the INVITE session, and pass the SDP returned earlier * as the session's initial capability. */ status = pjsip_inv_create_uac( dlg, local_sdp, 0, &g_inv); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* If we want the initial INVITE to travel to specific SIP proxies, * then we should put the initial dialog's route set here. The final * route set will be updated once a dialog has been established. * To set the dialog's initial route set, we do it with something * like this: * { pjsip_route_hdr route_set; pjsip_route_hdr *route; const pj_str_t hname = { "Route", 5 }; char *uri = "sip:proxy.server;lr"; pj_list_init(&route_set); route = pjsip_parse_hdr( dlg->pool, &hname, uri, strlen(uri), NULL); PJ_ASSERT_RETURN(route != NULL, 1); pj_list_push_back(&route_set, route); pjsip_dlg_set_route_set(dlg, &route_set); } * * Note that Route URI SHOULD have an ";lr" parameter! */ /* Create initial INVITE request. * This INVITE request will contain a perfectly good request and * an SDP body as well. */ status = pjsip_inv_invite(g_inv, &tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); /* Send initial INVITE request. * From now on, the invite session's state will be reported to us * via the invite session callbacks. */ status = pjsip_inv_send_msg(g_inv, tdata); PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1); } else { /* No URL to make call to */ PJ_LOG(3,(THIS_FILE, "Ready to accept incoming calls...")); } /* Loop until one call is completed */ for (;!g_complete;) { pj_time_val timeout = {0, 10}; pjsip_endpt_handle_events(g_endpt, &timeout); } /* On exit, dump current memory usage: */ dump_pool_usage(THIS_FILE, &cp); /* Destroy audio ports. Destroy the audio port first * before the stream since the audio port has threads * that get/put frames to the stream. */ if (g_snd_port) pjmedia_snd_port_destroy(g_snd_port); #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) /* Destroy video ports */ if (g_vid_capturer) pjmedia_vid_port_destroy(g_vid_capturer); if (g_vid_renderer) pjmedia_vid_port_destroy(g_vid_renderer); #endif /* Destroy streams */ if (g_med_stream) pjmedia_stream_destroy(g_med_stream); #if defined(PJMEDIA_HAS_VIDEO) && (PJMEDIA_HAS_VIDEO != 0) if (g_med_vstream) pjmedia_vid_stream_destroy(g_med_vstream); /* Deinit ffmpeg codec */ # if defined(PJMEDIA_HAS_FFMPEG_VID_CODEC) && PJMEDIA_HAS_FFMPEG_VID_CODEC!=0 pjmedia_codec_ffmpeg_vid_deinit(); # endif #endif /* Destroy media transports */ for (i = 0; i < MAX_MEDIA_CNT; ++i) { if (g_med_transport[i]) pjmedia_transport_close(g_med_transport[i]); } /* Deinit pjmedia endpoint */ if (g_med_endpt) pjmedia_endpt_destroy(g_med_endpt); /* Deinit pjsip endpoint */ if (g_endpt) pjsip_endpt_destroy(g_endpt); /* Release pool */ if (pool) pj_pool_release(pool); return 0; }
/* main() * * If called with argument, treat argument as SIP URL to be called. * Otherwise wait for incoming calls. */ int main(int argc, char *argv[]) { if (init_stack()) goto on_error; /* If URL is specified, then make call immediately. */ if (argc > 1) { pj_sockaddr hostaddr; char hostip[PJ_INET6_ADDRSTRLEN+2]; char temp[80]; call_t *call; pj_str_t dst_uri = pj_str(argv[1]); pj_str_t local_uri; pjsip_dialog *dlg; pj_status_t status; pjsip_tx_data *tdata; if (pj_gethostip(AF, &hostaddr) != PJ_SUCCESS) { PJ_LOG(1,(THIS_FILE, "Unable to retrieve local host IP")); goto on_error; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, SIP_PORT); local_uri = pj_str(temp); call = &app.call[0]; status = pjsip_dlg_create_uac( pjsip_ua_instance(), &local_uri, /* local URI */ &local_uri, /* local Contact */ &dst_uri, /* remote URI */ &dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create UAC dialog", status); return 1; } status = pjsip_inv_create_uac( dlg, NULL, 0, &call->inv); if (status != PJ_SUCCESS) goto on_error; call->inv->mod_data[mod_sipecho.id] = call; status = pjsip_inv_invite(call->inv, &tdata); if (status != PJ_SUCCESS) goto on_error; status = pjsip_inv_send_msg(call->inv, tdata); if (status != PJ_SUCCESS) goto on_error; puts("Press ENTER to quit..."); } else { puts("Ready for incoming calls. Press ENTER to quit..."); } for (;;) { char s[10]; printf("\nMenu:\n" " h Hangup all calls\n" " l %s message logging\n" " q Quit\n", (app.enable_msg_logging? "Disable" : "Enable")); if (fgets(s, sizeof(s), stdin) == NULL) continue; if (s[0]=='q') break; switch (s[0]) { case 'l': app.enable_msg_logging = !app.enable_msg_logging; break; case 'h': hangup_all(); break; } } destroy_stack(); puts("Bye bye.."); return 0; on_error: puts("An error has occurred. run a debugger.."); return 1; }
static pj_bool_t on_rx_request( pjsip_rx_data *rdata ) { pj_sockaddr hostaddr; char temp[80], hostip[PJ_INET6_ADDRSTRLEN]; pj_str_t local_uri; pjsip_dialog *dlg; pjsip_rdata_sdp_info *sdp_info; pjmedia_sdp_session *answer = NULL; pjsip_tx_data *tdata = NULL; call_t *call = NULL; unsigned i; pj_status_t status; PJ_LOG(3,(THIS_FILE, "RX %.*s from %s", (int)rdata->msg_info.msg->line.req.method.name.slen, rdata->msg_info.msg->line.req.method.name.ptr, rdata->pkt_info.src_name)); if (rdata->msg_info.msg->line.req.method.id == PJSIP_REGISTER_METHOD) { /* Let me be a registrar! */ pjsip_hdr hdr_list, *h; pjsip_msg *msg; int expires = -1; pj_list_init(&hdr_list); msg = rdata->msg_info.msg; h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_EXPIRES, NULL); if (h) { expires = ((pjsip_expires_hdr*)h)->ivalue; pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h)); PJ_LOG(3,(THIS_FILE, " Expires=%d", expires)); } if (expires != 0) { h = (pjsip_hdr*)pjsip_msg_find_hdr(msg, PJSIP_H_CONTACT, NULL); if (h) pj_list_push_back(&hdr_list, pjsip_hdr_clone(rdata->tp_info.pool, h)); } pjsip_endpt_respond(app.sip_endpt, &mod_sipecho, rdata, 200, NULL, &hdr_list, NULL, NULL); return PJ_TRUE; } if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { if (rdata->msg_info.msg->line.req.method.id != PJSIP_ACK_METHOD) { pj_str_t reason = pj_str("Go away"); pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 400, &reason, NULL, NULL); } return PJ_TRUE; } sdp_info = pjsip_rdata_get_sdp_info(rdata); if (!sdp_info || !sdp_info->sdp) { pj_str_t reason = pj_str("Require valid offer"); pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 400, &reason, NULL, NULL); } for (i=0; i<MAX_CALLS; ++i) { if (app.call[i].inv == NULL) { call = &app.call[i]; break; } } if (i==MAX_CALLS) { pj_str_t reason = pj_str("We're full"); pjsip_endpt_respond_stateless( app.sip_endpt, rdata, PJSIP_SC_BUSY_HERE, &reason, NULL, NULL); return PJ_TRUE; } /* Generate Contact URI */ status = pj_gethostip(AF, &hostaddr); if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to retrieve local host IP", status); return PJ_TRUE; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, SIP_PORT); local_uri = pj_str(temp); status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, &local_uri, &dlg); if (status == PJ_SUCCESS) answer = create_answer(call-app.call, dlg->pool, sdp_info->sdp); if (status == PJ_SUCCESS) status = pjsip_inv_create_uas( dlg, rdata, answer, 0, &call->inv); if (status == PJ_SUCCESS) status = pjsip_inv_initial_answer(call->inv, rdata, 100, NULL, NULL, &tdata); if (status == PJ_SUCCESS) status = pjsip_inv_send_msg(call->inv, tdata); if (status == PJ_SUCCESS) status = pjsip_inv_answer(call->inv, 180, NULL, NULL, &tdata); if (status == PJ_SUCCESS) status = pjsip_inv_send_msg(call->inv, tdata); if (status == PJ_SUCCESS) status = pjsip_inv_answer(call->inv, 200, NULL, NULL, &tdata); if (status == PJ_SUCCESS) status = pjsip_inv_send_msg(call->inv, tdata); if (status != PJ_SUCCESS) { pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 500, NULL, NULL, NULL); destroy_call(call); } else { call->inv->mod_data[mod_sipecho.id] = call; } return PJ_TRUE; }
//Wrap start & stop PJ_DECL(pj_status_t) csipsimple_init(pjsua_config *ua_cfg, pjsua_logging_config *log_cfg, pjsua_media_config *media_cfg, csipsimple_config *css_cfg){ pj_status_t result; // Finalize configuration log_cfg->cb = &pj_android_log_msg; if(css_cfg->turn_username.slen){ media_cfg->turn_auth_cred.type = PJ_STUN_AUTH_CRED_STATIC; media_cfg->turn_auth_cred.data.static_cred.realm = pj_str("*"); media_cfg->turn_auth_cred.data.static_cred.username = css_cfg->turn_username; if (css_cfg->turn_password.slen) { media_cfg->turn_auth_cred.data.static_cred.data_type = PJ_STUN_PASSWD_PLAIN; media_cfg->turn_auth_cred.data.static_cred.data = css_cfg->turn_password; } } // Static cfg extern pj_bool_t pjsip_use_compact_form; extern pj_bool_t pjsip_include_allow_hdr_in_dlg; extern pj_bool_t pjmedia_add_rtpmap_for_static_pt; extern pj_bool_t pjsua_no_update; pjsua_no_update = css_cfg->use_no_update ? PJ_TRUE : PJ_FALSE; pjsip_use_compact_form = css_cfg->use_compact_form_headers ? PJ_TRUE : PJ_FALSE; /* do not transmit Allow header */ pjsip_include_allow_hdr_in_dlg = css_cfg->use_compact_form_headers ? PJ_FALSE : PJ_TRUE; /* Do not include rtpmap for static payload types (<96) */ pjmedia_add_rtpmap_for_static_pt = css_cfg->use_compact_form_sdp ? PJ_FALSE : PJ_TRUE; #if defined(PJMEDIA_HAS_ZRTP) && PJMEDIA_HAS_ZRTP!=0 if(css_cfg->use_zrtp){ ua_cfg->cb.on_create_media_transport = &on_zrtp_transport_created; } #endif result = (pj_status_t) pjsua_init(ua_cfg, log_cfg, media_cfg); if(result == PJ_SUCCESS){ init_ringback_tone(); #if PJMEDIA_AUDIO_DEV_HAS_ANDROID #if PJ_ANDROID_DEVICE==1 pjmedia_aud_register_factory(&pjmedia_android_factory); #endif #if PJ_ANDROID_DEVICE==2 pjmedia_aud_register_factory(&pjmedia_opensl_factory); #endif #endif #if USE_TCP_HACK==1 // Registering module for tcp hack static pjsip_module tcp_hack_mod; // cannot be a stack variable memset(&tcp_hack_mod, 0, sizeof(tcp_hack_mod)); tcp_hack_mod.id = -1; tcp_hack_mod.priority = PJSIP_MOD_PRIORITY_UA_PROXY_LAYER - 1; tcp_hack_mod.on_rx_response = &on_rx_request_tcp_hack; tcp_hack_mod.name = pj_str("TCP-Hack"); result = pjsip_endpt_register_module(pjsip_ua_get_endpt(pjsip_ua_instance()), &tcp_hack_mod); #endif } return result; }
/* main() * * If called with argument, treat argument as SIP URL to be called. * Otherwise wait for incoming calls. */ int main(int argc, char *argv[]) { struct pj_getopt_option long_options[] = { { "local-port", 1, 0, 'p' }, { "tcp", 0, 0, 't' }, { "ipv6", 0, 0, '6' }, { "help", 0, 0, 'h' } }; int c, option_index; pj_log_set_level(5); pj_init(); sip_af = pj_AF_INET(); pj_optind = 0; while ((c = pj_getopt_long(argc, argv, "p:t6h", long_options, &option_index)) != -1) { switch (c) { case 'p': sip_port = atoi(pj_optarg); break; case 't': sip_tcp = PJ_TRUE; break; case 'h': usage(); return 0; case '6': sip_af = pj_AF_INET6(); break; default: PJ_LOG(1,(THIS_FILE, "Argument \"%s\" is not valid. Use --help to see help", argv[pj_optind-1])); return -1; } } if (init_stack()) goto on_error; /* If URL is specified, then make call immediately. */ if (pj_optind != argc) { pj_sockaddr hostaddr; char hostip[PJ_INET6_ADDRSTRLEN+2]; char temp[80]; call_t *call; pj_str_t dst_uri = pj_str(argv[pj_optind]); pj_str_t local_uri; pjsip_dialog *dlg; pj_status_t status; pjsip_tx_data *tdata; if (pj_gethostip(sip_af, &hostaddr) != PJ_SUCCESS) { PJ_LOG(1,(THIS_FILE, "Unable to retrieve local host IP")); goto on_error; } pj_sockaddr_print(&hostaddr, hostip, sizeof(hostip), 2); pj_ansi_sprintf(temp, "<sip:sipecho@%s:%d>", hostip, sip_port); local_uri = pj_str(temp); call = &app.call[0]; status = pjsip_dlg_create_uac( pjsip_ua_instance(), &local_uri, /* local URI */ &local_uri, /* local Contact */ &dst_uri, /* remote URI */ &dst_uri, /* remote target */ &dlg); /* dialog */ if (status != PJ_SUCCESS) { app_perror(THIS_FILE, "Unable to create UAC dialog", status); return 1; } status = pjsip_inv_create_uac( dlg, NULL, 0, &call->inv); if (status != PJ_SUCCESS) goto on_error; call->inv->mod_data[mod_sipecho.id] = call; status = pjsip_inv_invite(call->inv, &tdata); if (status != PJ_SUCCESS) goto on_error; status = pjsip_inv_send_msg(call->inv, tdata); if (status != PJ_SUCCESS) goto on_error; puts("Press ENTER to quit..."); } else { puts("Ready for incoming calls. Press ENTER to quit..."); } for (;;) { char s[10]; printf("\nMenu:\n" " h Hangup all calls\n" " l %s message logging\n" " q Quit\n", (app.enable_msg_logging? "Disable" : "Enable")); if (fgets(s, sizeof(s), stdin) == NULL) continue; if (s[0]=='q') break; switch (s[0]) { case 'l': app.enable_msg_logging = !app.enable_msg_logging; break; case 'h': hangup_all(); break; } } destroy_stack(); puts("Bye bye.."); return 0; on_error: puts("An error has occurred. run a debugger.."); return 1; }
/* This is called when request is received. * We need to check for incoming SUBSCRIBE request. */ static pj_bool_t pres_on_rx_request(pjsip_rx_data *rdata) { int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_method *req_method = &rdata->msg_info.msg->line.req.method; pjsua_srv_pres *uapres; pjsip_evsub *sub; pjsip_evsub_user pres_cb; pjsip_dialog *dlg; pjsip_status_code st_code; pj_str_t reason; pjsip_expires_hdr *expires_hdr; pjsua_msg_data msg_data; pj_status_t status; if (pjsip_method_cmp(req_method, pjsip_get_subscribe_method()) != 0) return PJ_FALSE; /* Incoming SUBSCRIBE: */ PJSUA_LOCK(); /* Find which account for the incoming request. */ acc_id = pjsua_acc_find_for_incoming(rdata); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Creating server subscription, using account %d", acc_id)); /* Create suitable Contact header */ if (acc->contact.slen) { contact = acc->contact; } else { status = pjsua_acc_create_uas_contact(rdata->tp_info.pool, &contact, acc_id, rdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } } /* Create UAS dialog: */ status = pjsip_dlg_create_uas(pjsip_ua_instance(), rdata, &contact, &dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create UAS dialog for subscription", status); PJSUA_UNLOCK(); pjsip_endpt_respond_stateless(pjsua_var.endpt, rdata, 400, NULL, NULL, NULL); return PJ_TRUE; } /* Set credentials and preference. */ pjsip_auth_clt_set_credentials(&dlg->auth_sess, acc->cred_cnt, acc->cred); pjsip_auth_clt_set_prefs(&dlg->auth_sess, &acc->cfg.auth_pref); /* Init callback: */ pj_bzero(&pres_cb, sizeof(pres_cb)); pres_cb.on_evsub_state = &pres_evsub_on_srv_state; /* Create server presence subscription: */ status = pjsip_pres_create_uas( dlg, &pres_cb, rdata, &sub); if (status != PJ_SUCCESS) { int code = PJSIP_ERRNO_TO_SIP_STATUS(status); pjsip_tx_data *tdata; pjsua_perror(THIS_FILE, "Unable to create server subscription", status); if (code==599 || code > 699 || code < 300) { code = 400; } status = pjsip_dlg_create_response(dlg, rdata, code, NULL, &tdata); if (status == PJ_SUCCESS) { status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); } PJSUA_UNLOCK(); return PJ_TRUE; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(dlg, &tp_sel); } /* Attach our data to the subscription: */ uapres = PJ_POOL_ALLOC_T(dlg->pool, pjsua_srv_pres); uapres->sub = sub; uapres->remote = (char*) pj_pool_alloc(dlg->pool, PJSIP_MAX_URL_SIZE); uapres->acc_id = acc_id; uapres->dlg = dlg; status = pjsip_uri_print(PJSIP_URI_IN_REQ_URI, dlg->remote.info->uri, uapres->remote, PJSIP_MAX_URL_SIZE); if (status < 1) pj_ansi_strcpy(uapres->remote, "<-- url is too long-->"); else uapres->remote[status] = '\0'; pjsip_evsub_set_mod_data(sub, pjsua_var.mod.id, uapres); /* Add server subscription to the list: */ pj_list_push_back(&pjsua_var.acc[acc_id].pres_srv_list, uapres); /* Capture the value of Expires header. */ expires_hdr = (pjsip_expires_hdr*) pjsip_msg_find_hdr(rdata->msg_info.msg, PJSIP_H_EXPIRES, NULL); if (expires_hdr) uapres->expires = expires_hdr->ivalue; else uapres->expires = -1; st_code = (pjsip_status_code)200; reason = pj_str("OK"); pjsua_msg_data_init(&msg_data); /* Notify application callback, if any */ if (pjsua_var.ua_cfg.cb.on_incoming_subscribe) { pjsua_buddy_id buddy_id; buddy_id = pjsua_find_buddy(rdata->msg_info.from->uri); (*pjsua_var.ua_cfg.cb.on_incoming_subscribe)(acc_id, uapres, buddy_id, &dlg->remote.info_str, rdata, &st_code, &reason, &msg_data); } /* Handle rejection case */ if (st_code >= 300) { pjsip_tx_data *tdata; /* Create response */ status = pjsip_dlg_create_response(dlg, rdata, st_code, &reason, &tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error creating response", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* Add header list, if any */ pjsua_process_msg_data(tdata, &msg_data); /* Send the response */ status = pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Error sending response", status); /* This is not fatal */ } /* Terminate presence subscription */ pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_TRUE; } /* Create and send 2xx response to the SUBSCRIBE request: */ status = pjsip_pres_accept(sub, rdata, st_code, &msg_data.hdr_list); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to accept presence subscription", status); pj_list_erase(uapres); pjsip_pres_terminate(sub, PJ_FALSE); PJSUA_UNLOCK(); return PJ_FALSE; } /* If code is 200, send NOTIFY now */ if (st_code == 200) { pjsua_pres_notify(acc_id, uapres, PJSIP_EVSUB_STATE_ACTIVE, NULL, NULL, PJ_TRUE, &msg_data); } /* Done: */ PJSUA_UNLOCK(); return PJ_TRUE; }
/* It does what it says.. */ static void subscribe_buddy_presence(unsigned index) { pj_pool_t *tmp_pool = NULL; pjsua_buddy *buddy; int acc_id; pjsua_acc *acc; pj_str_t contact; pjsip_tx_data *tdata; pj_status_t status; buddy = &pjsua_var.buddy[index]; acc_id = pjsua_acc_find_for_outgoing(&buddy->uri); acc = &pjsua_var.acc[acc_id]; PJ_LOG(4,(THIS_FILE, "Using account %d for buddy %d subscription", acc_id, index)); /* Generate suitable Contact header unless one is already set in * the account */ if (acc->contact.slen) { contact = acc->contact; } else { tmp_pool = pjsua_pool_create("tmpbuddy", 512, 256); status = pjsua_acc_create_uac_contact(tmp_pool, &contact, acc_id, &buddy->uri); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to generate Contact header", status); pj_pool_release(tmp_pool); return; } } /* Create UAC dialog */ status = pjsip_dlg_create_uac( pjsip_ua_instance(), &acc->cfg.id, &contact, &buddy->uri, NULL, &buddy->dlg); if (status != PJ_SUCCESS) { pjsua_perror(THIS_FILE, "Unable to create dialog", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } /* Increment the dialog's lock otherwise when presence session creation * fails the dialog will be destroyed prematurely. */ pjsip_dlg_inc_lock(buddy->dlg); status = pjsip_pres_create_uac( buddy->dlg, &pres_callback, PJSIP_EVSUB_NO_EVENT_ID, &buddy->sub); if (status != PJ_SUCCESS) { pjsua_var.buddy[index].sub = NULL; pjsua_perror(THIS_FILE, "Unable to create presence client", status); /* This should destroy the dialog since there's no session * referencing it */ pjsip_dlg_dec_lock(buddy->dlg); if (tmp_pool) pj_pool_release(tmp_pool); return; } /* If account is locked to specific transport, then lock dialog * to this transport too. */ if (acc->cfg.transport_id != PJSUA_INVALID_ID) { pjsip_tpselector tp_sel; pjsua_init_tpselector(acc->cfg.transport_id, &tp_sel); pjsip_dlg_set_transport(buddy->dlg, &tp_sel); } /* Set route-set */ if (!pj_list_empty(&acc->route_set)) { pjsip_dlg_set_route_set(buddy->dlg, &acc->route_set); } /* Set credentials */ if (acc->cred_cnt) { pjsip_auth_clt_set_credentials( &buddy->dlg->auth_sess, acc->cred_cnt, acc->cred); } /* Set authentication preference */ pjsip_auth_clt_set_prefs(&buddy->dlg->auth_sess, &acc->cfg.auth_pref); pjsip_evsub_set_mod_data(buddy->sub, pjsua_var.mod.id, buddy); status = pjsip_pres_initiate(buddy->sub, -1, &tdata); if (status != PJ_SUCCESS) { pjsip_dlg_dec_lock(buddy->dlg); if (buddy->sub) { pjsip_pres_terminate(buddy->sub, PJ_FALSE); } buddy->sub = NULL; pjsua_perror(THIS_FILE, "Unable to create initial SUBSCRIBE", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } pjsua_process_msg_data(tdata, NULL); status = pjsip_pres_send_request(buddy->sub, tdata); if (status != PJ_SUCCESS) { pjsip_dlg_dec_lock(buddy->dlg); if (buddy->sub) { pjsip_pres_terminate(buddy->sub, PJ_FALSE); } buddy->sub = NULL; pjsua_perror(THIS_FILE, "Unable to send initial SUBSCRIBE", status); if (tmp_pool) pj_pool_release(tmp_pool); return; } pjsip_dlg_dec_lock(buddy->dlg); if (tmp_pool) pj_pool_release(tmp_pool); }
static pj_bool_t mod_call_on_rx_request(pjsip_rx_data *rdata) { const pj_str_t call_user = { "2", 1 }; pjsip_uri *uri; pjsip_sip_uri *sip_uri; struct call *call; pjsip_dialog *dlg; pjmedia_sdp_session *sdp; pjsip_tx_data *tdata; pj_bool_t has_initial = PJ_FALSE; pj_status_t status; uri = pjsip_uri_get_uri(rdata->msg_info.msg->line.req.uri); /* Only want to receive SIP/SIPS scheme */ if (!PJSIP_URI_SCHEME_IS_SIP(uri) && !PJSIP_URI_SCHEME_IS_SIPS(uri)) return PJ_FALSE; sip_uri = (pjsip_sip_uri*) uri; /* Only want to handle INVITE requests. */ if (rdata->msg_info.msg->line.req.method.id != PJSIP_INVITE_METHOD) { return PJ_FALSE; } /* Check for matching user part. Incoming requests will be handled * call-statefully if: * - user part is "2", or * - user part is not "0" nor "1" and method is INVITE. */ if (pj_strcmp(&sip_uri->user, &call_user) == 0 || sip_uri->user.slen != 1 || (*sip_uri->user.ptr != '0' && *sip_uri->user.ptr != '1')) { /* Match */ } else { return PJ_FALSE; } /* Verify that we can handle the request. */ if (app.real_sdp) { unsigned options = 0; status = pjsip_inv_verify_request(rdata, &options, NULL, NULL, app.sip_endpt, &tdata); if (status != PJ_SUCCESS) { /* * No we can't handle the incoming INVITE request. */ if (tdata) { pjsip_response_addr res_addr; pjsip_get_response_addr(tdata->pool, rdata, &res_addr); pjsip_endpt_send_response(app.sip_endpt, &res_addr, tdata, NULL, NULL); } else { /* Respond with 500 (Internal Server Error) */ pjsip_endpt_respond_stateless(app.sip_endpt, rdata, 500, NULL, NULL, NULL); } return PJ_TRUE; } } /* Create UAS dialog */ status = pjsip_dlg_create_uas( pjsip_ua_instance(), rdata, &app.local_contact, &dlg); if (status != PJ_SUCCESS) { const pj_str_t reason = pj_str("Unable to create dialog"); pjsip_endpt_respond_stateless( app.sip_endpt, rdata, 500, &reason, NULL, NULL); return PJ_TRUE; } /* Alloc call structure. */ call = pj_pool_zalloc(dlg->pool, sizeof(struct call)); /* Create SDP from PJMEDIA */ if (app.real_sdp) { status = pjmedia_endpt_create_sdp(app.med_endpt, rdata->tp_info.pool, app.skinfo_cnt, app.skinfo, &sdp); } else { sdp = app.dummy_sdp; } /* Create UAS invite session */ status = pjsip_inv_create_uas( dlg, rdata, sdp, 0, &call->inv); if (status != PJ_SUCCESS) { pjsip_dlg_create_response(dlg, rdata, 500, NULL, &tdata); pjsip_dlg_send_response(dlg, pjsip_rdata_get_tsx(rdata), tdata); return PJ_TRUE; } /* Send 100/Trying if needed */ if (app.server.send_trying) { status = send_response(call->inv, rdata, 100, &has_initial); if (status != PJ_SUCCESS) return PJ_TRUE; } /* Send 180/Ringing if needed */ if (app.server.send_ringing) { status = send_response(call->inv, rdata, 180, &has_initial); if (status != PJ_SUCCESS) return PJ_TRUE; } /* Simulate call processing delay */ if (app.server.delay) { pj_time_val delay; call->ans_timer.id = 1; call->ans_timer.user_data = call; call->ans_timer.cb = &answer_timer_cb; delay.sec = 0; delay.msec = app.server.delay; pj_time_val_normalize(&delay); pjsip_endpt_schedule_timer(app.sip_endpt, &call->ans_timer, &delay); } else { /* Send the 200 response immediately . */ status = send_response(call->inv, rdata, 200, &has_initial); PJ_ASSERT_ON_FAIL(status == PJ_SUCCESS, return PJ_TRUE); } /* Done */ app.server.cur_state.call_cnt++; return PJ_TRUE; }