/* The best bit: SDP negotiation function! */ PJ_DEF(pj_status_t) pjmedia_sdp_neg_negotiate( pj_pool_t *pool, pjmedia_sdp_neg *neg, pj_bool_t allow_asym) { pj_status_t status; /* Check arguments are valid. */ PJ_ASSERT_RETURN(pool && neg, PJ_EINVAL); /* Must be in STATE_WAIT_NEGO state. */ PJ_ASSERT_RETURN(neg->state == PJMEDIA_SDP_NEG_STATE_WAIT_NEGO, PJMEDIA_SDPNEG_EINSTATE); /* Must have remote offer. */ PJ_ASSERT_RETURN(neg->neg_remote_sdp, PJ_EBUG); if (neg->has_remote_answer) { pjmedia_sdp_session *active; status = process_answer(pool, neg->neg_local_sdp, neg->neg_remote_sdp, allow_asym, &active); if (status == PJ_SUCCESS) { /* Only update active SDPs when negotiation is successfull */ neg->active_local_sdp = active; neg->active_remote_sdp = neg->neg_remote_sdp; } } else { pjmedia_sdp_session *answer = NULL; status = create_answer(pool, neg->prefer_remote_codec_order, neg->neg_local_sdp, neg->neg_remote_sdp, &answer); if (status == PJ_SUCCESS) { pj_uint32_t active_ver; if (neg->active_local_sdp) active_ver = neg->active_local_sdp->origin.version; else active_ver = neg->initial_sdp->origin.version; /* Only update active SDPs when negotiation is successfull */ neg->active_local_sdp = answer; neg->active_remote_sdp = neg->neg_remote_sdp; /* Increment SDP version */ neg->active_local_sdp->origin.version = ++active_ver; } } /* State is DONE regardless */ neg->state = PJMEDIA_SDP_NEG_STATE_DONE; /* Save state */ neg->answer_was_remote = neg->has_remote_answer; /* Clear temporary SDP */ neg->neg_local_sdp = neg->neg_remote_sdp = NULL; neg->has_remote_answer = PJ_FALSE; return status; }
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; }
static void call_on_rx_offer(pjsip_inv_session *inv, const pjmedia_sdp_session *offer) { call_t *call = (call_t*) inv->mod_data[mod_sipecho.id]; pjsip_inv_set_sdp_answer(inv, create_answer(call - app.call, inv->pool_prov, offer)); }
/** * サーバプロセス * * @param[in] arg ソケットディスクリプタ * @return 常にNULL */ static void * server_proc(void *arg) { thread_data dt; /* スレッドデータ構造体 */ int retval = 0; /* 戻り値 */ size_t length = 0; /* 長さ */ ssize_t slen = 0; /* 送信するバイト数 */ struct header hd; /* ヘッダ構造体 */ unsigned char *expr = NULL; /* 受信データ */ calcinfo calc; /* calc情報構造体 */ struct server_data *sdata = NULL; /* 送信データ構造体 */ (void)memcpy(&dt, arg, sizeof(thread_data)); dbglog("start: accept=%d sin_addr=%s sin_port=%d, len=%d", dt.sock, inet_ntoa(dt.addr.sin_addr), ntohs(dt.addr.sin_port), dt.len); /* シグナルマスクを設定 */ set_thread_sigmask(dt.sigmask); pthread_cleanup_push(thread_cleanup, &dt); do { /* ヘッダ受信 */ length = sizeof(struct header); (void)memset(&hd, 0, length); retval = recv_data(dt.sock, &hd, &length); if (retval < 0) /* エラーまたは接続先がシャットダウンされた */ pthread_exit((void *)EXIT_FAILURE); dbglog("recv_data: hd=%p, length=%zu, hd.length=%zu", &hd, length, hd.length); if (g_gflag) outdump(&hd, length, "recv: hd=%p, length=%zu", &hd, length); stddump(&hd, length, "recv: hd=%p, length=%zu", &hd, length); /* データ受信 */ length = (size_t)ntohl((uint32_t)hd.length); /* データ長を保持 */ expr = (unsigned char *)recv_data_new(dt.sock, &length); if (!expr) /* メモリ不足 */ pthread_exit((void *)EXIT_FAILURE); pthread_cleanup_push(thread_memfree, &expr); if (!length) /* 受信エラー */ pthread_exit((void *)EXIT_FAILURE); dbglog("expr=%p, length=%zu", expr, length); if (g_gflag) outdump(expr, length, "recv: expr=%p, length=%zu", expr, length); stddump(expr, length, "recv: expr=%p, length=%zu", expr, length); /* サーバ処理 */ (void)memset(&calc, 0, sizeof(calcinfo)); if (!create_answer(&calc, expr)) pthread_exit((void *)EXIT_FAILURE); pthread_cleanup_push(destroy_answer, &calc); length = strlen((char *)calc.answer) + 1; /* 文字列長保持 */ dbgdump(calc.answer, length, "answer=%p, length=%zu", calc.answer, length); /* データ送信 */ slen = set_server_data(&sdata, calc.answer, length); if (slen < 0) /* メモリ確保できない */ pthread_exit((void *)EXIT_FAILURE); pthread_cleanup_push(thread_memfree, &sdata); dbglog("slen=%zd", slen); if (g_gflag) outdump(sdata, slen, "send: sdata=%p, slen=%zd", sdata, slen); stddump(sdata, slen, "send: sdata=%p, slen=%zd", sdata, slen); retval = send_data(dt.sock, sdata, (size_t *)&slen); if (retval < 0) /* エラー */ pthread_exit((void *)EXIT_FAILURE); dbglog("send_data: sdata=%p, slen=%zu", sdata, slen); pthread_cleanup_pop(1); pthread_cleanup_pop(1); pthread_cleanup_pop(1); } while (!g_sig_handled); pthread_cleanup_pop(1); pthread_exit((void *)EXIT_SUCCESS); return (void *)EXIT_SUCCESS; }