Beispiel #1
0
enum gui_key gui_msgbox(const char *title, const char *message, enum gui_flag flag)
{
    wchar_t buf_title[64];
    wchar_t buf_msg[512];
    UINT wflag = 0;
    int retcode;

    pj_ansi_to_unicode(title, pj_ansi_strlen(title), buf_title, 64);
    pj_ansi_to_unicode(message, pj_ansi_strlen(message), buf_msg, 512);

    switch (flag) {
    case WITH_OK:
	wflag = MB_OK;
	break;
    case WITH_YESNO:
	wflag = MB_YESNO;
	break;
    case WITH_OKCANCEL:
	wflag = MB_OKCANCEL;
	break;
    }

    retcode = MessageBox(g_hWndMain, buf_msg, buf_title, wflag);

    switch (retcode) {
    case IDOK:
	return KEY_OK;
    case IDYES:
	return KEY_YES;
    case IDNO:
	return KEY_NO;
    default:
	return KEY_CANCEL;
    }
}
Beispiel #2
0
static void on_read_complete(pj_ioqueue_key_t *key, 
                             pj_ioqueue_op_key_t *op_key, 
                             pj_ssize_t bytes_read)
{
    pj_ssize_t size;
    char *sendbuf = "Hello world";
    pj_status_t status;

    if (sock_data.unregistered)
	return;

    pj_mutex_lock(sock_data.mutex);

    if (sock_data.unregistered) {
	pj_mutex_unlock(sock_data.mutex);
	return;
    }

    if (bytes_read < 0) {
	if (-bytes_read != PJ_STATUS_FROM_OS(PJ_BLOCKING_ERROR_VAL))
	    app_perror("ioqueue reported recv error", -bytes_read);
    } else {
	sock_data.received += bytes_read;
    }

    if (test_method == UNREGISTER_IN_CALLBACK) {
	pj_time_val now;

	pj_gettimeofday(&now);
	if (PJ_TIME_VAL_GTE(now, time_to_unregister)) { 
	    sock_data.unregistered = 1;
	    pj_ioqueue_unregister(key);
	    pj_mutex_destroy(sock_data.mutex);
	    pj_pool_release(sock_data.pool);
	    sock_data.pool = NULL;
	    return;
	}
    }
 
    do { 
	size = sock_data.bufsize;
	status = pj_ioqueue_recv(key, op_key, sock_data.buffer, &size, 0);
	if (status != PJ_EPENDING && status != PJ_SUCCESS)
	    app_perror("recv() error", status);

    } while (status == PJ_SUCCESS);

    pj_mutex_unlock(sock_data.mutex);

    size = pj_ansi_strlen(sendbuf);
    status = pj_sock_send(sock_data.csock, sendbuf, &size, 0);
    if (status != PJ_SUCCESS)
	app_perror("send() error", status);

    size = pj_ansi_strlen(sendbuf);
    status = pj_sock_send(sock_data.csock, sendbuf, &size, 0);
    if (status != PJ_SUCCESS)
	app_perror("send() error", status);

} 
Beispiel #3
0
/* generate submenu and register the menu handler, then return next menu id */
static UINT generate_submenu(HMENU parent, UINT id_start, gui_menu *menu)
{
    unsigned i;
    UINT id = id_start;

    if (!menu)
	return id;

    /* generate submenu */
    for (i = 0; i < menu->submenu_cnt; ++i) {

	if (menu->submenus[i] == NULL) {

	    /* add separator */
	    AppendMenu(parent, MF_SEPARATOR, 0, 0);
	
	}  else if (menu->submenus[i]->submenu_cnt != 0) {
	    
	    /* this submenu item has children, generate popup menu */
	    HMENU hMenu;
	    wchar_t buf[64];
	    
	    pj_ansi_to_unicode(menu->submenus[i]->title, 
			       pj_ansi_strlen(menu->submenus[i]->title),
			       buf, 64);

	    hMenu = CreatePopupMenu();
	    AppendMenu(parent, MF_STRING|MF_ENABLED|MF_POPUP, (UINT)hMenu, buf);
	    id = generate_submenu(hMenu, id, menu->submenus[i]);

	} else {

	    /* this submenu item is leaf, register the handler */
	    wchar_t buf[64];
	    
	    pj_ansi_to_unicode(menu->submenus[i]->title, 
			       pj_ansi_strlen(menu->submenus[i]->title),
			       buf, 64);

	    AppendMenu(parent, MF_STRING, id, buf);

	    if (menu->submenus[i]->handler) {
		g_menu_handlers[g_menu_handler_cnt].id = id;
		g_menu_handlers[g_menu_handler_cnt].handler = 
					menu->submenus[i]->handler;
		++g_menu_handler_cnt;
	    }

	    ++id;
	}
    }

    return id;
}
Beispiel #4
0
/**
 * Callback upon NAT detection completion
 */
static void nat_detect_cb (const pj_stun_nat_detect_result *res)
{
    if (res->status != PJ_SUCCESS) {
        char msg[250];
        pj_ansi_snprintf (msg, sizeof (msg), "NAT detection failed: %s",
                          res->status_text);
        SetCallStatus (msg, pj_ansi_strlen (msg));
    } else {
        char msg[250];
        pj_ansi_snprintf (msg, sizeof (msg), "NAT type is %s",
                          res->nat_type_name);
        SetCallStatus (msg, pj_ansi_strlen (msg));
    }
}
Beispiel #5
0
static void ffmpeg_log_cb(void* ptr, int level, const char* fmt, va_list vl)
{
    const char *LOG_SENDER = "ffmpeg";
    enum { LOG_LEVEL = 5 };
    char buf[100];
    int bufsize = sizeof(buf), len;
    pj_str_t fmt_st;

    /* Custom callback needs to filter log level by itself */
    if (level > av_log_get_level())
	return;
    
    /* Add original ffmpeg sender to log format */
    if (ptr) {
	AVClass* avc = *(AVClass**)ptr;
	len = pj_ansi_snprintf(buf, bufsize, "%s: ", avc->item_name(ptr));
	bufsize -= len;
    }

    /* Copy original log format */
    len = pj_ansi_strlen(fmt);
    if (len > bufsize-1)
	len = bufsize-1;
    pj_memcpy(buf+sizeof(buf)-bufsize, fmt, len);
    bufsize -= len;

    /* Trim log format */
    pj_strset(&fmt_st, buf, sizeof(buf)-bufsize);
    pj_strrtrim(&fmt_st);
    buf[fmt_st.slen] = '\0';

    pj_log(LOG_SENDER, LOG_LEVEL, buf, vl);
}
Beispiel #6
0
/*
 * Register new transport type to PJSIP.
 */
PJ_DEF(pj_status_t) pjsip_transport_register_type( unsigned tp_flag,
						   const char *tp_name,
						   int def_port,
						   int *p_tp_type)
{
    unsigned i;

    PJ_ASSERT_RETURN(tp_flag && tp_name && def_port, PJ_EINVAL);
    PJ_ASSERT_RETURN(pj_ansi_strlen(tp_name) < 
			PJ_ARRAY_SIZE(transport_names[0].name_buf), 
		     PJ_ENAMETOOLONG);

    for (i=1; i<PJ_ARRAY_SIZE(transport_names); ++i) {
	if (transport_names[i].type == 0)
	    break;
    }

    if (i == PJ_ARRAY_SIZE(transport_names))
	return PJ_ETOOMANY;

    transport_names[i].type = (pjsip_transport_type_e)i;
    transport_names[i].port = (pj_uint16_t)def_port;
    pj_ansi_strcpy(transport_names[i].name_buf, tp_name);
    transport_names[i].name = pj_str(transport_names[i].name_buf);
    transport_names[i].flag = tp_flag;

    if (p_tp_type)
	*p_tp_type = i;

    return PJ_SUCCESS;
}
Beispiel #7
0
PJ_DEF(unsigned) pjmedia_sdp_attr_remove_all(unsigned *count,
					     pjmedia_sdp_attr *attr_array[],
					     const char *name)
{
    unsigned i, removed = 0;
    pj_str_t attr_name;

    PJ_ASSERT_RETURN(count && attr_array && name, PJ_EINVAL);

    attr_name.ptr = (char*)name;
    attr_name.slen = pj_ansi_strlen(name);

    for (i=0; i<*count; ) {
	if (pj_strcmp(&attr_array[i]->name, &attr_name)==0) {
	    pj_array_erase(attr_array, sizeof(pjmedia_sdp_attr*),
			   *count, i);
	    --(*count);
	    ++removed;
	} else {
	    ++i;
	}   
    }

    return removed;
}
Beispiel #8
0
/*
 * pjnath_strerror()
 */
static pj_str_t pjnath_strerror(pj_status_t statcode, 
				char *buf, pj_size_t bufsize )
{
    pj_str_t errstr;

#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)

    if (statcode >= PJNATH_ERRNO_START && 
	statcode < PJNATH_ERRNO_START + PJ_ERRNO_SPACE_SIZE)
    {
	/* Find the error in the table.
	 * Use binary search!
	 */
	int first = 0;
	int n = PJ_ARRAY_SIZE(err_str);

	while (n > 0) {
	    int half = n/2;
	    int mid = first + half;

	    if (err_str[mid].code < statcode) {
		first = mid+1;
		n -= (half+1);
	    } else if (err_str[mid].code > statcode) {
		n = half;
	    } else {
		first = mid;
		break;
	    }
	}


	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
	    pj_str_t msg;
	    
	    msg.ptr = (char*)err_str[first].msg;
	    msg.slen = pj_ansi_strlen(err_str[first].msg);

	    errstr.ptr = buf;
	    pj_strncpy_with_null(&errstr, &msg, bufsize);
	    return errstr;

	} 
    }

#endif	/* PJ_HAS_ERROR_STRING */


    /* Error not found. */
    errstr.ptr = buf;
    errstr.slen = pj_ansi_snprintf(buf, bufsize, 
				   "Unknown pjnath error %d",
				   statcode);
    if (errstr.slen < 0) errstr.slen = 0;
    else if (errstr.slen > (int)bufsize) errstr.slen = bufsize;

    return errstr;
}
Beispiel #9
0
static void SetCallStatus (const char *state, int len)
{
    wchar_t tmp[128];

    if (len==-1) len=pj_ansi_strlen (state);

    pj_ansi_to_unicode (state, len, tmp, PJ_ARRAY_SIZE (tmp));
    SetDlgItemText (hMainWnd, ID_CALL_STATUS, tmp);
}
Beispiel #10
0
static void sockaddr_to_host_port( pj_pool_t *pool,
				   pjsip_host_port *host_port,
				   const pj_sockaddr_in *addr )
{
    host_port->host.ptr = (char*) pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+4);
    pj_sockaddr_print(addr, host_port->host.ptr, PJ_INET6_ADDRSTRLEN+4, 2);
    host_port->host.slen = pj_ansi_strlen(host_port->host.ptr);
    host_port->port = pj_sockaddr_get_port(addr);
}
Beispiel #11
0
static void SetURI (const char *uri, int len, bool enabled=true)
{
    wchar_t tmp[128];

    if (len==-1) len=pj_ansi_strlen (uri);

    pj_ansi_to_unicode (uri, len, tmp, PJ_ARRAY_SIZE (tmp));
    SetDlgItemText (hMainWnd, ID_URI, tmp);
    EnableWindow (hwndURI, enabled?TRUE:FALSE);
}
Beispiel #12
0
/*
 * pjmedia_videodev_strerror()
 */
PJ_DEF(pj_str_t) pjmedia_videodev_strerror(pj_status_t statcode,
					   char *buf, pj_size_t bufsize )
{
    pj_str_t errstr;

#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)

    /* videodev error */
    if (statcode >= PJMEDIA_VIDEODEV_ERRNO_START &&
	statcode < PJMEDIA_VIDEODEV_ERRNO_END)
    {
	/* Find the error in the table.
	 * Use binary search!
	 */
	int first = 0;
	int n = PJ_ARRAY_SIZE(err_str);

	while (n > 0) {
	    int half = n/2;
	    int mid = first + half;

	    if (err_str[mid].code < statcode) {
		first = mid+1;
		n -= (half+1);
	    } else if (err_str[mid].code > statcode) {
		n = half;
	    } else {
		first = mid;
		break;
	    }
	}


	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
	    pj_str_t msg;

	    msg.ptr = (char*)err_str[first].msg;
	    msg.slen = pj_ansi_strlen(err_str[first].msg);

	    errstr.ptr = buf;
	    pj_strncpy_with_null(&errstr, &msg, bufsize);
	    return errstr;

	}
    }
#endif	/* PJ_HAS_ERROR_STRING */

    /* Error not found. */
    errstr.ptr = buf;
    errstr.slen = pj_ansi_snprintf(buf, bufsize,
				   "Unknown pjmedia-videodev error %d",
				   statcode);

    return errstr;
}
Beispiel #13
0
pjmedia_sdp_attr_find2(unsigned count, 
		       pjmedia_sdp_attr *const attr_array[],
		       const char *c_name,
		       const pj_str_t *c_fmt)
{
    pj_str_t name;

    name.ptr = (char*)c_name;
    name.slen = pj_ansi_strlen(c_name);

    return pjmedia_sdp_attr_find(count, attr_array, &name, c_fmt);
}
Beispiel #14
0
/*
 * Convert text to IPv4/IPv6 address.
 */
PJ_DEF(pj_status_t) pj_inet_pton(int af, const pj_str_t *src, void *dst)
{
    char tempaddr[PJ_INET6_ADDRSTRLEN];

    PJ_ASSERT_RETURN(af==PJ_AF_INET || af==PJ_AF_INET6, PJ_EINVAL);
    PJ_ASSERT_RETURN(src && src->slen && dst, PJ_EINVAL);

    /* Initialize output with PJ_IN_ADDR_NONE for IPv4 (to be 
     * compatible with pj_inet_aton()
     */
    if (af==PJ_AF_INET) {
	((pj_in_addr*)dst)->s_addr = PJ_INADDR_NONE;
    }

    /* Caution:
     *	this function might be called with cp->slen >= 46
     *  (i.e. when called with hostname to check if it's an IP addr).
     */
    if (src->slen >= PJ_INET6_ADDRSTRLEN) {
	return PJ_ENAMETOOLONG;
    }

    pj_memcpy(tempaddr, src->ptr, src->slen);
    tempaddr[src->slen] = '\0';


    wchar_t tempaddr16[PJ_INET6_ADDRSTRLEN];
    pj_ansi_to_unicode(tempaddr, pj_ansi_strlen(tempaddr),
		       tempaddr16, sizeof(tempaddr16));

    TBuf<PJ_INET6_ADDRSTRLEN> ip_addr((const TText*)tempaddr16);

    TInetAddr addr;
    addr.Init(KAfInet6);
    if (addr.Input(ip_addr) == KErrNone) {
	if (af==PJ_AF_INET) {
	    /* Success (Symbian IP address is in host byte order) */
	    pj_uint32_t ip = pj_htonl(addr.Address());
	    pj_memcpy(dst, &ip, 4);
	} else if (af==PJ_AF_INET6) {
	    const TIp6Addr & ip6 = addr.Ip6Address();
	    pj_memcpy(dst, ip6.u.iAddr8, 16);
	} else {
	    pj_assert(!"Unexpected!");
	    return PJ_EBUG;
	}
	return PJ_SUCCESS;
    } else {
	/* Error */
	return PJ_EINVAL;
    }
}
Beispiel #15
0
/* Send request */
static void send_request(const pjsip_method *method,
			 int cseq,
			 const pj_str_t *branch,
			 pj_bool_t with_offer)
{
    pjsip_tx_data *tdata;
    pj_str_t dummy_sdp_str = 
    {
	"v=0\r\n"
	"o=- 3360842071 3360842071 IN IP4 192.168.0.68\r\n"
	"s=pjmedia\r\n"
	"c=IN IP4 192.168.0.68\r\n"
	"t=0 0\r\n"
	"m=audio 4000 RTP/AVP 0 101\r\n"
	"a=rtcp:4001 IN IP4 192.168.0.68\r\n"
	"a=rtpmap:0 PCMU/8000\r\n"
	"a=sendrecv\r\n"
	"a=rtpmap:101 telephone-event/8000\r\n"
	"a=fmtp:101 0-15\r\n",
	0
    };
    pj_status_t status;

    status = pjsip_dlg_create_request(dlg, method, cseq, &tdata);
    pj_assert(status == PJ_SUCCESS);

    if (branch) {
	pjsip_via_hdr *via;

	via = (pjsip_via_hdr*) pjsip_msg_find_hdr(tdata->msg, PJSIP_H_VIA, NULL);
	pj_strdup(tdata->pool, &via->branch_param, branch);
    }

    if (with_offer) {
	pjsip_msg_body *body;
	pj_str_t mime_application = { "application", 11};
	pj_str_t mime_sdp = {"sdp", 3};


	dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr);
	body = pjsip_msg_body_create(tdata->pool, 
				     &mime_application, &mime_sdp, 
				     &dummy_sdp_str);
	tdata->msg->body = body;
    }

    status = pjsip_dlg_send_request(dlg, tdata, -1, NULL);
    pj_assert(status == PJ_SUCCESS);
}
Beispiel #16
0
static void ui_echo(char menuin[])
{
    if (pj_ansi_strnicmp(menuin, "echo", 4)==0) {
	pj_str_t tmp;

	tmp.ptr = menuin+5;
	tmp.slen = pj_ansi_strlen(menuin)-6;

	if (tmp.slen < 1) {
	    puts("Usage: echo [0|1]");
	    return;
	}
	cmd_echo = *tmp.ptr != '0' || tmp.slen!=1;
    }
}
static pj_bool_t mod_stateful_on_rx_request(pjsip_rx_data *rdata)
{
    const pj_str_t stateful_user = { "1", 1 };
    pjsip_uri *uri;
    pjsip_sip_uri *sip_uri;

    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;

    /* Check for matching user part */
    if (pj_strcmp(&sip_uri->user, &stateful_user)!=0)
	return PJ_FALSE;

    /*
     * Yes, this is for us.
     * Respond statefully with 200/OK.
     */
    switch (rdata->msg_info.msg->line.req.method.id) {
    case PJSIP_INVITE_METHOD:
	{
	    pjsip_msg_body *body;

	    if (dummy_sdp_str.slen == 0)
		dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr);

	    body = pjsip_msg_body_create(rdata->tp_info.pool, 
					 &mime_application, &mime_sdp, 
					 &dummy_sdp_str);
	    pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
				200, NULL, NULL, body, NULL);
	}
	break;
    case PJSIP_ACK_METHOD:
	return PJ_TRUE;
    default:
	pjsip_endpt_respond(app.sip_endpt, &mod_stateful_server, rdata,
			    200, NULL, NULL, NULL, NULL);
	break;
    }

    app.server.cur_state.stateful_cnt++;
    return PJ_TRUE;
}
Beispiel #18
0
/* Util to find child node with the specified substring */
static pj_xml_node *find_node(const pj_xml_node *parent, 
			      const char *part_name)
{
    const pj_xml_node *node = parent->node_head.next, 
		      *head = (pj_xml_node*) &parent->node_head;
    pj_ssize_t part_len = pj_ansi_strlen(part_name);

    while (node != head) {
	if (substring_match(node, part_name, part_len))
	    return (pj_xml_node*) node;

	node = node->next;
    }

    return NULL;
}
Beispiel #19
0
/* Comparison function to find node name substring */
static pj_bool_t substring_match(const pj_xml_node *node, 
				 const char *part_name,
				 pj_ssize_t part_len)
{
    pj_str_t end_name;

    if (part_len < 1)
	part_len = pj_ansi_strlen(part_name);

    if (node->name.slen < part_len)
	return PJ_FALSE;

    end_name.ptr = node->name.ptr + (node->name.slen - part_len);
    end_name.slen = part_len;

    return pj_strnicmp2(&end_name, part_name, part_len)==0;
}
/*
 * Init media stack.
 */
static pj_status_t init_media()
{
    unsigned	i;
    pj_uint16_t	rtp_port;
    pj_status_t	status;


    /* Initialize media endpoint so that at least error subsystem is properly
     * initialized.
     */
    status = pjmedia_endpt_create(&app.cp.factory, 
				  pjsip_endpt_get_ioqueue(app.sip_endpt), 0, 
				  &app.med_endpt);
    PJ_ASSERT_RETURN(status == PJ_SUCCESS, status);


    /* Must register all codecs to be supported */
    pjmedia_codec_register_audio_codecs(app.med_endpt, NULL);

    /* Init dummy socket addresses */
    app.skinfo_cnt = 0;
    for (i=0, rtp_port=4000; i<PJ_ARRAY_SIZE(app.skinfo); ++i, rtp_port+=2) {
	pjmedia_sock_info *skinfo;

	skinfo = &app.skinfo[i];
	
	pj_sockaddr_in_init(&skinfo->rtp_addr_name.ipv4, &app.local_addr,
			    (pj_uint16_t)rtp_port);
	pj_sockaddr_in_init(&skinfo->rtp_addr_name.ipv4, &app.local_addr,
			    (pj_uint16_t)(rtp_port+1));
	app.skinfo_cnt++;
    }

    /* Generate dummy SDP */
    dummy_sdp_str.slen = pj_ansi_strlen(dummy_sdp_str.ptr);
    status = pjmedia_sdp_parse(app.pool, dummy_sdp_str.ptr, dummy_sdp_str.slen, 
			       &app.dummy_sdp);
    if (status != PJ_SUCCESS) {
	app_perror(THIS_FILE, "Error parsing dummy SDP", status);
	return status;
    }


    /* Done */
    return PJ_SUCCESS;
}
Beispiel #21
0
/* API: set capability */
static pj_status_t alsa_stream_set_cap(pjmedia_aud_stream *strm,
				       pjmedia_aud_dev_cap cap,
				       const void *value)
{
    struct alsa_factory *af = ((struct alsa_stream*)strm)->af;

    if (cap==PJMEDIA_AUD_DEV_CAP_OUTPUT_VOLUME_SETTING && 
	pj_ansi_strlen(af->pb_mixer_name)) 
    {
	pj_ssize_t min, max;
	snd_mixer_t *handle;
	snd_mixer_selem_id_t *sid;
	snd_mixer_elem_t* elem;
	unsigned vol = *(unsigned*)value;

	if (snd_mixer_open(&handle, 0) < 0)
	    return PJMEDIA_EAUD_SYSERR;

	if (snd_mixer_attach(handle, "default") < 0)
	    return PJMEDIA_EAUD_SYSERR;

	if (snd_mixer_selem_register(handle, NULL, NULL) < 0)
	    return PJMEDIA_EAUD_SYSERR;

	if (snd_mixer_load(handle) < 0)
	    return PJMEDIA_EAUD_SYSERR;

	snd_mixer_selem_id_alloca(&sid);
	snd_mixer_selem_id_set_index(sid, 0);
	snd_mixer_selem_id_set_name(sid, af->pb_mixer_name);
	elem = snd_mixer_find_selem(handle, sid);
	if (!elem)
	    return PJMEDIA_EAUD_SYSERR;

	snd_mixer_selem_get_playback_volume_range(elem, &min, &max);
	if (snd_mixer_selem_set_playback_volume_all(elem, vol * max / 100) < 0)
	    return PJMEDIA_EAUD_SYSERR;

	snd_mixer_close(handle);
	return PJ_SUCCESS;
    }

    return PJMEDIA_EAUD_INVCAP;
}
Beispiel #22
0
static void ui_sleep(char menuin[])
{
    if (pj_ansi_strnicmp(menuin, "sleep", 5)==0) {
	pj_str_t tmp;
	int delay;

	tmp.ptr = menuin+6;
	tmp.slen = pj_ansi_strlen(menuin)-7;

	if (tmp.slen < 1) {
	    puts("Usage: sleep MSEC");
	    return;
	}

	delay = pj_strtoul(&tmp);
	if (delay < 0) delay = 0;
	pj_thread_sleep(delay);
    }
}
Beispiel #23
0
/*
 * This function converts the Internet host address cp from the standard
 * numbers-and-dots notation into binary data and stores it in the structure
 * that inp points to. 
 */
PJ_DEF(int) pj_inet_aton(const pj_str_t *cp, struct pj_in_addr *inp)
{
    enum { MAXIPLEN = PJ_INET_ADDRSTRLEN };

    /* Initialize output with PJ_INADDR_NONE.
     * Some apps relies on this instead of the return value
     * (and anyway the return value is quite confusing!)
     */
    inp->s_addr = PJ_INADDR_NONE;

    /* Caution:
     *	this function might be called with cp->slen >= 16
     *  (i.e. when called with hostname to check if it's an IP addr).
     */
    PJ_ASSERT_RETURN(cp && cp->slen && inp, 0);
    if (cp->slen >= 16) {
	return 0;
    }

    char tempaddr8[MAXIPLEN];
    pj_memcpy(tempaddr8, cp->ptr, cp->slen);
    tempaddr8[cp->slen] = '\0';

    wchar_t tempaddr16[MAXIPLEN];
    pj_ansi_to_unicode(tempaddr8, pj_ansi_strlen(tempaddr8),
		       tempaddr16, sizeof(tempaddr16));

    TBuf<MAXIPLEN> ip_addr((const TText*)tempaddr16);

    TInetAddr addr;
    addr.Init(KAfInet);
    if (addr.Input(ip_addr) == KErrNone) {
	/* Success (Symbian IP address is in host byte order) */
	inp->s_addr = pj_htonl(addr.Address());
	return 1;
    } else {
	/* Error */
	return 0;
    }
}
/*
 * Verify that valid SIP url is given.
 */
static pj_status_t verify_sip_url(const char *c_url)
{
    pjsip_uri *p;
    pj_pool_t *pool;
    char *url;
    int len = (c_url ? pj_ansi_strlen(c_url) : 0);

    if (!len) return -1;

    pool = pj_pool_create(&app.cp.factory, "check%p", 1024, 0, NULL);
    if (!pool) return PJ_ENOMEM;

    url = pj_pool_alloc(pool, len+1);
    pj_ansi_strcpy(url, c_url);
    url[len] = '\0';

    p = pjsip_parse_uri(pool, url, len, 0);
    if (!p || pj_stricmp2(pjsip_uri_get_scheme(p), "sip") != 0)
	p = NULL;

    pj_pool_release(pool);
    return p ? 0 : -1;
}
Beispiel #25
0
/*
 * pjmedia_strerror()
 */
PJ_DEF(pj_str_t) pjmedia_strerror( pj_status_t statcode, 
				   char *buf, pj_size_t bufsize )
{
    pj_str_t errstr;

#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)

    /* See if the error comes from PortAudio. */
#if defined(PJMEDIA_SOUND_IMPLEMENTATION) && \
    PJMEDIA_SOUND_IMPLEMENTATION == PJMEDIA_SOUND_PORTAUDIO_SOUND
    if (statcode >= PJMEDIA_PORTAUDIO_ERRNO_START &&
	statcode <= PJMEDIA_PORTAUDIO_ERRNO_END)
    {

	//int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0);
	int pa_err = PJMEDIA_PORTAUDIO_ERRNO_START - statcode;
	pj_str_t msg;
	
	msg.ptr = (char*)Pa_GetErrorText(pa_err);
	msg.slen = pj_ansi_strlen(msg.ptr);

	errstr.ptr = buf;
	pj_strncpy_with_null(&errstr, &msg, bufsize);
	return errstr;

    } else 
#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */

#if defined(PJMEDIA_HAS_SRTP) && (PJMEDIA_HAS_SRTP != 0)
    /* LIBSRTP error */
    if (statcode >= PJMEDIA_LIBSRTP_ERRNO_START &&
	statcode <  PJMEDIA_LIBSRTP_ERRNO_END)
    {
	int err = statcode - PJMEDIA_LIBSRTP_ERRNO_START;
	pj_str_t msg;
	
	msg = pj_str((char*)get_libsrtp_errstr(err));

	errstr.ptr = buf;
	pj_strncpy_with_null(&errstr, &msg, bufsize);
	return errstr;
    
    } else
#endif
    
    /* PJMEDIA error */
    if (statcode >= PJMEDIA_ERRNO_START && 
	       statcode < PJMEDIA_ERRNO_END)
    {
	/* Find the error in the table.
	 * Use binary search!
	 */
	int first = 0;
	int n = PJ_ARRAY_SIZE(err_str);

	while (n > 0) {
	    int half = n/2;
	    int mid = first + half;

	    if (err_str[mid].code < statcode) {
		first = mid+1;
		n -= (half+1);
	    } else if (err_str[mid].code > statcode) {
		n = half;
	    } else {
		first = mid;
		break;
	    }
	}


	if (PJ_ARRAY_SIZE(err_str) && err_str[first].code == statcode) {
	    pj_str_t msg;
	    
	    msg.ptr = (char*)err_str[first].msg;
	    msg.slen = pj_ansi_strlen(err_str[first].msg);

	    errstr.ptr = buf;
	    pj_strncpy_with_null(&errstr, &msg, bufsize);
	    return errstr;

	} 
    } 
#endif	/* PJ_HAS_ERROR_STRING */

    /* Error not found. */
    errstr.ptr = buf;
    errstr.slen = pj_ansi_snprintf(buf, bufsize, 
				   "Unknown pjmedia error %d",
				   statcode);
    if (errstr.slen < 1 || errstr.slen >= (pj_ssize_t)bufsize)
	errstr.slen = bufsize - 1;
    return errstr;
}
Beispiel #26
0
/* Generate transport's published address */
static pj_status_t get_published_name(pj_sock_t sock,
				      char hostbuf[],
				      int hostbufsz,
				      pjsip_host_port *bound_name)
{
    pj_sockaddr tmp_addr;
    int addr_len;
    pj_status_t status;

    addr_len = sizeof(tmp_addr);
    status = pj_sock_getsockname(sock, &tmp_addr, &addr_len);
    if (status != PJ_SUCCESS)
	return status;

    bound_name->host.ptr = hostbuf;
    if (tmp_addr.addr.sa_family == pj_AF_INET()) {
	bound_name->port = pj_ntohs(tmp_addr.ipv4.sin_port);

	/* If bound address specifies "0.0.0.0", get the IP address
	 * of local hostname.
	 */
	if (tmp_addr.ipv4.sin_addr.s_addr == PJ_INADDR_ANY) {
	    pj_sockaddr hostip;

	    status = pj_gethostip(pj_AF_INET(), &hostip);
	    if (status != PJ_SUCCESS)
		return status;

	    pj_strcpy2(&bound_name->host, pj_inet_ntoa(hostip.ipv4.sin_addr));
	} else {
	    /* Otherwise use bound address. */
	    pj_strcpy2(&bound_name->host, 
		       pj_inet_ntoa(tmp_addr.ipv4.sin_addr));
	    status = PJ_SUCCESS;
	}

    } else {
	/* If bound address specifies "INADDR_ANY" (IPv6), get the
         * IP address of local hostname
         */
	pj_uint32_t loop6[4] = { 0, 0, 0, 0};

	bound_name->port = pj_ntohs(tmp_addr.ipv6.sin6_port);

	if (pj_memcmp(&tmp_addr.ipv6.sin6_addr, loop6, sizeof(loop6))==0) {
	    status = pj_gethostip(tmp_addr.addr.sa_family, &tmp_addr);
	    if (status != PJ_SUCCESS)
		return status;
	}

	status = pj_inet_ntop(tmp_addr.addr.sa_family, 
			      pj_sockaddr_get_addr(&tmp_addr),
			      hostbuf, hostbufsz);
	if (status == PJ_SUCCESS) {
	    bound_name->host.slen = pj_ansi_strlen(hostbuf);
	}
    }


    return status;
}
Beispiel #27
0
static int https_client_test(unsigned ms_timeout)
{
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_timer_heap_t *timer = NULL;
    pj_ssl_sock_t *ssock = NULL;
    pj_ssl_sock_param param;
    pj_status_t status;
    struct test_state state = {0};
    pj_sockaddr local_addr, rem_addr;
    pj_str_t tmp_st;

    pool = pj_pool_create(mem, "https_get", 256, 256, NULL);

    status = pj_ioqueue_create(pool, 4, &ioqueue);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    status = pj_timer_heap_create(pool, 4, &timer);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    state.pool = pool;
    state.send_str = HTTP_REQ;
    state.send_str_len = pj_ansi_strlen(state.send_str);
    state.is_verbose = PJ_TRUE;

    pj_ssl_sock_param_default(&param);
    param.cb.on_connect_complete = &ssl_on_connect_complete;
    param.cb.on_data_read = &ssl_on_data_read;
    param.cb.on_data_sent = &ssl_on_data_sent;
    param.ioqueue = ioqueue;
    param.user_data = &state;
    param.server_name = pj_str((char*)HTTP_SERVER_ADDR);
    param.timer_heap = timer;
    param.timeout.sec = 0;
    param.timeout.msec = ms_timeout;
    param.proto = PJ_SSL_SOCK_PROTO_SSL23;
    pj_time_val_normalize(&param.timeout);

    status = pj_ssl_sock_create(pool, &param, &ssock);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    pj_sockaddr_init(PJ_AF_INET, &local_addr, pj_strset2(&tmp_st, "0.0.0.0"), 0);
    pj_sockaddr_init(PJ_AF_INET, &rem_addr, pj_strset2(&tmp_st, HTTP_SERVER_ADDR), HTTP_SERVER_PORT);
    status = pj_ssl_sock_start_connect(ssock, pool, &local_addr, &rem_addr, sizeof(rem_addr));
    if (status == PJ_SUCCESS) {
	ssl_on_connect_complete(ssock, PJ_SUCCESS);
    } else if (status == PJ_EPENDING) {
	status = PJ_SUCCESS;
    } else {
	goto on_return;
    }

    /* Wait until everything has been sent/received */
    while (state.err == PJ_SUCCESS && !state.done) {
#ifdef PJ_SYMBIAN
	pj_symbianos_poll(-1, 1000);
#else
	pj_time_val delay = {0, 100};
	pj_ioqueue_poll(ioqueue, &delay);
	pj_timer_heap_poll(timer, &delay);
#endif
    }

    if (state.err) {
	status = state.err;
	goto on_return;
    }

    PJ_LOG(3, ("", "...Done!"));
    PJ_LOG(3, ("", ".....Sent/recv: %d/%d bytes", state.sent, state.recv));

on_return:
    if (ssock && !state.err && !state.done) 
	pj_ssl_sock_close(ssock);
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (timer)
	pj_timer_heap_destroy(timer);
    if (pool)
	pj_pool_release(pool);

    return status;
}
Beispiel #28
0
static int server_thread(void *p)
{
    struct server_t *srv = (struct server_t*)p;
    char *pkt = (char*)pj_pool_alloc(pool, srv->buf_size);
    pj_sock_t newsock = PJ_INVALID_SOCKET;

    while (!thread_quit) {
	pj_ssize_t pkt_len;
	int rc;
        pj_fd_set_t rset;
	pj_time_val timeout = {0, 500};

	while (!thread_quit) {
	    PJ_FD_ZERO(&rset);
	    PJ_FD_SET(srv->sock, &rset);
	    rc = pj_sock_select((int)srv->sock+1, &rset, NULL, NULL, &timeout);
	    if (rc != 1) {
		continue;
	    }

	    rc = pj_sock_accept(srv->sock, &newsock, NULL, NULL);
	    if (rc == PJ_SUCCESS) {
		break;
	    }
	}

	if (thread_quit)
	    break;

	while (!thread_quit) {
            PJ_FD_ZERO(&rset);
            PJ_FD_SET(newsock, &rset);
            rc = pj_sock_select((int)newsock+1, &rset, NULL, NULL, &timeout);
            if (rc != 1) {
        	PJ_LOG(3,("http test", "client timeout"));
                continue;
            }

            pkt_len = srv->buf_size;
            rc = pj_sock_recv(newsock, pkt, &pkt_len, 0);
            if (rc == PJ_SUCCESS) {
                break;
            }
        }

	if (thread_quit)
	    break;

	/* Simulate network RTT */
	pj_thread_sleep(50);

	if (srv->action == ACTION_IGNORE) {
	    continue;
	} else if (srv->action == ACTION_REPLY) {
            pj_size_t send_size = 0;
	    unsigned ctr = 0;
            pj_ansi_sprintf(pkt, "HTTP/1.0 200 OK\r\n");
            if (srv->send_content_length) {
                pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt), 
                                "Content-Length: %d\r\n",
                                srv->data_size);
            }
            pj_ansi_sprintf(pkt + pj_ansi_strlen(pkt), "\r\n");
            pkt_len = pj_ansi_strlen(pkt);
            rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
            if (rc != PJ_SUCCESS) {
        	pj_sock_close(newsock);
        	continue;
            }
            while (send_size < srv->data_size) {
                pkt_len = srv->data_size - send_size;
                if (pkt_len > (signed)srv->buf_size)
                    pkt_len = srv->buf_size;
                send_size += pkt_len;
                pj_create_random_string(pkt, pkt_len);
                pj_ansi_sprintf(pkt, "\nPacket: %d", ++ctr);
                pkt[pj_ansi_strlen(pkt)] = '\n';
		rc = pj_sock_send(newsock, pkt, &pkt_len, 0);
		if (rc != PJ_SUCCESS)
		    break;
            }
            pj_sock_close(newsock);
	}
    }

    return 0;
}
Beispiel #29
0
/*
 * pjmedia_audiodev_strerror()
 */
PJ_DEF(pj_str_t) pjmedia_audiodev_strerror(pj_status_t statcode, 
					   char *buf, pj_size_t bufsize )
{
    pj_str_t errstr;

#if defined(PJ_HAS_ERROR_STRING) && (PJ_HAS_ERROR_STRING != 0)


    /* See if the error comes from Core Audio. */
#if PJMEDIA_AUDIO_DEV_HAS_COREAUDIO
    if (statcode >= PJMEDIA_AUDIODEV_COREAUDIO_ERRNO_START &&
	statcode <= PJMEDIA_AUDIODEV_COREAUDIO_ERRNO_END)
    {
	int ca_err = PJMEDIA_AUDIODEV_COREAUDIO_ERRNO_START - statcode;

	PJ_UNUSED_ARG(ca_err);
	// TODO: create more helpful error messages
	errstr.ptr = buf;
	pj_strcpy2(&errstr, "Core audio error");
	return errstr;
    } else
#endif

    /* See if the error comes from PortAudio. */
#if PJMEDIA_AUDIO_DEV_HAS_PORTAUDIO
    if (statcode >= PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START &&
	statcode <= PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_END)
    {

	//int pa_err = statcode - PJMEDIA_ERRNO_FROM_PORTAUDIO(0);
	int pa_err = PJMEDIA_AUDIODEV_PORTAUDIO_ERRNO_START - statcode;
	pj_str_t msg;
	
	msg.ptr = (char*)Pa_GetErrorText(pa_err);
	msg.slen = pj_ansi_strlen(msg.ptr);

	errstr.ptr = buf;
	pj_strncpy_with_null(&errstr, &msg, bufsize);
	return errstr;

    } else 
#endif	/* PJMEDIA_SOUND_IMPLEMENTATION */

    /* See if the error comes from WMME */
#if PJMEDIA_AUDIO_DEV_HAS_WMME
    if ((statcode >= PJMEDIA_AUDIODEV_WMME_IN_ERROR_START &&
	 statcode < PJMEDIA_AUDIODEV_WMME_IN_ERROR_END) ||
	(statcode >= PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START &&
	 statcode < PJMEDIA_AUDIODEV_WMME_OUT_ERROR_END))
    {
	MMRESULT native_err, mr;
	MMRESULT (WINAPI *waveGetErrText)(UINT mmrError, LPTSTR pszText, UINT cchText);
	PJ_DECL_UNICODE_TEMP_BUF(wbuf, 80)

	if (statcode >= PJMEDIA_AUDIODEV_WMME_IN_ERROR_START &&
	    statcode <= PJMEDIA_AUDIODEV_WMME_IN_ERROR_END)
	{
	    native_err = statcode - PJMEDIA_AUDIODEV_WMME_IN_ERROR_START;
	    waveGetErrText = &waveInGetErrorText;
	} else {
	    native_err = statcode - PJMEDIA_AUDIODEV_WMME_OUT_ERROR_START;
	    waveGetErrText = &waveOutGetErrorText;
	}

#if PJ_NATIVE_STRING_IS_UNICODE
	mr = (*waveGetErrText)(native_err, wbuf, PJ_ARRAY_SIZE(wbuf));
	if (mr == MMSYSERR_NOERROR) {
	    int len = wcslen(wbuf);
	    pj_unicode_to_ansi(wbuf, len, buf, bufsize);
	}
#else
	mr = (*waveGetErrText)(native_err, buf, (UINT)bufsize);
#endif

	if (mr==MMSYSERR_NOERROR) {
	    errstr.ptr = buf;
	    errstr.slen = pj_ansi_strlen(buf);
	    return errstr;
	} else {
	    pj_ansi_snprintf(buf, bufsize, "MMSYSTEM native error %d", 
			     native_err);
	    return pj_str(buf);
	}

    } else
Beispiel #30
0
static int offer_answer_test(pj_pool_t *pool, pjmedia_sdp_neg **p_neg,
			     struct offer_answer *oa)
{
    pjmedia_sdp_session *sdp1;
    pjmedia_sdp_neg *neg;
    pj_status_t status;

    status = pjmedia_sdp_parse(pool, oa->sdp1, pj_ansi_strlen(oa->sdp1),
				&sdp1);
    if (status != PJ_SUCCESS) {
	app_perror(status, "   error: unexpected parse status for sdp1");
	return -10;
    }

    status = pjmedia_sdp_validate(sdp1);
    if (status != PJ_SUCCESS) {
	app_perror(status, "   error: sdp1 validation failed");
	return -15;
    }

    neg = *p_neg;

    if (oa->type == LOCAL_OFFER) {
	
	/* 
	 * Local creates offer first. 
	 */
	pjmedia_sdp_session *sdp2, *sdp3;
	const pjmedia_sdp_session *active;

	if (neg == NULL) {
	    /* Create negotiator with local offer. */
	    status = pjmedia_sdp_neg_create_w_local_offer(pool, sdp1, &neg);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: pjmedia_sdp_neg_create_w_local_offer");
		return -20;
	    }
	    *p_neg = neg;

	} else {
	    /* Modify local offer */
	    status = pjmedia_sdp_neg_modify_local_offer(pool, neg, sdp1);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: pjmedia_sdp_neg_modify_local_offer");
		return -30;
	    }
	}

	/* Parse and validate remote answer */
	status = pjmedia_sdp_parse(pool, oa->sdp2, pj_ansi_strlen(oa->sdp2),
				   &sdp2);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: parsing sdp2");
	    return -40;
	}

	status = pjmedia_sdp_validate(sdp2);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: sdp2 validation failed");
	    return -50;
	}

	/* Give the answer to negotiator. */
	status = pjmedia_sdp_neg_set_remote_answer(pool, neg, sdp2);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: pjmedia_sdp_neg_rx_remote_answer");
	    return -60;
	}

	/* Negotiate remote answer with local answer */
	status = pjmedia_sdp_neg_negotiate(pool, neg, 0);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: pjmedia_sdp_neg_negotiate");
	    return -70;
	}

	/* Get the local active media. */
	status = pjmedia_sdp_neg_get_active_local(neg, &active);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: pjmedia_sdp_neg_get_local");
	    return -80;
	}

	/* Parse and validate the correct active media. */
	status = pjmedia_sdp_parse(pool, oa->sdp3, pj_ansi_strlen(oa->sdp3),
				   &sdp3);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: parsing sdp3");
	    return -90;
	}

	status = pjmedia_sdp_validate(sdp3);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: sdp3 validation failed");
	    return -100;
	}

	/* Compare active with sdp3 */
	status = pjmedia_sdp_session_cmp(active, sdp3, 0);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: active local comparison mismatch");
	    compare_sdp_string("Logical cmp after negotiatin remote answer",
			       "Active local sdp from negotiator", active,
			       "The correct active local sdp", sdp3,
			       status);
	    return -110;
	}

	/* Compare the string representation oa both sdps */
	status = compare_sdp_string("String cmp after negotiatin remote answer",
				    "Active local sdp from negotiator", active,
				    "The correct active local sdp", sdp3,
				    PJ_SUCCESS);
	if (status != 0)
	    return -120;

    } else {
	/* 
	 * Remote creates offer first. 
	 */

	pjmedia_sdp_session *sdp2 = NULL, *sdp3;
	const pjmedia_sdp_session *answer;

	if (oa->sdp2) {
	    /* Parse and validate initial local capability */
	    status = pjmedia_sdp_parse(pool, oa->sdp2, pj_ansi_strlen(oa->sdp2),
				       &sdp2);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: parsing sdp2");
		return -200;
	    }

	    status = pjmedia_sdp_validate(sdp2);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: sdp2 validation failed");
		return -210;
	    }
	} else if (neg) {
	    status = pjmedia_sdp_neg_get_active_local(neg, &sdp2);
	    if (status != PJ_SUCCESS) {
		app_perror(status, 
			   "   error: pjmedia_sdp_neg_get_active_local");
		return -215;
	    }
	}

	if (neg == NULL) {
	    /* Create negotiator with remote offer. */
	    status = pjmedia_sdp_neg_create_w_remote_offer(pool, sdp2, sdp1, &neg);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: pjmedia_sdp_neg_create_w_remote_offer");
		return -220;
	    }
	    *p_neg = neg;

	} else {
	    /* Received subsequent offer from remote. */
	    status = pjmedia_sdp_neg_set_remote_offer(pool, neg, sdp1);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: pjmedia_sdp_neg_rx_remote_offer");
		return -230;
	    }

	    status = pjmedia_sdp_neg_set_local_answer(pool, neg, sdp2);
	    if (status != PJ_SUCCESS) {
		app_perror(status, "   error: pjmedia_sdp_neg_set_local_answer");
		return -235;
	    }
	}

	/* Negotiate. */
	status = pjmedia_sdp_neg_negotiate(pool, neg, 0);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: pjmedia_sdp_neg_negotiate");
	    return -240;
	}
	
	/* Get our answer. */
	status = pjmedia_sdp_neg_get_active_local(neg, &answer);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: pjmedia_sdp_neg_get_local");
	    return -250;
	}

	/* Parse the correct answer. */
	status = pjmedia_sdp_parse(pool, oa->sdp3, pj_ansi_strlen(oa->sdp3),
				   &sdp3);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: parsing sdp3");
	    return -260;
	}

	/* Validate the correct answer. */
	status = pjmedia_sdp_validate(sdp3);
	if (status != PJ_SUCCESS) {
	    app_perror(status, "   error: sdp3 validation failed");
	    return -270;
	}

	/* Compare answer from negotiator and the correct answer */
	status = pjmedia_sdp_session_cmp(sdp3, answer, 0);
	if (status != PJ_SUCCESS) {
	    compare_sdp_string("Logical cmp after negotiating remote offer",
			       "Local answer from negotiator", answer,
			       "The correct local answer", sdp3,
			       status);

	    return -280;
	}

	/* Compare the string representation oa both answers */
	status = compare_sdp_string("String cmp after negotiating remote offer",
				    "Local answer from negotiator", answer,
				    "The correct local answer", sdp3,
				    PJ_SUCCESS);
	if (status != 0)
	    return -290;

    }

    return 0;
}