Exemple #1
0
/* 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;
}
Exemple #2
0
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;
}
Exemple #3
0
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));
}
Exemple #4
0
/**
 * サーバプロセス
 *
 * @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;
}