コード例 #1
0
ファイル: sipecho.c プロジェクト: xhook/asterisk-v11
static pj_status_t init_stack()
{
    pj_sockaddr addr;
    pjsip_inv_callback inv_cb;
    pj_status_t status;

    pj_log_set_level(5);

    status = pj_init();
    CHECK_STATUS();

    pj_log_set_level(3);

    status = pjlib_util_init();
    CHECK_STATUS();

    pj_caching_pool_init(&app.cp, NULL, 0);
    app.pool = pj_pool_create( &app.cp.factory, "sipecho", 512, 512, 0);

    status = pjsip_endpt_create(&app.cp.factory, NULL, &app.sip_endpt);
    CHECK_STATUS();

    pj_log_set_level(4);
    pj_sockaddr_init(AF, &addr, NULL, (pj_uint16_t)SIP_PORT);
    if (AF == pj_AF_INET()) {
	status = pjsip_udp_transport_start( app.sip_endpt, &addr.ipv4, NULL,
					    1, NULL);
    } else if (AF == pj_AF_INET6()) {
	status = pjsip_udp_transport_start6(app.sip_endpt, &addr.ipv6, NULL,
					    1, NULL);
    } else {
	status = PJ_EAFNOTSUP;
    }

    pj_log_set_level(3);
    CHECK_STATUS();

    status = pjsip_tsx_layer_init_module(app.sip_endpt) ||
	     pjsip_ua_init_module( app.sip_endpt, NULL );
    CHECK_STATUS();

    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;
    inv_cb.on_rx_offer = &call_on_rx_offer;

    status = pjsip_inv_usage_init(app.sip_endpt, &inv_cb) ||
	     pjsip_100rel_init_module(app.sip_endpt) ||
	     pjsip_endpt_register_module( app.sip_endpt, &mod_sipecho) ||
	     pjsip_endpt_register_module( app.sip_endpt, &msg_logger) ||
	     //pjmedia_endpt_create(&app.cp.factory,
		//		  pjsip_endpt_get_ioqueue(app.sip_endpt),
		//		  0, &app.med_endpt) ||
             pj_thread_create(app.pool, "sipecho", &worker_proc, NULL, 0, 0,
                              &app.worker_thread);
    CHECK_STATUS();

    return PJ_SUCCESS;
}
コード例 #2
0
/* Get the default IP interface */
PJ_DEF(pj_status_t) pj_getdefaultipinterface(int af, pj_sockaddr *addr)
{
    pj_sock_t fd;
    pj_str_t cp;
    pj_sockaddr a;
    int len;
    pj_uint8_t zero[64];
    pj_status_t status;

    addr->addr.sa_family = (pj_uint16_t)af;

    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
    if (status != PJ_SUCCESS) {
	return status;
	}
	PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_socket."));

    if (af == PJ_AF_INET) {
	cp = pj_str("1.1.1.1");
    } else {
	cp = pj_str("1::1");
    }
    status = pj_sockaddr_init(af, &a, &cp, 53);
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
	}
	PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sockaddr_init."));

    status = pj_sock_connect(fd, &a, pj_sockaddr_get_len(&a));
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
	}
	PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_connect."));

    len = sizeof(a);
    status = pj_sock_getsockname(fd, &a, &len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
	}
	PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() pj_sock_getsockname."));

    pj_sock_close(fd);

    /* Check that the address returned is not zero */
    pj_bzero(zero, sizeof(zero));
    if (pj_memcmp(pj_sockaddr_get_addr(&a), zero,
		  pj_sockaddr_get_addr_len(&a))==0)
	{
		PJ_LOG(4, ("sock_common.c", "pj_getdefaultipinterface() interface not found."));
		return PJ_ENOTFOUND;
    }

    pj_sockaddr_copy_addr(addr, &a);

    /* Success */
    return PJ_SUCCESS;
}
コード例 #3
0
ファイル: sip_transport_udp.c プロジェクト: avble/natClientEx
/*
 * Initialize pjsip_udp_transport_cfg structure with default values.
 */
PJ_DEF(void) pjsip_udp_transport_cfg_default(pjsip_udp_transport_cfg *cfg,
					     int af)
{
    pj_bzero(cfg, sizeof(*cfg));
    cfg->af = af;
    pj_sockaddr_init(cfg->af, &cfg->bind_addr, NULL, 0);
    cfg->async_cnt = 1;
}
コード例 #4
0
ファイル: sip_resolve.c プロジェクト: G0retZ/pjproject
/* 
 * This callback is called when target is resolved with DNS AAAA query.
 */
static void dns_aaaa_callback(void *user_data,
			      pj_status_t status,
			      pj_dns_parsed_packet *pkt)
{
    struct query *query = (struct query*) user_data;
    pjsip_server_addresses *srv = &query->server;

    /* Reset outstanding job */
    query->object6 = NULL;

    if (status == PJ_SUCCESS) {
	pj_dns_addr_record rec;
	unsigned i;

	/* Parse the response */
	rec.addr_count = 0;
	status = pj_dns_parse_addr_response(pkt, &rec);

	/* Build server addresses and call callback */
	for (i = 0; i < rec.addr_count &&
		    srv->count < PJSIP_MAX_RESOLVED_ADDRESSES; ++i)
	{
	    /* Should not happen, just in case */
	    if (rec.addr[i].af != pj_AF_INET6())
		continue;

	    srv->entry[srv->count].type = query->naptr[0].type |
					  PJSIP_TRANSPORT_IPV6;
	    srv->entry[srv->count].priority = 0;
	    srv->entry[srv->count].weight = 0;
	    srv->entry[srv->count].addr_len = sizeof(pj_sockaddr_in6);
	    pj_sockaddr_init(pj_AF_INET6(), &srv->entry[srv->count].addr,
			     0, (pj_uint16_t)query->req.def_port);
	    srv->entry[srv->count].addr.ipv6.sin6_addr = rec.addr[i].ip.v6;

	    ++srv->count;
	}
    }
    
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];

	/* Log error */
	pj_strerror(status, errmsg, sizeof(errmsg));
	PJ_LOG(4,(query->objname, "DNS AAAA record resolution failed: %s", 
		  errmsg));

	query->last_error = status;
    }

    /* Call the callback if all DNS queries have been completed */
    if (query->object == NULL && query->object6 == NULL) {
	if (srv->count > 0)
	    (*query->cb)(PJ_SUCCESS, query->token, &query->server);
	else
	    (*query->cb)(query->last_error, query->token, NULL);
    }
}
コード例 #5
0
/*
 * Initialize pjsip_tcp_transport_cfg structure with default values.
 */
PJ_DEF(void) pjsip_tcp_transport_cfg_default(pjsip_tcp_transport_cfg *cfg,
					     int af)
{
    pj_bzero(cfg, sizeof(*cfg));
    cfg->af = af;
    pj_sockaddr_init(cfg->af, &cfg->bind_addr, NULL, 0);
    cfg->async_cnt = 1;
    cfg->reuse_addr = PJSIP_TCP_TRANSPORT_REUSEADDR;
}
コード例 #6
0
ファイル: sip_resolve.c プロジェクト: G0retZ/pjproject
/* Callback to be called by DNS SRV resolution */
static void srv_resolver_cb(void *user_data,
			    pj_status_t status,
			    const pj_dns_srv_record *rec)
{
    struct query *query = (struct query*) user_data;
    pjsip_server_addresses srv;
    unsigned i;

    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];

	/* Log error */
	pj_strerror(status, errmsg, sizeof(errmsg));
	PJ_LOG(4,(query->objname, "DNS A/AAAA record resolution failed: %s",
		  errmsg));

	/* Call the callback */
	(*query->cb)(status, query->token, NULL);
	return;
    }

    /* Build server addresses and call callback */
    srv.count = 0;
    for (i=0; i<rec->count; ++i) {
	const pj_dns_addr_record *s = &rec->entry[i].server;
	unsigned j;

	for (j = 0; j < s->addr_count &&
		    srv.count < PJSIP_MAX_RESOLVED_ADDRESSES; ++j)
	{
	    srv.entry[srv.count].type = query->naptr[0].type;
	    srv.entry[srv.count].priority = rec->entry[i].priority;
	    srv.entry[srv.count].weight = rec->entry[i].weight;
	    pj_sockaddr_init(s->addr[j].af,
			     &srv.entry[srv.count].addr,
			     0, (pj_uint16_t)rec->entry[i].port);
	    if (s->addr[j].af == pj_AF_INET6())
		srv.entry[srv.count].addr.ipv6.sin6_addr = s->addr[j].ip.v6;
	    else
		srv.entry[srv.count].addr.ipv4.sin_addr = s->addr[j].ip.v4;
	    srv.entry[srv.count].addr_len =
			    pj_sockaddr_get_len(&srv.entry[srv.count].addr);

	    /* Update transport type if this is IPv6 */
	    if (s->addr[j].af == pj_AF_INET6())
		srv.entry[srv.count].type |= PJSIP_TRANSPORT_IPV6;

	    ++srv.count;
	}
    }

    /* Call the callback */
    (*query->cb)(PJ_SUCCESS, query->token, &srv);
}
コード例 #7
0
ファイル: activesock.c プロジェクト: 0x0B501E7E/pjproject
PJ_DEF(pj_status_t) pj_activesock_create_udp( pj_pool_t *pool,
					      const pj_sockaddr *addr,
					      const pj_activesock_cfg *opt,
					      pj_ioqueue_t *ioqueue,
					      const pj_activesock_cb *cb,
					      void *user_data,
					      pj_activesock_t **p_asock,
					      pj_sockaddr *bound_addr)
{
    pj_sock_t sock_fd;
    pj_sockaddr default_addr;
    pj_status_t status;

    if (addr == NULL) {
	pj_sockaddr_init(pj_AF_INET(), &default_addr, NULL, 0);
	addr = &default_addr;
    }

    status = pj_sock_socket(addr->addr.sa_family, pj_SOCK_DGRAM(), 0, 
			    &sock_fd);
    if (status != PJ_SUCCESS) {
	return status;
    }

    status = pj_sock_bind(sock_fd, addr, pj_sockaddr_get_len(addr));
    if (status != PJ_SUCCESS) {
	pj_sock_close(sock_fd);
	return status;
    }

    status = pj_activesock_create(pool, sock_fd, pj_SOCK_DGRAM(), opt,
				  ioqueue, cb, user_data, p_asock);
    if (status != PJ_SUCCESS) {
	pj_sock_close(sock_fd);
	return status;
    }

    if (bound_addr) {
	int addr_len = sizeof(*bound_addr);
	status = pj_sock_getsockname(sock_fd, bound_addr, &addr_len);
	if (status != PJ_SUCCESS) {
	    pj_activesock_close(*p_asock);
	    return status;
	}
    }

    return PJ_SUCCESS;
}
コード例 #8
0
static pj_stun_msg* create_msgint3(pj_pool_t *pool, test_vector *v)
{
    pj_stun_msg *msg;
    pj_sockaddr mapped_addr;
    pj_str_t s1;
    pj_status_t status;

    status = pj_stun_msg_create(pool, v->msg_type, PJ_STUN_MAGIC,
				(pj_uint8_t*)v->tsx_id, &msg);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_stun_msg_add_string_attr(pool, msg, PJ_STUN_ATTR_SOFTWARE, 
					 pj_cstr(&s1, "test vector"));
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_sockaddr_init(pj_AF_INET6(), &mapped_addr,
		      pj_cstr(&s1, "2001:db8:1234:5678:11:2233:4455:6677"),
		      32853);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_stun_msg_add_sockaddr_attr(pool, msg, 
					   PJ_STUN_ATTR_XOR_MAPPED_ADDR,
					   PJ_TRUE, &mapped_addr, 
					   sizeof(pj_sockaddr));
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_stun_msg_add_msgint_attr(pool, msg);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_stun_msg_add_uint_attr(pool, msg, PJ_STUN_ATTR_FINGERPRINT, 0);
    if (status != PJ_SUCCESS)
	goto on_error;

    return msg;

on_error:
    app_perror("    error: create_msgint3()", status);
    return NULL;
}
コード例 #9
0
ファイル: nat_detect.c プロジェクト: batk0/pjsip
static pj_status_t get_local_interface(const pj_sockaddr *server,
				       pj_sockaddr *local_addr)
{
    pj_sock_t sock;
    pj_sockaddr tmp, local;
    int addr_len;
    pj_status_t status;

    status = pj_sock_socket(server->addr.sa_family, pj_SOCK_DGRAM(),
    			    0, &sock);
    if (status != PJ_SUCCESS)
	return status;

    addr_len = pj_sockaddr_get_len(server);
    pj_sockaddr_init(server->addr.sa_family, &local, NULL, 0);
    status = pj_sock_bind(sock, &local, addr_len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(sock);
	return status;
    }

    status = pj_sock_connect(sock, server, addr_len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(sock);
	return status;
    }

    status = pj_sock_getsockname(sock, &tmp, &addr_len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(sock);
	return status;
    }

    pj_sockaddr_cp(local_addr, &tmp);
    
    pj_sock_close(sock);
    return PJ_SUCCESS;
}
コード例 #10
0
ファイル: stun_sock.c プロジェクト: RyanLee27/pjproject
/* DNS resolver callback */
static void dns_srv_resolver_cb(void *user_data,
				pj_status_t status,
				const pj_dns_srv_record *rec)
{
    pj_stun_sock *stun_sock = (pj_stun_sock*) user_data;

    pj_grp_lock_acquire(stun_sock->grp_lock);

    /* Clear query */
    stun_sock->q = NULL;

    /* Handle error */
    if (status != PJ_SUCCESS) {
	sess_fail(stun_sock, PJ_STUN_SOCK_DNS_OP, status);
	pj_grp_lock_release(stun_sock->grp_lock);
	return;
    }

    pj_assert(rec->count);
    pj_assert(rec->entry[0].server.addr_count);
    pj_assert(rec->entry[0].server.addr[0].af == stun_sock->af);

    /* Set the address */
    pj_sockaddr_init(stun_sock->af, &stun_sock->srv_addr, NULL,
		     rec->entry[0].port);
    if (stun_sock->af == pj_AF_INET6()) {
	stun_sock->srv_addr.ipv6.sin6_addr = 
				    rec->entry[0].server.addr[0].ip.v6;
    } else {
	stun_sock->srv_addr.ipv4.sin_addr = 
				    rec->entry[0].server.addr[0].ip.v4;
    }

    /* Start sending Binding request */
    get_mapped_addr(stun_sock);

    pj_grp_lock_release(stun_sock->grp_lock);
}
コード例 #11
0
ファイル: sip_transport_tcp.c プロジェクト: ChrisKwon/spore
/*
 * This is the public API to create, initialize, register, and start the
 * TCP listener.
 */
PJ_DEF(pj_status_t) pjsip_tcp_transport_start2(pjsip_endpoint *endpt,
					       const pj_sockaddr_in *local,
					       const pjsip_host_port *a_name,
					       unsigned async_cnt,
					       pjsip_tpfactory **p_factory)
{
    pjsip_tcp_transport_cfg cfg;

    pjsip_tcp_transport_cfg_default(&cfg, pj_AF_INET());

    if (local)
	pj_sockaddr_cp(&cfg.bind_addr, local);
    else
	pj_sockaddr_init(cfg.af, &cfg.bind_addr, NULL, 0);

    if (a_name)
	pj_memcpy(&cfg.addr_name, a_name, sizeof(*a_name));

    if (async_cnt)
	cfg.async_cnt = async_cnt;

    return pjsip_tcp_transport_start3(endpt, &cfg, p_factory);
}
コード例 #12
0
ファイル: ssl_sock.c プロジェクト: kaaustubh/pjsip
/* Test will perform multiple clients trying to connect to single server.
 * Once SSL connection established, echo test will be performed.
 */
static int perf_test(unsigned clients, unsigned ms_handshake_timeout)
{
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_timer_heap_t *timer = NULL;
    pj_ssl_sock_t *ssock_serv = NULL;
    pj_ssl_sock_t **ssock_cli = NULL;
    pj_ssl_sock_param param;
    struct test_state state_serv = { 0 };
    struct test_state *state_cli = NULL;
    pj_sockaddr addr, listen_addr;
    pj_ssl_cert_t *cert = NULL;
    pj_status_t status;
    unsigned i, cli_err = 0, tot_sent = 0, tot_recv = 0;
    pj_time_val start;

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

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

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

    /* Set cert */
    {
	pj_str_t tmp1, tmp2, tmp3, tmp4;

	status = pj_ssl_cert_load_from_files(pool, 
					     pj_strset2(&tmp1, (char*)CERT_CA_FILE), 
					     pj_strset2(&tmp2, (char*)CERT_FILE), 
					     pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), 
					     pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), 
					     &cert);
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}
    }

    pj_ssl_sock_param_default(&param);
    param.cb.on_accept_complete = &ssl_on_accept_complete;
    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.timer_heap = timer;
    param.timeout.sec = 0;
    param.timeout.msec = ms_handshake_timeout;
    pj_time_val_normalize(&param.timeout);

    /* Init default bind address */
    {
	pj_str_t tmp_st;
	pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
    }

    /* SERVER */
    param.user_data = &state_serv;

    state_serv.pool = pool;
    state_serv.echo = PJ_TRUE;
    state_serv.is_server = PJ_TRUE;

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

    status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Get listening address for clients to connect to */
    {
	pj_ssl_sock_info info;
	char buf[64];

	pj_ssl_sock_get_info(ssock_serv, &info);
	pj_sockaddr_cp(&listen_addr, &info.local_addr);

	pj_sockaddr_print((pj_sockaddr_t*)&listen_addr, buf, sizeof(buf), 1);
	PJ_LOG(3, ("", "...Listener ready at %s", buf));
    }


    /* CLIENTS */
    clients_num = clients;
    param.timeout.sec = 0;
    param.timeout.msec = 0;

    /* Init random seed */
    {
	pj_time_val now;

	pj_gettimeofday(&now);
	pj_srand((unsigned)now.sec);
    }

    /* Allocate SSL socket pointers and test state */
    ssock_cli = pj_pool_calloc(pool, clients, sizeof(pj_ssl_sock_t*));
    state_cli = pj_pool_calloc(pool, clients, sizeof(struct test_state));

    /* Get start timestamp */
    pj_gettimeofday(&start);

    /* Setup clients */
    for (i = 0; i < clients; ++i) {
	param.user_data = &state_cli[i];

	state_cli[i].pool = pool;
	state_cli[i].check_echo = PJ_TRUE;
	state_cli[i].send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024;
	state_cli[i].send_str = pj_pool_alloc(pool, state_cli[i].send_str_len);
	{
	    unsigned j;
	    for (j = 0; j < state_cli[i].send_str_len; ++j)
		state_cli[i].send_str[j] = (char)(pj_rand() % 256);
	}

	status = pj_ssl_sock_create(pool, &param, &ssock_cli[i]);
	if (status != PJ_SUCCESS) {
	    app_perror("...ERROR pj_ssl_sock_create()", status);
	    cli_err++;
	    clients_num--;
	    continue;
	}

	status = pj_ssl_sock_start_connect(ssock_cli[i], pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
	if (status == PJ_SUCCESS) {
	    ssl_on_connect_complete(ssock_cli[i], PJ_SUCCESS);
	} else if (status == PJ_EPENDING) {
	    status = PJ_SUCCESS;
	} else {
	    app_perror("...ERROR pj_ssl_sock_create()", status);
	    pj_ssl_sock_close(ssock_cli[i]);
	    ssock_cli[i] = NULL;
	    clients_num--;
	    cli_err++;
	    continue;
	}

	/* Give chance to server to accept this client */
	{
	    unsigned n = 5;

#ifdef PJ_SYMBIAN
	    while(n && pj_symbianos_poll(-1, 1000))
		n--;
#else
	    pj_time_val delay = {0, 100};
	    while(n && pj_ioqueue_poll(ioqueue, &delay) > 0)
		n--;
#endif
	}
    }

    /* Wait until everything has been sent/received or error */
    while (clients_num)
    {
#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
    }

    /* Clean up sockets */
    {
	pj_time_val delay = {0, 500};
	while (pj_ioqueue_poll(ioqueue, &delay) > 0);
    }

    if (state_serv.err != PJ_SUCCESS) {
	status = state_serv.err;
	goto on_return;
    }

    PJ_LOG(3, ("", "...Done!"));

    /* SSL setup and data transfer duration */
    {
	pj_time_val stop;
	
	pj_gettimeofday(&stop);
	PJ_TIME_VAL_SUB(stop, start);

	PJ_LOG(3, ("", ".....Setup & data transfer duration: %d.%03ds", stop.sec, stop.msec));
    }

    /* Check clients status */
    for (i = 0; i < clients; ++i) {
	if (state_cli[i].err != PJ_SUCCESS)
	    cli_err++;

	tot_sent += state_cli[1].sent;
	tot_recv += state_cli[1].recv;
    }

    PJ_LOG(3, ("", ".....Clients: %d (%d errors)", clients, cli_err));
    PJ_LOG(3, ("", ".....Total sent/recv: %d/%d bytes", tot_sent, tot_recv));

on_return:
    if (ssock_serv) 
	pj_ssl_sock_close(ssock_serv);

    for (i = 0; i < clients; ++i) {
	if (ssock_cli[i] && !state_cli[i].err && !state_cli[i].done)
	    pj_ssl_sock_close(ssock_cli[i]);
    }
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (pool)
	pj_pool_release(pool);

    return status;
}
コード例 #13
0
/*
 * Create stream info from SDP media line.
 */
PJ_DEF(pj_status_t) pjmedia_vid_stream_info_from_sdp(
					   pjmedia_vid_stream_info *si,
					   pj_pool_t *pool,
					   pjmedia_endpt *endpt,
					   const pjmedia_sdp_session *local,
					   const pjmedia_sdp_session *remote,
					   unsigned stream_idx)
{
    const pjmedia_sdp_attr *attr;
    const pjmedia_sdp_media *local_m;
    const pjmedia_sdp_media *rem_m;
    const pjmedia_sdp_conn *local_conn;
    const pjmedia_sdp_conn *rem_conn;
    int rem_af, local_af;
    pj_sockaddr local_addr;
    pj_status_t status;

    PJ_UNUSED_ARG(endpt);

    /* Validate arguments: */
    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);

    /* Keep SDP shortcuts */
    local_m = local->media[stream_idx];
    rem_m = remote->media[stream_idx];

    local_conn = local_m->conn ? local_m->conn : local->conn;
    if (local_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;

    rem_conn = rem_m->conn ? rem_m->conn : remote->conn;
    if (rem_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;

    /* Media type must be video */
    if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) != 0)
	return PJMEDIA_EINVALIMEDIATYPE;


    /* Reset: */

    pj_bzero(si, sizeof(*si));

    /* Media type: */
    si->type = PJMEDIA_TYPE_VIDEO;

    /* Transport protocol */

    /* At this point, transport type must be compatible,
     * the transport instance will do more validation later.
     */
    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport,
				       &local_m->desc.transport);
    if (status != PJ_SUCCESS)
	return PJMEDIA_SDPNEG_EINVANSTP;

    if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_AVP;

    } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;

    } else {

	si->proto = PJMEDIA_TP_PROTO_UNKNOWN;
	return PJ_SUCCESS;
    }


    /* Check address family in remote SDP */
    rem_af = pj_AF_UNSPEC();
    if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) {
	    rem_af = pj_AF_INET();
	} else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) {
	    rem_af = pj_AF_INET6();
	}
    }

    if (rem_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_EAFNOTSUP;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr,
			      rem_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Check address family of local info */
    local_af = pj_AF_UNSPEC();
    if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) {
	    local_af = pj_AF_INET();
	} else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) {
	    local_af = pj_AF_INET6();
	}
    }

    if (local_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_SUCCESS;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr,
			      local_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Local and remote address family must match */
    if (local_af != rem_af)
	return PJ_EAFNOTSUP;

    /* Media direction: */

    if (local_m->desc.port == 0 ||
	pj_sockaddr_has_addr(&local_addr)==PJ_FALSE ||
	pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE ||
	pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)
    {
	/* Inactive stream. */

	si->dir = PJMEDIA_DIR_NONE;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {

	/* Send only stream. */

	si->dir = PJMEDIA_DIR_ENCODING;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {

	/* Recv only stream. */

	si->dir = PJMEDIA_DIR_DECODING;

    } else {

	/* Send and receive stream. */

	si->dir = PJMEDIA_DIR_ENCODING_DECODING;

    }

    /* No need to do anything else if stream is rejected */
    if (local_m->desc.port == 0) {
	return PJ_SUCCESS;
    }

    /* If "rtcp" attribute is present in the SDP, set the RTCP address
     * from that attribute. Otherwise, calculate from RTP address.
     */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "rtcp", NULL);
    if (attr) {
	pjmedia_sdp_rtcp_attr rtcp;
	status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);
	if (status == PJ_SUCCESS) {
	    if (rtcp.addr.slen) {
		status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr,
					  (pj_uint16_t)rtcp.port);
	    } else {
		pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL,
				 (pj_uint16_t)rtcp.port);
		pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp),
		          pj_sockaddr_get_addr(&si->rem_addr),
			  pj_sockaddr_get_addr_len(&si->rem_addr));
	    }
	}
    }

    if (!pj_sockaddr_has_addr(&si->rem_rtcp)) {
	int rtcp_port;

	pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr));
	rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1;
	pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port);
    }

    /* Get codec info and param */
    status = get_video_codec_info_param(si, pool, NULL, local_m, rem_m);

    /* Leave SSRC to random. */
    si->ssrc = pj_rand();

    /* Set default jitter buffer parameter. */
    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;

    return status;
}
コード例 #14
0
ファイル: listener_udp.c プロジェクト: deveck/Deveck.TAM
/*
 * Create a new listener on the specified port.
 */
PJ_DEF(pj_status_t) pj_turn_listener_create_udp( pj_turn_srv *srv,
					        int af,
					        const pj_str_t *bound_addr,
					        unsigned port,
						unsigned concurrency_cnt,
						unsigned flags,
						pj_turn_listener **p_listener)
{
    pj_pool_t *pool;
    struct udp_listener *udp;
    pj_ioqueue_callback ioqueue_cb;
    unsigned i;
    pj_status_t status;

    /* Create structure */
    pool = pj_pool_create(srv->core.pf, "udp%p", 1000, 1000, NULL);
    udp = PJ_POOL_ZALLOC_T(pool, struct udp_listener);
    udp->base.pool = pool;
    udp->base.obj_name = pool->obj_name;
    udp->base.server = srv;
    udp->base.tp_type = PJ_TURN_TP_UDP;
    udp->base.sock = PJ_INVALID_SOCKET;
    udp->base.destroy = &udp_destroy;
    udp->read_cnt = concurrency_cnt;
    udp->base.flags = flags;

    udp->tp.obj_name = udp->base.obj_name;
    udp->tp.info = udp->base.info;
    udp->tp.listener = &udp->base;
    udp->tp.sendto = &udp_sendto;
    udp->tp.add_ref = &udp_add_ref;
    udp->tp.dec_ref = &udp_dec_ref;

    /* Create socket */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &udp->base.sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Init bind address */
    status = pj_sockaddr_init(af, &udp->base.addr, bound_addr, 
			      (pj_uint16_t)port);
    if (status != PJ_SUCCESS) 
	goto on_error;
    
    /* Create info */
    pj_ansi_strcpy(udp->base.info, "UDP:");
    pj_sockaddr_print(&udp->base.addr, udp->base.info+4, 
		      sizeof(udp->base.info)-4, 3);

    /* Bind socket */
    status = pj_sock_bind(udp->base.sock, &udp->base.addr, 
			  pj_sockaddr_get_len(&udp->base.addr));
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Register to ioqueue */
    pj_bzero(&ioqueue_cb, sizeof(ioqueue_cb));
    ioqueue_cb.on_read_complete = on_read_complete;
    status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, udp->base.sock,
				      udp, &ioqueue_cb, &udp->key);

    /* Create op keys */
    udp->read_op = (struct read_op**)pj_pool_calloc(pool, concurrency_cnt, 
						    sizeof(struct read_op*));

    /* Create each read_op and kick off read operation */
    for (i=0; i<concurrency_cnt; ++i) {
	pj_pool_t *rpool = pj_pool_create(srv->core.pf, "rop%p", 
					  1000, 1000, NULL);

	udp->read_op[i] = PJ_POOL_ZALLOC_T(pool, struct read_op);
	udp->read_op[i]->pkt.pool = rpool;

	on_read_complete(udp->key, &udp->read_op[i]->op_key, 0);
    }

    /* Done */
    PJ_LOG(4,(udp->base.obj_name, "Listener %s created", udp->base.info));

    *p_listener = &udp->base;
    return PJ_SUCCESS;


on_error:
    udp_destroy(&udp->base);
    return status;
}
コード例 #15
0
/*
 * Parse address
 */
PJ_DEF(pj_status_t) pj_sockaddr_parse( int af, unsigned options,
				       const pj_str_t *str,
				       pj_sockaddr *addr)
{
    pj_str_t hostpart;
    pj_uint16_t port;
    pj_status_t status;

    PJ_ASSERT_RETURN(addr, PJ_EINVAL);
    PJ_ASSERT_RETURN(af==PJ_AF_UNSPEC ||
		     af==PJ_AF_INET ||
		     af==PJ_AF_INET6, PJ_EINVAL);
    PJ_ASSERT_RETURN(options == 0, PJ_EINVAL);

    status = pj_sockaddr_parse2(af, options, str, &hostpart, &port, &af);
    if (status != PJ_SUCCESS)
	return status;
    
#if !defined(PJ_HAS_IPV6) || !PJ_HAS_IPV6
    if (af==PJ_AF_INET6)
	return PJ_EIPV6NOTSUP;
#endif

    status = pj_sockaddr_init(af, addr, &hostpart, port);
#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
    if (status != PJ_SUCCESS && af == PJ_AF_INET6) {
	/* Parsing does not yield valid address. Try to treat the last 
	 * portion after the colon as port number.
	 */
	const char *last_colon_pos=NULL, *p;
	const char *end = str->ptr + str->slen;
	unsigned long long_port;
	pj_str_t port_part;
	int i;

	/* Parse as IPv6:port */
	for (p=str->ptr; p!=end; ++p) {
	    if (*p == ':')
		last_colon_pos = p;
	}

	if (last_colon_pos == NULL)
	    return status;

	hostpart.ptr = (char*)str->ptr;
	hostpart.slen = last_colon_pos - str->ptr;

	port_part.ptr = (char*)last_colon_pos + 1;
	port_part.slen = end - port_part.ptr;

	/* Make sure port number is valid */
	for (i=0; i<port_part.slen; ++i) {
	    if (!pj_isdigit(port_part.ptr[i]))
		return status;
	}
	long_port = pj_strtoul(&port_part);
	if (long_port > 65535)
	    return status;

	port = (pj_uint16_t)long_port;

	status = pj_sockaddr_init(PJ_AF_INET6, addr, &hostpart, port);
    }
#endif
    
    return status;
}
コード例 #16
0
ファイル: concur_test.c プロジェクト: AmoebaLabs/pjsip
static int stun_destroy_test(void)
{
    enum { LOOP = 500 };
    struct stun_test_session test_sess;
    pj_sockaddr bind_addr;
    int addr_len;
    pj_caching_pool cp;
    pj_pool_t *pool;
    unsigned i;
    pj_status_t status;
    int rc = 0;

    PJ_LOG(3,(THIS_FILE, "  STUN destroy concurrency test"));

    pj_bzero(&test_sess, sizeof(test_sess));

    pj_caching_pool_init(&cp, NULL, 0);
    pool = pj_pool_create(&cp.factory, "testsess", 512, 512, NULL);

    pj_stun_config_init(&test_sess.stun_cfg, &cp.factory, 0, NULL, NULL);

    status = pj_timer_heap_create(pool, 1023, &test_sess.stun_cfg.timer_heap);
    pj_assert(status == PJ_SUCCESS);

    status = pj_lock_create_recursive_mutex(pool, NULL, &test_sess.lock);
    pj_assert(status == PJ_SUCCESS);

    pj_timer_heap_set_lock(test_sess.stun_cfg.timer_heap, test_sess.lock, PJ_TRUE);
    pj_assert(status == PJ_SUCCESS);

    status = pj_ioqueue_create(pool, 512, &test_sess.stun_cfg.ioqueue);
    pj_assert(status == PJ_SUCCESS);

    pj_sock_socket(pj_AF_INET(), pj_SOCK_DGRAM(), 0, &test_sess.server_sock);
    pj_sockaddr_init(pj_AF_INET(), &bind_addr, NULL, 0);
    status = pj_sock_bind(test_sess.server_sock, &bind_addr, pj_sockaddr_get_len(&bind_addr));
    pj_assert(status == PJ_SUCCESS);

    addr_len = sizeof(bind_addr);
    status = pj_sock_getsockname(test_sess.server_sock, &bind_addr, &addr_len);
    pj_assert(status == PJ_SUCCESS);

    test_sess.server_port = pj_sockaddr_get_port(&bind_addr);

    status = pj_event_create(pool, NULL, PJ_TRUE, PJ_FALSE, &test_sess.server_event);
    pj_assert(status == PJ_SUCCESS);

    for (i=0; i<SERVER_THREAD_CNT; ++i) {
	status = pj_thread_create(pool, NULL,
	                          &server_thread_proc, &test_sess,
	                          0, 0, &test_sess.server_threads[i]);
	pj_assert(status == PJ_SUCCESS);
    }

    for (i=0; i<WORKER_THREAD_CNT; ++i) {
	status = pj_thread_create(pool, NULL,
	                          &worker_thread_proc, &test_sess,
	                          0, 0, &test_sess.worker_threads[i]);
	pj_assert(status == PJ_SUCCESS);
    }

    /* Test 1: Main thread calls destroy while callback is processing response */
    PJ_LOG(3,(THIS_FILE, "    Destroy in main thread while callback is running"));
    for (i=0; i<LOOP; ++i) {
	int sleep = pj_rand() % 5;

	PJ_LOG(3,(THIS_FILE, "      Try %-3d of %d", i+1, LOOP));

	/* Test 1: destroy at the same time when receiving response */
	pj_bzero(&test_sess.param, sizeof(test_sess.param));
	test_sess.param.client_sleep_after_start = 20;
	test_sess.param.client_sleep_before_destroy = sleep;
	test_sess.param.server_wait_for_event = PJ_TRUE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE,
		  "        stun test a: sleep delay:%d: clients with response: %d",
		  sleep, test_sess.param.client_got_response));

	/* Test 2: destroy at the same time with STUN retransmit timer */
	test_sess.param.server_drop_request = PJ_TRUE;
	test_sess.param.client_sleep_after_start = 0;
	test_sess.param.client_sleep_before_destroy = PJ_STUN_RTO_VALUE;
	test_sess.param.server_wait_for_event = PJ_FALSE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE, "        stun test b: retransmit concurrency"));

	/* Test 3: destroy at the same time with receiving response
	 * AND STUN retransmit timer */
	test_sess.param.client_got_response = 0;
	test_sess.param.server_drop_request = PJ_FALSE;
	test_sess.param.client_sleep_after_start = PJ_STUN_RTO_VALUE;
	test_sess.param.client_sleep_before_destroy = 0;
	test_sess.param.server_wait_for_event = PJ_TRUE;
	stun_destroy_test_session(&test_sess);
	PJ_LOG(3,(THIS_FILE,
		  "        stun test c: clients with response: %d",
		  test_sess.param.client_got_response));

	pj_thread_sleep(10);

	ice_one_conc_test(&test_sess.stun_cfg, PJ_FALSE);

	pj_thread_sleep(10);
    }

    /* Avoid compiler warning */
    goto on_return;


on_return:
    test_sess.thread_quit_flag = PJ_TRUE;

    for (i=0; i<SERVER_THREAD_CNT; ++i) {
	pj_thread_join(test_sess.server_threads[i]);
    }

    for (i=0; i<WORKER_THREAD_CNT; ++i) {
	pj_thread_join(test_sess.worker_threads[i]);
    }

    pj_event_destroy(test_sess.server_event);
    pj_sock_close(test_sess.server_sock);
    pj_ioqueue_destroy(test_sess.stun_cfg.ioqueue);
    pj_timer_heap_destroy(test_sess.stun_cfg.timer_heap);

    pj_pool_release(pool);
    pj_caching_pool_destroy(&cp);

    PJ_LOG(3,(THIS_FILE, "    Done. rc=%d", rc));
    return rc;
}
コード例 #17
0
ファイル: sock.c プロジェクト: AmoebaLabs/pjsip
static int parse_test(void)
{
#define IPv4	1
#define IPv6	2

    struct test_t {
	const char  *input;
	int	     result_af;
	const char  *result_ip;
	pj_uint16_t  result_port;
    };
    struct test_t valid_tests[] = 
    {
	/* IPv4 */
	{ "10.0.0.1:80", IPv4, "10.0.0.1", 80},
	{ "10.0.0.1", IPv4, "10.0.0.1", 0},
	{ "10.0.0.1:", IPv4, "10.0.0.1", 0},
	{ "10.0.0.1:0", IPv4, "10.0.0.1", 0},
	{ ":80", IPv4, "0.0.0.0", 80},
	{ ":", IPv4, "0.0.0.0", 0},
#if !PJ_SYMBIAN
	{ "localhost", IPv4, "127.0.0.1", 0},
	{ "localhost:", IPv4, "127.0.0.1", 0},
	{ "localhost:80", IPv4, "127.0.0.1", 80},
#endif

#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
	{ "fe::01:80", IPv6, "fe::01:80", 0},
	{ "[fe::01]:80", IPv6, "fe::01", 80},
	{ "fe::01", IPv6, "fe::01", 0},
	{ "[fe::01]", IPv6, "fe::01", 0},
	{ "fe::01:", IPv6, "fe::01", 0},
	{ "[fe::01]:", IPv6, "fe::01", 0},
	{ "::", IPv6, "::0", 0},
	{ "[::]", IPv6, "::", 0},
	{ ":::", IPv6, "::", 0},
	{ "[::]:", IPv6, "::", 0},
	{ ":::80", IPv6, "::", 80},
	{ "[::]:80", IPv6, "::", 80},
#endif
    };
    struct test_t invalid_tests[] = 
    {
	/* IPv4 */
	{ "10.0.0.1:abcd", IPv4},   /* port not numeric */
	{ "10.0.0.1:-1", IPv4},	    /* port contains illegal character */
	{ "10.0.0.1:123456", IPv4}, /* port too big	*/
	{ "1.2.3.4.5:80", IPv4},    /* invalid IP */
	{ "10:0:80", IPv4},	    /* hostname has colon */

#if defined(PJ_HAS_IPV6) && PJ_HAS_IPV6
	{ "[fe::01]:abcd", IPv6},   /* port not numeric */
	{ "[fe::01]:-1", IPv6},	    /* port contains illegal character */
	{ "[fe::01]:123456", IPv6}, /* port too big	*/
	{ "fe::01:02::03:04:80", IPv6},	    /* invalid IP */
	{ "[fe::01:02::03:04]:80", IPv6},   /* invalid IP */
	{ "[fe:01", IPv6},	    /* Unterminated bracket */
#endif
    };

    unsigned i;

    PJ_LOG(3,("test", "...IP address parsing"));

    for (i=0; i<PJ_ARRAY_SIZE(valid_tests); ++i) {
	pj_status_t status;
	pj_str_t input;
	pj_sockaddr addr, result;

	switch (valid_tests[i].result_af) {
	case IPv4:
	    valid_tests[i].result_af = PJ_AF_INET;
	    break;
	case IPv6:
	    valid_tests[i].result_af = PJ_AF_INET6;
	    break;
	default:
	    pj_assert(!"Invalid AF!");
	    continue;
	}

	/* Try parsing with PJ_AF_UNSPEC */
	status = pj_sockaddr_parse(PJ_AF_UNSPEC, 0, 
				   pj_cstr(&input, valid_tests[i].input), 
				   &addr);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,("test", ".... failed when parsing %s (i=%d)", 
		      valid_tests[i].input, i));
	    return -10;
	}

	/* Check "sin_len" member of parse result */
	CHECK_SA_ZERO_LEN(&addr, -20);

	/* Build the correct result */
	status = pj_sockaddr_init(valid_tests[i].result_af,
				  &result,
				  pj_cstr(&input, valid_tests[i].result_ip), 
				  valid_tests[i].result_port);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,("test", ".... error building IP address %s", 
		      valid_tests[i].input));
	    return -30;
	}

	/* Compare the result */
	if (pj_sockaddr_cmp(&addr, &result) != 0) {
	    PJ_LOG(1,("test", ".... parsed result mismatched for %s", 
		      valid_tests[i].input));
	    return -40;
	}

	/* Parse again with the specified af */
	status = pj_sockaddr_parse(valid_tests[i].result_af, 0, 
				   pj_cstr(&input, valid_tests[i].input), 
				   &addr);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(1,("test", ".... failed when parsing %s", 
		      valid_tests[i].input));
	    return -50;
	}

	/* Check "sin_len" member of parse result */
	CHECK_SA_ZERO_LEN(&addr, -55);

	/* Compare the result again */
	if (pj_sockaddr_cmp(&addr, &result) != 0) {
	    PJ_LOG(1,("test", ".... parsed result mismatched for %s", 
		      valid_tests[i].input));
	    return -60;
	}
    }

    for (i=0; i<PJ_ARRAY_SIZE(invalid_tests); ++i) {
	pj_status_t status;
	pj_str_t input;
	pj_sockaddr addr;

	switch (invalid_tests[i].result_af) {
	case IPv4:
	    invalid_tests[i].result_af = PJ_AF_INET;
	    break;
	case IPv6:
	    invalid_tests[i].result_af = PJ_AF_INET6;
	    break;
	default:
	    pj_assert(!"Invalid AF!");
	    continue;
	}

	/* Try parsing with PJ_AF_UNSPEC */
	status = pj_sockaddr_parse(PJ_AF_UNSPEC, 0, 
				   pj_cstr(&input, invalid_tests[i].input), 
				   &addr);
	if (status == PJ_SUCCESS) {
	    PJ_LOG(1,("test", ".... expecting failure when parsing %s", 
		      invalid_tests[i].input));
	    return -100;
	}
    }

    return 0;
}
コード例 #18
0
ファイル: simpleua.c プロジェクト: Archipov/android-client
/*
 * 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;
}
コード例 #19
0
ファイル: sock_common.c プロジェクト: avble/natClientEx
/* Get IP interface for sending to the specified destination */
PJ_DEF(pj_status_t) pj_getipinterface(int af,
                                      const pj_str_t *dst,
                                      pj_sockaddr *itf_addr,
                                      pj_bool_t allow_resolve,
                                      pj_sockaddr *p_dst_addr)
{
    pj_sockaddr dst_addr;
    pj_sock_t fd;
    int len;
    pj_uint8_t zero[64];
    pj_status_t status;

    pj_sockaddr_init(af, &dst_addr, NULL, 53);
    status = pj_inet_pton(af, dst, pj_sockaddr_get_addr(&dst_addr));
    if (status != PJ_SUCCESS) {
	/* "dst" is not an IP address. */
	if (allow_resolve) {
	    status = pj_sockaddr_init(af, &dst_addr, dst, 53);
	} else {
	    pj_str_t cp;

	    if (af == PJ_AF_INET) {
		cp = pj_str("1.1.1.1");
	    } else {
		cp = pj_str("1::1");
	    }
	    status = pj_sockaddr_init(af, &dst_addr, &cp, 53);
	}

	if (status != PJ_SUCCESS)
	    return status;
    }

    /* Create UDP socket and connect() to the destination IP */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &fd);
    if (status != PJ_SUCCESS) {
	return status;
    }

    status = pj_sock_connect(fd, &dst_addr, pj_sockaddr_get_len(&dst_addr));
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
    }

    len = sizeof(*itf_addr);
    status = pj_sock_getsockname(fd, itf_addr, &len);
    if (status != PJ_SUCCESS) {
	pj_sock_close(fd);
	return status;
    }

    pj_sock_close(fd);

    /* Check that the address returned is not zero */
    pj_bzero(zero, sizeof(zero));
    if (pj_memcmp(pj_sockaddr_get_addr(itf_addr), zero,
		  pj_sockaddr_get_addr_len(itf_addr))==0)
    {
	return PJ_ENOTFOUND;
    }

    if (p_dst_addr)
	*p_dst_addr = dst_addr;

    return PJ_SUCCESS;
}
コード例 #20
0
ファイル: ssl_sock.c プロジェクト: kaaustubh/pjsip
/* Raw TCP socket try to connect to SSL socket server, once
 * connection established, it will just do nothing, SSL socket
 * server should be able to close the connection after specified
 * timeout period (set ms_timeout to 0 to disable timer).
 */
static int client_non_ssl(unsigned ms_timeout)
{
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_timer_heap_t *timer = NULL;
    pj_ssl_sock_t *ssock_serv = NULL;
    pj_activesock_t *asock_cli = NULL;
    pj_activesock_cb asock_cb = { 0 };
    pj_sock_t sock = PJ_INVALID_SOCKET;
    pj_ssl_sock_param param;
    struct test_state state_serv = { 0 };
    struct test_state state_cli = { 0 };
    pj_sockaddr listen_addr;
    pj_ssl_cert_t *cert = NULL;
    pj_status_t status;

    pool = pj_pool_create(mem, "ssl_accept_raw_tcp", 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;
    }

    /* Set cert */
    {
	pj_str_t tmp1, tmp2, tmp3, tmp4;
	status = pj_ssl_cert_load_from_files(pool, 
					     pj_strset2(&tmp1, (char*)CERT_CA_FILE), 
					     pj_strset2(&tmp2, (char*)CERT_FILE), 
					     pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), 
					     pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), 
					     &cert);
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}
    }

    pj_ssl_sock_param_default(&param);
    param.cb.on_accept_complete = &ssl_on_accept_complete;
    param.cb.on_data_read = &ssl_on_data_read;
    param.cb.on_data_sent = &ssl_on_data_sent;
    param.ioqueue = ioqueue;
    param.timer_heap = timer;
    param.timeout.sec = 0;
    param.timeout.msec = ms_timeout;
    pj_time_val_normalize(&param.timeout);

    /* SERVER */
    param.user_data = &state_serv;
    state_serv.pool = pool;
    state_serv.is_server = PJ_TRUE;
    state_serv.is_verbose = PJ_TRUE;

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

    status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Init bind address */
    {
	pj_str_t tmp_st;
	pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
    }

    status = pj_ssl_sock_start_accept(ssock_serv, pool, &listen_addr, pj_sockaddr_get_len(&listen_addr));
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Update listener address */
    {
	pj_ssl_sock_info info;

	pj_ssl_sock_get_info(ssock_serv, &info);
	pj_sockaddr_cp(&listen_addr, &info.local_addr);
    }

    /* CLIENT */
    state_cli.pool = pool;
    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    asock_cb.on_connect_complete = &asock_on_connect_complete;
    asock_cb.on_data_read = &asock_on_data_read;
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, 
				  ioqueue, &asock_cb, &state_cli, &asock_cli);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    status = pj_activesock_start_connect(asock_cli, pool, (pj_sockaddr_t*)&listen_addr, 
					 pj_sockaddr_get_len(&listen_addr));
    if (status == PJ_SUCCESS) {
	asock_on_connect_complete(asock_cli, PJ_SUCCESS);
    } else if (status == PJ_EPENDING) {
	status = PJ_SUCCESS;
    } else {
	goto on_return;
    }

    /* Wait until everything has been sent/received or error */
    while (!state_serv.err && !state_cli.err && !state_serv.done && !state_cli.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_serv.err || state_cli.err) {
	if (state_serv.err != PJ_SUCCESS)
	    status = state_serv.err;
	else
	    status = state_cli.err;

	goto on_return;
    }

    PJ_LOG(3, ("", "...Done!"));

on_return:
    if (ssock_serv)
	pj_ssl_sock_close(ssock_serv);
    if (asock_cli && !state_cli.err && !state_cli.done)
	pj_activesock_close(asock_cli);
    if (timer)
	pj_timer_heap_destroy(timer);
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (pool)
	pj_pool_release(pool);

    return status;
}
コード例 #21
0
ファイル: session.c プロジェクト: max3903/SFLphone
/*
 * Create stream info from SDP media line.
 */
PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
					   pjmedia_stream_info *si,
					   pj_pool_t *pool,
					   pjmedia_endpt *endpt,
					   const pjmedia_sdp_session *local,
					   const pjmedia_sdp_session *remote,
					   unsigned stream_idx)
{
    pjmedia_codec_mgr *mgr;
    const pjmedia_sdp_attr *attr;
    const pjmedia_sdp_media *local_m;
    const pjmedia_sdp_media *rem_m;
    const pjmedia_sdp_conn *local_conn;
    const pjmedia_sdp_conn *rem_conn;
    int rem_af, local_af;
    pj_sockaddr local_addr;
    pjmedia_sdp_rtpmap *rtpmap;
    unsigned i, pt, fmti;
    pj_status_t status;

    
    /* Validate arguments: */
    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);


    /* Get codec manager. */
    mgr = pjmedia_endpt_get_codec_mgr(endpt);

    /* Keep SDP shortcuts */
    local_m = local->media[stream_idx];
    rem_m = remote->media[stream_idx];

    local_conn = local_m->conn ? local_m->conn : local->conn;
    if (local_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;

    rem_conn = rem_m->conn ? rem_m->conn : remote->conn;
    if (rem_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;


    /* Reset: */

    pj_bzero(si, sizeof(*si));

#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR
    /* Set default RTCP XR enabled/disabled */
    si->rtcp_xr_enabled = PJ_TRUE;
#endif

    /* Media type: */

    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) == 0) {

	si->type = PJMEDIA_TYPE_AUDIO;

    } else if (pj_stricmp(&local_m->desc.media, &ID_VIDEO) == 0) {

	si->type = PJMEDIA_TYPE_VIDEO;

    } else {

	si->type = PJMEDIA_TYPE_UNKNOWN;

	/* Avoid rejecting call because of unrecognized media, 
	 * just return PJ_SUCCESS, this media will be deactivated later.
	 */
	//return PJMEDIA_EINVALIMEDIATYPE;
	return PJ_SUCCESS;

    }

    /* Transport protocol */

    /* At this point, transport type must be compatible, 
     * the transport instance will do more validation later.
     */
    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport, 
				       &local_m->desc.transport);
    if (status != PJ_SUCCESS)
	return PJMEDIA_SDPNEG_EINVANSTP;

    if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_AVP;

    } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;

    } else {

	si->proto = PJMEDIA_TP_PROTO_UNKNOWN;
	return PJ_SUCCESS;
    }


    /* Check address family in remote SDP */
    rem_af = pj_AF_UNSPEC();
    if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) {
	    rem_af = pj_AF_INET();
	} else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) {
	    rem_af = pj_AF_INET6();
	}
    }

    if (rem_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_EAFNOTSUP;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr, 
			      rem_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Check address family of local info */
    local_af = pj_AF_UNSPEC();
    if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) {
	    local_af = pj_AF_INET();
	} else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) {
	    local_af = pj_AF_INET6();
	}
    }

    if (local_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_SUCCESS;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr, 
			      local_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Local and remote address family must match */
    if (local_af != rem_af)
	return PJ_EAFNOTSUP;

    /* Media direction: */

    if (local_m->desc.port == 0 || 
	pj_sockaddr_has_addr(&local_addr)==PJ_FALSE ||
	pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE ||
	pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)
    {
	/* Inactive stream. */

	si->dir = PJMEDIA_DIR_NONE;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {

	/* Send only stream. */

	si->dir = PJMEDIA_DIR_ENCODING;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {

	/* Recv only stream. */

	si->dir = PJMEDIA_DIR_DECODING;

    } else {

	/* Send and receive stream. */

	si->dir = PJMEDIA_DIR_ENCODING_DECODING;

    }

    /* No need to do anything else if stream is rejected */
    if (local_m->desc.port == 0) {
	return PJ_SUCCESS;
    }

    /* If "rtcp" attribute is present in the SDP, set the RTCP address
     * from that attribute. Otherwise, calculate from RTP address.
     */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "rtcp", NULL);
    if (attr) {
	pjmedia_sdp_rtcp_attr rtcp;
	status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);
	if (status == PJ_SUCCESS) {
	    if (rtcp.addr.slen) {
		status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr,
					  (pj_uint16_t)rtcp.port);
	    } else {
		pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL, 
				 (pj_uint16_t)rtcp.port);
		pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp),
		          pj_sockaddr_get_addr(&si->rem_addr),
			  pj_sockaddr_get_addr_len(&si->rem_addr));
	    }
	}
    }
    
    if (!pj_sockaddr_has_addr(&si->rem_rtcp)) {
	int rtcp_port;

	pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr));
	rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1;
	pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port);
    }


    /* Get the payload number for receive channel. */
    /*
       Previously we used to rely on fmt[0] being the selected codec,
       but some UA sends telephone-event as fmt[0] and this would
       cause assert failure below.

       Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch.

    // And codec must be numeric!
    if (!pj_isdigit(*local_m->desc.fmt[0].ptr) || 
	!pj_isdigit(*rem_m->desc.fmt[0].ptr))
    {
	return PJMEDIA_EINVALIDPT;
    }

    pt = pj_strtoul(&local_m->desc.fmt[0]);
    pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 ||
	      pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS);
    */

    /* This is to suppress MSVC warning about uninitialized var */
    pt = 0;

    /* Find the first codec which is not telephone-event */
    for ( fmti = 0; fmti < local_m->desc.fmt_count; ++fmti ) {
	if ( !pj_isdigit(*local_m->desc.fmt[fmti].ptr) )
	    return PJMEDIA_EINVALIDPT;
	pt = pj_strtoul(&local_m->desc.fmt[fmti]);
	if ( PJMEDIA_RTP_PT_TELEPHONE_EVENTS == 0 ||
		pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS )
		break;
    }
    if ( fmti >= local_m->desc.fmt_count )
	return PJMEDIA_EINVALIDPT;

    /* Get codec info.
     * For static payload types, get the info from codec manager.
     * For dynamic payload types, MUST get the rtpmap.
     */
    if (pt < 96) {
	pj_bool_t has_rtpmap;

	rtpmap = NULL;
	has_rtpmap = PJ_TRUE;

	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 
					   &local_m->desc.fmt[fmti]);
	if (attr == NULL) {
	    has_rtpmap = PJ_FALSE;
	}
	if (attr != NULL) {
	    status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
	    if (status != PJ_SUCCESS)
		has_rtpmap = PJ_FALSE;
	}

	/* Build codec format info: */
	if (has_rtpmap) {
	    si->fmt.type = si->type;
	    si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
	    pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
	    si->fmt.clock_rate = rtpmap->clock_rate;
	    
#if defined(PJMEDIA_HANDLE_G722_MPEG_BUG) && (PJMEDIA_HANDLE_G722_MPEG_BUG != 0)
	    /* The session info should have the actual clock rate, because 
	     * this info is used for calculationg buffer size, etc in stream 
	     */
	    if (si->fmt.pt == PJMEDIA_RTP_PT_G722)
		si->fmt.clock_rate = 16000;
#endif

	    /* For audio codecs, rtpmap parameters denotes the number of
	     * channels.
	     */
	    if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
		si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
	    } else {
		si->fmt.channel_cnt = 1;
	    }

	} else {	    
	    const pjmedia_codec_info *p_info;

	    status = pjmedia_codec_mgr_get_codec_info( mgr, pt, &p_info);
	    if (status != PJ_SUCCESS)
		return status;

	    pj_memcpy(&si->fmt, p_info, sizeof(pjmedia_codec_info));
	}

	/* For static payload type, pt's are symetric */
	si->tx_pt = pt;

    } else {

	attr = pjmedia_sdp_media_find_attr(local_m, &ID_RTPMAP, 
					   &local_m->desc.fmt[fmti]);
	if (attr == NULL)
	    return PJMEDIA_EMISSINGRTPMAP;

	status = pjmedia_sdp_attr_to_rtpmap(pool, attr, &rtpmap);
	if (status != PJ_SUCCESS)
	    return status;

	/* Build codec format info: */

	si->fmt.type = si->type;
	si->fmt.pt = pj_strtoul(&local_m->desc.fmt[fmti]);
	pj_strdup(pool, &si->fmt.encoding_name, &rtpmap->enc_name);
	si->fmt.clock_rate = rtpmap->clock_rate;

	/* For audio codecs, rtpmap parameters denotes the number of
	 * channels.
	 */
	if (si->type == PJMEDIA_TYPE_AUDIO && rtpmap->param.slen) {
	    si->fmt.channel_cnt = (unsigned) pj_strtoul(&rtpmap->param);
	} else {
	    si->fmt.channel_cnt = 1;
	}

	/* Determine payload type for outgoing channel, by finding
	 * dynamic payload type in remote SDP that matches the answer.
	 */
	si->tx_pt = 0xFFFF;
	for (i=0; i<rem_m->desc.fmt_count; ++i) {
	    unsigned rpt;
	    pjmedia_sdp_attr *r_attr;
	    pjmedia_sdp_rtpmap r_rtpmap;

	    rpt = pj_strtoul(&rem_m->desc.fmt[i]);
	    if (rpt < 96)
		continue;

	    r_attr = pjmedia_sdp_media_find_attr(rem_m, &ID_RTPMAP,
						 &rem_m->desc.fmt[i]);
	    if (!r_attr)
		continue;

	    if (pjmedia_sdp_attr_get_rtpmap(r_attr, &r_rtpmap) != PJ_SUCCESS)
		continue;

	    if (!pj_stricmp(&rtpmap->enc_name, &r_rtpmap.enc_name) &&
		rtpmap->clock_rate == r_rtpmap.clock_rate)
	    {
		/* Found matched codec. */
		si->tx_pt = rpt;

		break;
	    }
	}

	if (si->tx_pt == 0xFFFF)
	    return PJMEDIA_EMISSINGRTPMAP;
    }

  
    /* Now that we have codec info, get the codec param. */
    si->param = PJ_POOL_ALLOC_T(pool, pjmedia_codec_param);
    status = pjmedia_codec_mgr_get_default_param(mgr, &si->fmt, si->param);

    /* Get remote fmtp for our encoder. */
    parse_fmtp(pool, rem_m, si->tx_pt, &si->param->setting.enc_fmtp);

    /* Get local fmtp for our decoder. */
    parse_fmtp(pool, local_m, si->fmt.pt, &si->param->setting.dec_fmtp);

    /* Get remote maxptime for our encoder. */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "maxptime", NULL);
    if (attr) {
	pj_str_t tmp_val = attr->value;

	pj_strltrim(&tmp_val);
	si->tx_maxptime = pj_strtoul(&tmp_val);
    }

    /* When direction is NONE (it means SDP negotiation has failed) we don't
     * need to return a failure here, as returning failure will cause
     * the whole SDP to be rejected. See ticket #:
     *	http://
     *
     * Thanks Alain Totouom 
     */
    if (status != PJ_SUCCESS && si->dir != PJMEDIA_DIR_NONE)
	return status;


    /* Get incomming payload type for telephone-events */
    si->rx_event_pt = -1;
    for (i=0; i<local_m->attr_count; ++i) {
	pjmedia_sdp_rtpmap r;

	attr = local_m->attr[i];
	if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
	    continue;
	if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
	    continue;
	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
	    si->rx_event_pt = pj_strtoul(&r.pt);
	    break;
	}
    }

    /* Get outgoing payload type for telephone-events */
    si->tx_event_pt = -1;
    for (i=0; i<rem_m->attr_count; ++i) {
	pjmedia_sdp_rtpmap r;

	attr = rem_m->attr[i];
	if (pj_strcmp(&attr->name, &ID_RTPMAP) != 0)
	    continue;
	if (pjmedia_sdp_attr_get_rtpmap(attr, &r) != PJ_SUCCESS)
	    continue;
	if (pj_strcmp(&r.enc_name, &ID_TELEPHONE_EVENT) == 0) {
	    si->tx_event_pt = pj_strtoul(&r.pt);
	    break;
	}
    }

    /* Leave SSRC to random. */
    si->ssrc = pj_rand();

    /* Set default jitter buffer parameter. */
    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;

    return PJ_SUCCESS;
}
コード例 #22
0
ファイル: stream_info.c プロジェクト: avble/natClientEx
/*
 * Create stream info from SDP media line.
 */
PJ_DEF(pj_status_t) pjmedia_stream_info_from_sdp(
					   pjmedia_stream_info *si,
					   pj_pool_t *pool,
					   pjmedia_endpt *endpt,
					   const pjmedia_sdp_session *local,
					   const pjmedia_sdp_session *remote,
					   unsigned stream_idx)
{
    const pj_str_t STR_INACTIVE = { "inactive", 8 };
    const pj_str_t STR_SENDONLY = { "sendonly", 8 };
    const pj_str_t STR_RECVONLY = { "recvonly", 8 };

    pjmedia_codec_mgr *mgr;
    const pjmedia_sdp_attr *attr;
    const pjmedia_sdp_media *local_m;
    const pjmedia_sdp_media *rem_m;
    const pjmedia_sdp_conn *local_conn;
    const pjmedia_sdp_conn *rem_conn;
    int rem_af, local_af;
    pj_sockaddr local_addr;
    pj_status_t status;


    /* Validate arguments: */
    PJ_ASSERT_RETURN(pool && si && local && remote, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < local->media_count, PJ_EINVAL);
    PJ_ASSERT_RETURN(stream_idx < remote->media_count, PJ_EINVAL);

    /* Keep SDP shortcuts */
    local_m = local->media[stream_idx];
    rem_m = remote->media[stream_idx];

    local_conn = local_m->conn ? local_m->conn : local->conn;
    if (local_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;

    rem_conn = rem_m->conn ? rem_m->conn : remote->conn;
    if (rem_conn == NULL)
	return PJMEDIA_SDP_EMISSINGCONN;

    /* Media type must be audio */
    if (pj_stricmp(&local_m->desc.media, &ID_AUDIO) != 0)
	return PJMEDIA_EINVALIMEDIATYPE;

    /* Get codec manager. */
    mgr = pjmedia_endpt_get_codec_mgr(endpt);

    /* Reset: */

    pj_bzero(si, sizeof(*si));

#if PJMEDIA_HAS_RTCP_XR && PJMEDIA_STREAM_ENABLE_XR
    /* Set default RTCP XR enabled/disabled */
    si->rtcp_xr_enabled = PJ_TRUE;
#endif

    /* Media type: */
    si->type = PJMEDIA_TYPE_AUDIO;

    /* Transport protocol */

    /* At this point, transport type must be compatible,
     * the transport instance will do more validation later.
     */
    status = pjmedia_sdp_transport_cmp(&rem_m->desc.transport,
				       &local_m->desc.transport);
    if (status != PJ_SUCCESS)
	return PJMEDIA_SDPNEG_EINVANSTP;

    if (pj_stricmp(&local_m->desc.transport, &ID_RTP_AVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_AVP;

    } else if (pj_stricmp(&local_m->desc.transport, &ID_RTP_SAVP) == 0) {

	si->proto = PJMEDIA_TP_PROTO_RTP_SAVP;

    } else {

	si->proto = PJMEDIA_TP_PROTO_UNKNOWN;
	return PJ_SUCCESS;
    }


    /* Check address family in remote SDP */
    rem_af = pj_AF_UNSPEC();
    if (pj_stricmp(&rem_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&rem_conn->addr_type, &ID_IP4)==0) {
	    rem_af = pj_AF_INET();
	} else if (pj_stricmp(&rem_conn->addr_type, &ID_IP6)==0) {
	    rem_af = pj_AF_INET6();
	}
    }

    if (rem_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_EAFNOTSUP;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(rem_af, &si->rem_addr, &rem_conn->addr,
			      rem_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Check address family of local info */
    local_af = pj_AF_UNSPEC();
    if (pj_stricmp(&local_conn->net_type, &ID_IN)==0) {
	if (pj_stricmp(&local_conn->addr_type, &ID_IP4)==0) {
	    local_af = pj_AF_INET();
	} else if (pj_stricmp(&local_conn->addr_type, &ID_IP6)==0) {
	    local_af = pj_AF_INET6();
	}
    }

    if (local_af==pj_AF_UNSPEC()) {
	/* Unsupported address family */
	return PJ_SUCCESS;
    }

    /* Set remote address: */
    status = pj_sockaddr_init(local_af, &local_addr, &local_conn->addr,
			      local_m->desc.port);
    if (status != PJ_SUCCESS) {
	/* Invalid IP address. */
	return PJMEDIA_EINVALIDIP;
    }

    /* Local and remote address family must match */
    if (local_af != rem_af)
	return PJ_EAFNOTSUP;

    /* Media direction: */

    if (local_m->desc.port == 0 ||
	pj_sockaddr_has_addr(&local_addr)==PJ_FALSE ||
	pj_sockaddr_has_addr(&si->rem_addr)==PJ_FALSE ||
	pjmedia_sdp_media_find_attr(local_m, &STR_INACTIVE, NULL)!=NULL)
    {
	/* Inactive stream. */

	si->dir = PJMEDIA_DIR_NONE;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_SENDONLY, NULL)!=NULL) {

	/* Send only stream. */

	si->dir = PJMEDIA_DIR_ENCODING;

    } else if (pjmedia_sdp_media_find_attr(local_m, &STR_RECVONLY, NULL)!=NULL) {

	/* Recv only stream. */

	si->dir = PJMEDIA_DIR_DECODING;

    } else {

	/* Send and receive stream. */

	si->dir = PJMEDIA_DIR_ENCODING_DECODING;

    }

    /* No need to do anything else if stream is rejected */
    if (local_m->desc.port == 0) {
	return PJ_SUCCESS;
    }

    /* If "rtcp" attribute is present in the SDP, set the RTCP address
     * from that attribute. Otherwise, calculate from RTP address.
     */
    attr = pjmedia_sdp_attr_find2(rem_m->attr_count, rem_m->attr,
				  "rtcp", NULL);
    if (attr) {
	pjmedia_sdp_rtcp_attr rtcp;
	status = pjmedia_sdp_attr_get_rtcp(attr, &rtcp);
	if (status == PJ_SUCCESS) {
	    if (rtcp.addr.slen) {
		status = pj_sockaddr_init(rem_af, &si->rem_rtcp, &rtcp.addr,
					  (pj_uint16_t)rtcp.port);
	    } else {
		pj_sockaddr_init(rem_af, &si->rem_rtcp, NULL,
				 (pj_uint16_t)rtcp.port);
		pj_memcpy(pj_sockaddr_get_addr(&si->rem_rtcp),
		          pj_sockaddr_get_addr(&si->rem_addr),
			  pj_sockaddr_get_addr_len(&si->rem_addr));
	    }
	}
    }

    if (!pj_sockaddr_has_addr(&si->rem_rtcp)) {
	int rtcp_port;

	pj_memcpy(&si->rem_rtcp, &si->rem_addr, sizeof(pj_sockaddr));
	rtcp_port = pj_sockaddr_get_port(&si->rem_addr) + 1;
	pj_sockaddr_set_port(&si->rem_rtcp, (pj_uint16_t)rtcp_port);
    }


    /* Get the payload number for receive channel. */
    /*
       Previously we used to rely on fmt[0] being the selected codec,
       but some UA sends telephone-event as fmt[0] and this would
       cause assert failure below.

       Thanks Chris Hamilton <chamilton .at. cs.dal.ca> for this patch.

    // And codec must be numeric!
    if (!pj_isdigit(*local_m->desc.fmt[0].ptr) ||
	!pj_isdigit(*rem_m->desc.fmt[0].ptr))
    {
	return PJMEDIA_EINVALIDPT;
    }

    pt = pj_strtoul(&local_m->desc.fmt[0]);
    pj_assert(PJMEDIA_RTP_PT_TELEPHONE_EVENTS==0 ||
	      pt != PJMEDIA_RTP_PT_TELEPHONE_EVENTS);
    */

    /* Get codec info and param */
    status = get_audio_codec_info_param(si, pool, mgr, local_m, rem_m);

    /* Leave SSRC to random. */
    si->ssrc = pj_rand();

    /* Set default jitter buffer parameter. */
    si->jb_init = si->jb_max = si->jb_min_pre = si->jb_max_pre = -1;

    return status;
}
コード例 #23
0
ファイル: ssl_sock.c プロジェクト: kaaustubh/pjsip
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;
}
コード例 #24
0
ファイル: sip_transport_tcp.c プロジェクト: ChrisKwon/spore
/*
 * This is the public API to create, initialize, register, and start the
 * TCP listener.
 */
PJ_DEF(pj_status_t) pjsip_tcp_transport_start3(
					pjsip_endpoint *endpt,
					const pjsip_tcp_transport_cfg *cfg,
					pjsip_tpfactory **p_factory
					)
{
    pj_pool_t *pool;
    pj_sock_t sock = PJ_INVALID_SOCKET;
    struct tcp_listener *listener;
    pj_activesock_cfg asock_cfg;
    pj_activesock_cb listener_cb;
    pj_sockaddr *listener_addr;
    int addr_len;
    pj_status_t status;

    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && cfg->async_cnt, PJ_EINVAL);

    /* Verify that address given in a_name (if any) is valid */
    if (cfg->addr_name.host.slen) {
	pj_sockaddr tmp;

	status = pj_sockaddr_init(cfg->af, &tmp, &cfg->addr_name.host, 
				  (pj_uint16_t)cfg->addr_name.port);
	if (status != PJ_SUCCESS || !pj_sockaddr_has_addr(&tmp) ||
	    (cfg->af==pj_AF_INET() && 
	     tmp.ipv4.sin_addr.s_addr==PJ_INADDR_NONE)) 
	{
	    /* Invalid address */
	    return PJ_EINVAL;
	}
    }

    pool = pjsip_endpt_create_pool(endpt, "tcplis", POOL_LIS_INIT, 
				   POOL_LIS_INC);
    PJ_ASSERT_RETURN(pool, PJ_ENOMEM);


    listener = PJ_POOL_ZALLOC_T(pool, struct tcp_listener);
    listener->factory.pool = pool;
    listener->factory.type = cfg->af==pj_AF_INET() ? PJSIP_TRANSPORT_TCP :
						     PJSIP_TRANSPORT_TCP6;
    listener->factory.type_name = (char*)
		pjsip_transport_get_type_name(listener->factory.type);
    listener->factory.flag = 
	pjsip_transport_get_flag_from_type(listener->factory.type);
    listener->qos_type = cfg->qos_type;
    pj_memcpy(&listener->qos_params, &cfg->qos_params,
	      sizeof(cfg->qos_params));

    pj_ansi_strcpy(listener->factory.obj_name, "tcplis");
    if (listener->factory.type==PJSIP_TRANSPORT_TCP6)
	pj_ansi_strcat(listener->factory.obj_name, "6");

    status = pj_lock_create_recursive_mutex(pool, listener->factory.obj_name,
					    &listener->factory.lock);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create socket */
    status = pj_sock_socket(cfg->af, pj_SOCK_STREAM(), 0, &sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Apply QoS, if specified */
    status = pj_sock_apply_qos2(sock, cfg->qos_type, &cfg->qos_params, 
				2, listener->factory.obj_name, 
				"SIP TCP listener socket");

    /* Bind address may be different than factory.local_addr because
     * factory.local_addr will be resolved below.
     */
    pj_sockaddr_cp(&listener->bound_addr, &cfg->bind_addr);

    /* Bind socket */
    listener_addr = &listener->factory.local_addr;
    pj_sockaddr_cp(listener_addr, &cfg->bind_addr);

    status = pj_sock_bind(sock, listener_addr, 
			  pj_sockaddr_get_len(listener_addr));
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Retrieve the bound address */
    addr_len = pj_sockaddr_get_len(listener_addr);
    status = pj_sock_getsockname(sock, listener_addr, &addr_len);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* If published host/IP is specified, then use that address as the
     * listener advertised address.
     */
    if (cfg->addr_name.host.slen) {
	/* Copy the address */
	listener->factory.addr_name = cfg->addr_name;
	pj_strdup(listener->factory.pool, &listener->factory.addr_name.host, 
		  &cfg->addr_name.host);
	listener->factory.addr_name.port = cfg->addr_name.port;

    } else {
	/* No published address is given, use the bound address */

	/* If the address returns 0.0.0.0, use the default
	 * interface address as the transport's address.
	 */
	if (!pj_sockaddr_has_addr(listener_addr)) {
	    pj_sockaddr hostip;

	    status = pj_gethostip(listener->bound_addr.addr.sa_family,
	                          &hostip);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    pj_sockaddr_copy_addr(listener_addr, &hostip);
	}

	/* Save the address name */
	sockaddr_to_host_port(listener->factory.pool, 
			      &listener->factory.addr_name, 
			      listener_addr);
    }

    /* If port is zero, get the bound port */
    if (listener->factory.addr_name.port == 0) {
	listener->factory.addr_name.port = pj_sockaddr_get_port(listener_addr);
    }

    pj_ansi_snprintf(listener->factory.obj_name, 
		     sizeof(listener->factory.obj_name),
		     "tcplis:%d",  listener->factory.addr_name.port);


    /* Start listening to the address */
    status = pj_sock_listen(sock, PJSIP_TCP_TRANSPORT_BACKLOG);
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create active socket */
    pj_activesock_cfg_default(&asock_cfg);
    if (cfg->async_cnt > MAX_ASYNC_CNT) 
	asock_cfg.async_cnt = MAX_ASYNC_CNT;
    else
	asock_cfg.async_cnt = cfg->async_cnt;

    pj_bzero(&listener_cb, sizeof(listener_cb));
    listener_cb.on_accept_complete = &on_accept_complete;
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
				  pjsip_endpt_get_ioqueue(endpt), 
				  &listener_cb, listener,
				  &listener->asock);

    /* Register to transport manager */
    listener->endpt = endpt;
    listener->tpmgr = pjsip_endpt_get_tpmgr(endpt);
    listener->factory.create_transport = lis_create_transport;
    listener->factory.destroy = lis_destroy;
    listener->is_registered = PJ_TRUE;
    status = pjsip_tpmgr_register_tpfactory(listener->tpmgr,
					    &listener->factory);
    if (status != PJ_SUCCESS) {
	listener->is_registered = PJ_FALSE;
	goto on_error;
    }

    /* Start pending accept() operations */
    status = pj_activesock_start_accept(listener->asock, pool);
    if (status != PJ_SUCCESS)
	goto on_error;

    PJ_LOG(4,(listener->factory.obj_name, 
	     "SIP TCP listener ready for incoming connections at %.*s:%d",
	     (int)listener->factory.addr_name.host.slen,
	     listener->factory.addr_name.host.ptr,
	     listener->factory.addr_name.port));

    /* Return the pointer to user */
    if (p_factory) *p_factory = &listener->factory;

    return PJ_SUCCESS;

on_error:
    if (listener->asock==NULL && sock!=PJ_INVALID_SOCKET)
	pj_sock_close(sock);
    lis_destroy(&listener->factory);
    return status;
}
コード例 #25
0
ファイル: ssl_sock.c プロジェクト: kaaustubh/pjsip
static int echo_test(pj_ssl_sock_proto srv_proto, pj_ssl_sock_proto cli_proto,
		     pj_ssl_cipher srv_cipher, pj_ssl_cipher cli_cipher,
		     pj_bool_t req_client_cert, pj_bool_t client_provide_cert)
{
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_ssl_sock_t *ssock_serv = NULL;
    pj_ssl_sock_t *ssock_cli = NULL;
    pj_ssl_sock_param param;
    struct test_state state_serv = { 0 };
    struct test_state state_cli = { 0 };
    pj_sockaddr addr, listen_addr;
    pj_ssl_cipher ciphers[1];
    pj_ssl_cert_t *cert = NULL;
    pj_status_t status;

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

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

    pj_ssl_sock_param_default(&param);
    param.cb.on_accept_complete = &ssl_on_accept_complete;
    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.ciphers = ciphers;

    /* Init default bind address */
    {
	pj_str_t tmp_st;
	pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
    }

    /* === SERVER === */
    param.proto = srv_proto;
    param.user_data = &state_serv;
    param.ciphers_num = (srv_cipher == -1)? 0 : 1;
    param.require_client_cert = req_client_cert;
    ciphers[0] = srv_cipher;

    state_serv.pool = pool;
    state_serv.echo = PJ_TRUE;
    state_serv.is_server = PJ_TRUE;
    state_serv.is_verbose = PJ_TRUE;

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

    /* Set server cert */
    {
	pj_str_t tmp1, tmp2, tmp3, tmp4;

	status = pj_ssl_cert_load_from_files(pool, 
					     pj_strset2(&tmp1, (char*)CERT_CA_FILE), 
					     pj_strset2(&tmp2, (char*)CERT_FILE), 
					     pj_strset2(&tmp3, (char*)CERT_PRIVKEY_FILE), 
					     pj_strset2(&tmp4, (char*)CERT_PRIVKEY_PASS), 
					     &cert);
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}

	status = pj_ssl_sock_set_certificate(ssock_serv, pool, cert);
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}
    }

    status = pj_ssl_sock_start_accept(ssock_serv, pool, &addr, pj_sockaddr_get_len(&addr));
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Get listener address */
    {
	pj_ssl_sock_info info;

	pj_ssl_sock_get_info(ssock_serv, &info);
	pj_sockaddr_cp(&listen_addr, &info.local_addr);
    }

    /* === CLIENT === */
    param.proto = cli_proto;
    param.user_data = &state_cli;
    param.ciphers_num = (cli_cipher == -1)? 0 : 1;
    ciphers[0] = cli_cipher;

    state_cli.pool = pool;
    state_cli.check_echo = PJ_TRUE;
    state_cli.is_verbose = PJ_TRUE;

    {
	pj_time_val now;

	pj_gettimeofday(&now);
	pj_srand((unsigned)now.sec);
	state_cli.send_str_len = (pj_rand() % 5 + 1) * 1024 + pj_rand() % 1024;
    }
    state_cli.send_str = pj_pool_alloc(pool, state_cli.send_str_len);
    {
	unsigned i;
	for (i = 0; i < state_cli.send_str_len; ++i)
	    state_cli.send_str[i] = (char)(pj_rand() % 256);
    }

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

    /* Set cert for client */
    {

	if (!client_provide_cert) {
	    pj_str_t tmp1, tmp2;

	    pj_strset2(&tmp1, (char*)CERT_CA_FILE);
	    pj_strset2(&tmp2, NULL);
	    status = pj_ssl_cert_load_from_files(pool, 
						 &tmp1, &tmp2, &tmp2, &tmp2,
						 &cert);
	    if (status != PJ_SUCCESS) {
		goto on_return;
	    }
	}

	status = pj_ssl_sock_set_certificate(ssock_cli, pool, cert);
	if (status != PJ_SUCCESS) {
	    goto on_return;
	}
    }

    status = pj_ssl_sock_start_connect(ssock_cli, pool, &addr, &listen_addr, pj_sockaddr_get_len(&addr));
    if (status == PJ_SUCCESS) {
	ssl_on_connect_complete(ssock_cli, PJ_SUCCESS);
    } else if (status == PJ_EPENDING) {
	status = PJ_SUCCESS;
    } else {
	goto on_return;
    }

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

    /* Clean up sockets */
    {
	pj_time_val delay = {0, 100};
	while (pj_ioqueue_poll(ioqueue, &delay) > 0);
    }

    if (state_serv.err || state_cli.err) {
	if (state_serv.err != PJ_SUCCESS)
	    status = state_serv.err;
	else
	    status = state_cli.err;

	goto on_return;
    }

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

on_return:
    if (ssock_serv)
	pj_ssl_sock_close(ssock_serv);
    if (ssock_cli && !state_cli.err && !state_cli.done) 
	pj_ssl_sock_close(ssock_cli);
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (pool)
	pj_pool_release(pool);

    return status;
}
コード例 #26
0
/**
 * Create UDP stream transport.
 */
PJ_DEF(pj_status_t) pjmedia_transport_udp_create3(pjmedia_endpt *endpt,
						  int af,
						  const char *name,
						  const pj_str_t *addr,
						  int port,
						  unsigned options,
						  pjmedia_transport **p_tp)
{
    pjmedia_sock_info si;
    pj_status_t status;

    
    /* Sanity check */
    PJ_ASSERT_RETURN(endpt && port && p_tp, PJ_EINVAL);


    pj_bzero(&si, sizeof(pjmedia_sock_info));
    si.rtp_sock = si.rtcp_sock = PJ_INVALID_SOCKET;

    /* Create RTP socket */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &si.rtp_sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Bind RTP socket */
    status = pj_sockaddr_init(af, &si.rtp_addr_name, addr, (pj_uint16_t)port);
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_sock_bind(si.rtp_sock, &si.rtp_addr_name, 
			  pj_sockaddr_get_len(&si.rtp_addr_name));
    if (status != PJ_SUCCESS)
	goto on_error;


    /* Create RTCP socket */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &si.rtcp_sock);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Bind RTCP socket */
    status = pj_sockaddr_init(af, &si.rtcp_addr_name, addr, 
			      (pj_uint16_t)(port+1));
    if (status != PJ_SUCCESS)
	goto on_error;

    status = pj_sock_bind(si.rtcp_sock, &si.rtcp_addr_name,
			  pj_sockaddr_get_len(&si.rtcp_addr_name));
    if (status != PJ_SUCCESS)
	goto on_error;

    
    /* Create UDP transport by attaching socket info */
    return pjmedia_transport_udp_attach( endpt, name, &si, options, p_tp);


on_error:
    if (si.rtp_sock != PJ_INVALID_SOCKET)
	pj_sock_close(si.rtp_sock);
    if (si.rtcp_sock != PJ_INVALID_SOCKET)
	pj_sock_close(si.rtcp_sock);
    return status;
}
コード例 #27
0
ファイル: ssl_sock.c プロジェクト: kaaustubh/pjsip
/* SSL socket try to connect to raw TCP socket server, once
 * connection established, SSL socket will try to perform SSL
 * handshake. SSL client socket should be able to close the
 * connection after specified timeout period (set ms_timeout to 
 * 0 to disable timer).
 */
static int server_non_ssl(unsigned ms_timeout)
{
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_timer_heap_t *timer = NULL;
    pj_activesock_t *asock_serv = NULL;
    pj_ssl_sock_t *ssock_cli = NULL;
    pj_activesock_cb asock_cb = { 0 };
    pj_sock_t sock = PJ_INVALID_SOCKET;
    pj_ssl_sock_param param;
    struct test_state state_serv = { 0 };
    struct test_state state_cli = { 0 };
    pj_sockaddr addr, listen_addr;
    pj_status_t status;

    pool = pj_pool_create(mem, "ssl_connect_raw_tcp", 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;
    }

    /* SERVER */
    state_serv.pool = pool;
    state_serv.ioqueue = ioqueue;

    status = pj_sock_socket(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Init bind address */
    {
	pj_str_t tmp_st;
	pj_sockaddr_init(PJ_AF_INET, &listen_addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
    }

    status = pj_sock_bind(sock, (pj_sockaddr_t*)&listen_addr, 
			  pj_sockaddr_get_len((pj_sockaddr_t*)&listen_addr));
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    status = pj_sock_listen(sock, PJ_SOMAXCONN);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    asock_cb.on_accept_complete = &asock_on_accept_complete;
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), NULL, 
				  ioqueue, &asock_cb, &state_serv, &asock_serv);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    status = pj_activesock_start_accept(asock_serv, pool);
    if (status != PJ_SUCCESS)
	goto on_return;

    /* Update listener address */
    {
	int addr_len;

	addr_len = sizeof(listen_addr);
	pj_sock_getsockname(sock, (pj_sockaddr_t*)&listen_addr, &addr_len);
    }

    /* CLIENT */
    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.timer_heap = timer;
    param.timeout.sec = 0;
    param.timeout.msec = ms_timeout;
    pj_time_val_normalize(&param.timeout);
    param.user_data = &state_cli;

    state_cli.pool = pool;
    state_cli.is_server = PJ_FALSE;
    state_cli.is_verbose = PJ_TRUE;

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

    /* Init default bind address */
    {
	pj_str_t tmp_st;
	pj_sockaddr_init(PJ_AF_INET, &addr, pj_strset2(&tmp_st, "127.0.0.1"), 0);
    }

    status = pj_ssl_sock_start_connect(ssock_cli, pool, 
				       (pj_sockaddr_t*)&addr, 
				       (pj_sockaddr_t*)&listen_addr, 
				       pj_sockaddr_get_len(&listen_addr));
    if (status != PJ_EPENDING) {
	goto on_return;
    }

    /* Wait until everything has been sent/received or error */
    while ((!state_serv.err && !state_serv.done) || (!state_cli.err && !state_cli.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_serv.err || state_cli.err) {
	if (state_cli.err != PJ_SUCCESS)
	    status = state_cli.err;
	else
	    status = state_serv.err;

	goto on_return;
    }

    PJ_LOG(3, ("", "...Done!"));

on_return:
    if (asock_serv)
	pj_activesock_close(asock_serv);
    if (ssock_cli && !state_cli.err && !state_cli.done)
	pj_ssl_sock_close(ssock_cli);
    if (timer)
	pj_timer_heap_destroy(timer);
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (pool)
	pj_pool_release(pool);

    return status;
}
コード例 #28
0
ファイル: sip_resolve.c プロジェクト: max3903/SFLphone
/*
 * This is the main function for performing server resolution.
 */
PJ_DEF(void) pjsip_resolve( pjsip_resolver_t *resolver,
			    pj_pool_t *pool,
			    const pjsip_host_info *target,
			    void *token,
			    pjsip_resolver_callback *cb)
{
    pjsip_server_addresses svr_addr;
    pj_status_t status = PJ_SUCCESS;
    int ip_addr_ver;
    struct query *query;
    pjsip_transport_type_e type = target->type;

    /* Is it IP address or hostname? And if it's an IP, which version? */
    ip_addr_ver = get_ip_addr_ver(&target->addr.host);

    /* Set the transport type if not explicitly specified. 
     * RFC 3263 section 4.1 specify rules to set up this.
     */
    if (type == PJSIP_TRANSPORT_UNSPECIFIED) {
	if (ip_addr_ver || (target->addr.port != 0)) {
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	} else {
	    /* No type or explicit port is specified, and the address is
	     * not IP address.
	     * In this case, full NAPTR resolution must be performed.
	     * But we don't support it (yet).
	     */
#if PJ_HAS_TCP
	    if (target->flag & PJSIP_TRANSPORT_SECURE) 
	    {
		type = PJSIP_TRANSPORT_TLS;
	    } else if (target->flag & PJSIP_TRANSPORT_RELIABLE) 
	    {
		type = PJSIP_TRANSPORT_TCP;
	    } else 
#endif
	    {
		type = PJSIP_TRANSPORT_UDP;
	    }
	}

	/* Add IPv6 flag for IPv6 address */
	if (ip_addr_ver == 6)
	    type = (pjsip_transport_type_e)((int)type + PJSIP_TRANSPORT_IPV6);
    }


    /* If target is an IP address, or if resolver is not configured, 
     * we can just finish the resolution now using pj_gethostbyname()
     */
    if (ip_addr_ver || resolver->res == NULL) {
	char addr_str[PJ_INET6_ADDRSTRLEN+10];
	pj_uint16_t srv_port;

	if (ip_addr_ver != 0) {
	    /* Target is an IP address, no need to resolve */
	    if (ip_addr_ver == 4) {
		pj_sockaddr_init(pj_AF_INET(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_aton(&target->addr.host,
			     &svr_addr.entry[0].addr.ipv4.sin_addr);
	    } else {
		pj_sockaddr_init(pj_AF_INET6(), &svr_addr.entry[0].addr, 
				 NULL, 0);
		pj_inet_pton(pj_AF_INET6(), &target->addr.host,
			     &svr_addr.entry[0].addr.ipv6.sin6_addr);
	    }
	} else {
	    pj_addrinfo ai;
	    unsigned count;
	    int af;

	    PJ_LOG(5,(THIS_FILE,
		      "DNS resolver not available, target '%.*s:%d' type=%s "
		      "will be resolved with getaddrinfo()",
		      target->addr.host.slen,
		      target->addr.host.ptr,
		      target->addr.port,
		      pjsip_transport_get_type_name(target->type)));

	    if (type & PJSIP_TRANSPORT_IPV6) {
		af = pj_AF_INET6();
	    } else {
		af = pj_AF_INET();
	    }

	    /* Resolve */
	    count = 1;
	    status = pj_getaddrinfo(af, &target->addr.host, &count, &ai);
	    if (status != PJ_SUCCESS)
		goto on_error;

	    svr_addr.entry[0].addr.addr.sa_family = (pj_uint16_t)af;
	    pj_memcpy(&svr_addr.entry[0].addr, &ai.ai_addr,
		      sizeof(pj_sockaddr));
	}

	/* Set the port number */
	if (target->addr.port == 0) {
	   srv_port = (pj_uint16_t)
		      pjsip_transport_get_default_port_for_type(type);
	} else {
	   srv_port = (pj_uint16_t)target->addr.port;
	}
	pj_sockaddr_set_port(&svr_addr.entry[0].addr, srv_port);

	/* Call the callback. */
	PJ_LOG(5,(THIS_FILE, 
		  "Target '%.*s:%d' type=%s resolved to "
		  "'%s' type=%s (%s)",
		  (int)target->addr.host.slen,
		  target->addr.host.ptr,
		  target->addr.port,
		  pjsip_transport_get_type_name(target->type),
		  pj_sockaddr_print(&svr_addr.entry[0].addr, addr_str,
				    sizeof(addr_str), 3),
		  pjsip_transport_get_type_name(type),
		  pjsip_transport_get_type_desc(type)));
	svr_addr.count = 1;
	svr_addr.entry[0].priority = 0;
	svr_addr.entry[0].weight = 0;
	svr_addr.entry[0].type = type;
	svr_addr.entry[0].addr_len = pj_sockaddr_get_len(&svr_addr.entry[0].addr);
	(*cb)(status, token, &svr_addr);

	/* Done. */
	return;
    }

    /* Target is not an IP address so we need to resolve it. */
#if PJSIP_HAS_RESOLVER

    /* Build the query state */
    query = PJ_POOL_ZALLOC_T(pool, struct query);
    query->objname = THIS_FILE;
    query->token = token;
    query->cb = cb;
    query->req.target = *target;
    pj_strdup(pool, &query->req.target.addr.host, &target->addr.host);

    /* If port is not specified, start with SRV resolution
     * (should be with NAPTR, but we'll do that later)
     */
    PJ_TODO(SUPPORT_DNS_NAPTR);

    /* Build dummy NAPTR entry */
    query->naptr_cnt = 1;
    pj_bzero(&query->naptr[0], sizeof(query->naptr[0]));
    query->naptr[0].order = 0;
    query->naptr[0].pref = 0;
    query->naptr[0].type = type;
    pj_strdup(pool, &query->naptr[0].name, &target->addr.host);


    /* Start DNS SRV or A resolution, depending on whether port is specified */
    if (target->addr.port == 0) {
	query->query_type = PJ_DNS_TYPE_SRV;

	query->req.def_port = 5060;

	if (type == PJSIP_TRANSPORT_TLS) {
	    query->naptr[0].res_type = pj_str("_sips._tcp.");
	    query->req.def_port = 5061;
	} else if (type == PJSIP_TRANSPORT_TCP)
	    query->naptr[0].res_type = pj_str("_sip._tcp.");
	else if (type == PJSIP_TRANSPORT_UDP)
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	else {
	    pj_assert(!"Unknown transport type");
	    query->naptr[0].res_type = pj_str("_sip._udp.");
	    
	}

    } else {
	/* Otherwise if port is specified, start with A (or AAAA) host 
	 * resolution 
	 */
	query->query_type = PJ_DNS_TYPE_A;
	query->naptr[0].res_type.slen = 0;
	query->req.def_port = target->addr.port;
    }

    /* Start the asynchronous query */
    PJ_LOG(5, (query->objname, 
	       "Starting async DNS %s query: target=%.*s%.*s, transport=%s, "
	       "port=%d",
	       pj_dns_get_type_name(query->query_type),
	       (int)query->naptr[0].res_type.slen,
	       query->naptr[0].res_type.ptr,
	       (int)query->naptr[0].name.slen, query->naptr[0].name.ptr,
	       pjsip_transport_get_type_name(target->type),
	       target->addr.port));

    if (query->query_type == PJ_DNS_TYPE_SRV) {

    		unsigned option = PJ_TRUE;
    	        if (type & PJSIP_TRANSPORT_IPV6) {
    	            option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV6;
    	        } else {
    	            option |= PJ_DNS_SRV_FALLBACK_GETADDRINFO_IPV4;
    	        }

    	        status = pj_dns_srv_resolve(&query->naptr[0].name,
    	        			    &query->naptr[0].res_type,
    	        			    query->req.def_port, pool, resolver->res,
    	        			    option, query, &srv_resolver_cb, NULL);

    } else if (query->query_type == PJ_DNS_TYPE_A) {

    	 status = pj_dns_resolver_start_query(resolver->res,
					     &query->naptr[0].name,
					     PJ_DNS_TYPE_A, 0, 
					     &dns_a_callback,
    					     query, &query->object);

    } else {
	pj_assert(!"Unexpected");
	status = PJ_EBUG;
    }

    if (status != PJ_SUCCESS)
	goto on_error;

    return;

#else /* PJSIP_HAS_RESOLVER */
    PJ_UNUSED_ARG(pool);
    PJ_UNUSED_ARG(query);
    PJ_UNUSED_ARG(srv_name);
#endif /* PJSIP_HAS_RESOLVER */

on_error:
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	PJ_LOG(4,(THIS_FILE, "Failed to resolve '%.*s'. Err=%d (%s)",
			     (int)target->addr.host.slen,
			     target->addr.host.ptr,
			     status,
			     pj_strerror(status,errmsg,sizeof(errmsg)).ptr));
	(*cb)(status, token, NULL);
	return;
    }
}
コード例 #29
0
ファイル: allocation.c プロジェクト: RyanLee27/pjproject
/*
 * Create relay.
 */
static pj_status_t create_relay(pj_turn_srv *srv,
				pj_turn_allocation *alloc,
				const pj_stun_msg *msg,
				const alloc_request *req,
				pj_turn_relay_res *relay)
{
    enum { RETRY = 40 };
    pj_pool_t *pool = alloc->pool;
    int retry, retry_max, sock_type;
    pj_ioqueue_callback icb;
    int af, namelen;
    pj_stun_string_attr *sa;
    pj_status_t status;

    pj_bzero(relay, sizeof(*relay));

    relay->allocation = alloc;
    relay->tp.sock = PJ_INVALID_SOCKET;

    /* TODO: get the requested address family from somewhere */
    af = alloc->transport->listener->addr.addr.sa_family;

    /* Save realm */
    sa = (pj_stun_string_attr*)
	 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REALM, 0);
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
    pj_strdup(pool, &relay->realm, &sa->value);

    /* Save username */
    sa = (pj_stun_string_attr*)
	 pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_USERNAME, 0);
    PJ_ASSERT_RETURN(sa, PJ_EINVALIDOP);
    pj_strdup(pool, &relay->user, &sa->value);

    /* Lifetime and timeout */
    relay->lifetime = req->lifetime;
    pj_timer_entry_init(&relay->timer, TIMER_ID_NONE, relay,
			&relay_timeout_cb);
    resched_timeout(alloc);

    /* Transport type */
    relay->hkey.tp_type = req->tp_type;

    /* Create the socket */
    if (req->tp_type == PJ_TURN_TP_UDP) {
	sock_type = pj_SOCK_DGRAM();
    } else if (req->tp_type == PJ_TURN_TP_TCP) {
	sock_type = pj_SOCK_STREAM();
    } else {
	pj_assert(!"Unknown transport");
	return PJ_EINVALIDOP;
    }

    status = pj_sock_socket(af, sock_type, 0, &relay->tp.sock);
    if (status != PJ_SUCCESS) {
	pj_bzero(relay, sizeof(*relay));
	return status;
    }

    /* Find suitable port for this allocation */
    if (req->rpp_port) {
	retry_max = 1;
    } else {
	retry_max = RETRY;
    }

    for (retry=0; retry<retry_max; ++retry) {
	pj_uint16_t port;
	pj_sockaddr bound_addr;

	pj_lock_acquire(srv->core.lock);

	if (req->rpp_port) {
	    port = (pj_uint16_t) req->rpp_port;
	} else if (req->tp_type == PJ_TURN_TP_UDP) {
	    port = (pj_uint16_t) srv->ports.next_udp++;
	    if (srv->ports.next_udp > srv->ports.max_udp)
		srv->ports.next_udp = srv->ports.min_udp;
	} else if (req->tp_type == PJ_TURN_TP_TCP) {
	    port = (pj_uint16_t) srv->ports.next_tcp++;
	    if (srv->ports.next_tcp > srv->ports.max_tcp)
		srv->ports.next_tcp = srv->ports.min_tcp;
	} else {
	    pj_assert(!"Invalid transport");
	    port = 0;
	}

	pj_lock_release(srv->core.lock);

	pj_sockaddr_init(af, &bound_addr, NULL, port);

	status = pj_sock_bind(relay->tp.sock, &bound_addr,
			      pj_sockaddr_get_len(&bound_addr));
	if (status == PJ_SUCCESS)
	    break;
    }

    if (status != PJ_SUCCESS) {
	/* Unable to allocate port */
	PJ_LOG(4,(THIS_FILE, "Unable to allocate relay, giving up: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }

    /* Init relay key */
    namelen = sizeof(relay->hkey.addr);
    status = pj_sock_getsockname(relay->tp.sock, &relay->hkey.addr, &namelen);
    if (status != PJ_SUCCESS) {
	PJ_LOG(4,(THIS_FILE, "pj_sock_getsockname() failed: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
	pj_sockaddr_copy_addr(&relay->hkey.addr,
			      &alloc->transport->listener->addr);
    }
    if (!pj_sockaddr_has_addr(&relay->hkey.addr)) {
	pj_sockaddr tmp_addr;
	pj_gethostip(af, &tmp_addr);
	pj_sockaddr_copy_addr(&relay->hkey.addr, &tmp_addr);
    }

    /* Init ioqueue */
    pj_bzero(&icb, sizeof(icb));
    icb.on_read_complete = &on_rx_from_peer;

    status = pj_ioqueue_register_sock(pool, srv->core.ioqueue, relay->tp.sock,
				      relay, &icb, &relay->tp.key);
    if (status != PJ_SUCCESS) {
	PJ_LOG(4,(THIS_FILE, "pj_ioqueue_register_sock() failed: err %d",
		  status));
	pj_sock_close(relay->tp.sock);
	relay->tp.sock = PJ_INVALID_SOCKET;
	return status;
    }

    /* Kick off pending read operation */
    pj_ioqueue_op_key_init(&relay->tp.read_key, sizeof(relay->tp.read_key));
    on_rx_from_peer(relay->tp.key, &relay->tp.read_key, 0);

    /* Done */
    return PJ_SUCCESS;
}
コード例 #30
0
ファイル: turn_sock.c プロジェクト: 0x0B501E7E/pjproject
/*
 * Callback from TURN session when state has changed
 */
static void turn_on_state(pj_turn_session *sess, 
			  pj_turn_state_t old_state,
			  pj_turn_state_t new_state)
{
    pj_turn_sock *turn_sock = (pj_turn_sock*) 
			   pj_turn_session_get_user_data(sess);
    pj_status_t status;

    if (turn_sock == NULL) {
	/* We've been destroyed */
	return;
    }

    /* Notify app first */
    if (turn_sock->cb.on_state) {
	(*turn_sock->cb.on_state)(turn_sock, old_state, new_state);
    }

    /* Make sure user hasn't destroyed us in the callback */
    if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
	pj_turn_session_info info;
	pj_turn_session_get_info(turn_sock->sess, &info);
	new_state = info.state;
    }

    if (turn_sock->sess && new_state == PJ_TURN_STATE_RESOLVED) {
	/*
	 * Once server has been resolved, initiate outgoing TCP
	 * connection to the server.
	 */
	pj_turn_session_info info;
	char addrtxt[PJ_INET6_ADDRSTRLEN+8];
	int sock_type;
	pj_sock_t sock;
	pj_activesock_cfg asock_cfg;
	pj_activesock_cb asock_cb;
	pj_sockaddr bound_addr, *cfg_bind_addr;
	pj_uint16_t max_bind_retry;

	/* Close existing connection, if any. This happens when
	 * we're switching to alternate TURN server when either TCP
	 * connection or ALLOCATE request failed.
	 */
	if (turn_sock->active_sock) {
	    pj_activesock_close(turn_sock->active_sock);
	    turn_sock->active_sock = NULL;
	}

	/* Get server address from session info */
	pj_turn_session_get_info(sess, &info);

	if (turn_sock->conn_type == PJ_TURN_TP_UDP)
	    sock_type = pj_SOCK_DGRAM();
	else
	    sock_type = pj_SOCK_STREAM();

	/* Init socket */
	status = pj_sock_socket(turn_sock->af, sock_type, 0, &sock);
	if (status != PJ_SUCCESS) {
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	/* Bind socket */
	cfg_bind_addr = &turn_sock->setting.bound_addr;
	max_bind_retry = MAX_BIND_RETRY;
	if (turn_sock->setting.port_range &&
	    turn_sock->setting.port_range < max_bind_retry)
	{
	    max_bind_retry = turn_sock->setting.port_range;
	}
	pj_sockaddr_init(turn_sock->af, &bound_addr, NULL, 0);
	if (cfg_bind_addr->addr.sa_family == pj_AF_INET() || 
	    cfg_bind_addr->addr.sa_family == pj_AF_INET6())
	{
	    pj_sockaddr_cp(&bound_addr, cfg_bind_addr);
	}
	status = pj_sock_bind_random(sock, &bound_addr,
				     turn_sock->setting.port_range,
				     max_bind_retry);
	if (status != PJ_SUCCESS) {
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	/* Apply QoS, if specified */
	status = pj_sock_apply_qos2(sock, turn_sock->setting.qos_type,
				    &turn_sock->setting.qos_params, 
				    (turn_sock->setting.qos_ignore_error?2:1),
				    turn_sock->pool->obj_name, NULL);
	if (status != PJ_SUCCESS && !turn_sock->setting.qos_ignore_error) {
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	/* Apply socket buffer size */
	if (turn_sock->setting.so_rcvbuf_size > 0) {
	    unsigned sobuf_size = turn_sock->setting.so_rcvbuf_size;
	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_RCVBUF(),
					      PJ_TRUE, &sobuf_size);
	    if (status != PJ_SUCCESS) {
		pj_perror(3, turn_sock->obj_name, status,
			  "Failed setting SO_RCVBUF");
	    } else {
		if (sobuf_size < turn_sock->setting.so_rcvbuf_size) {
		    PJ_LOG(4, (turn_sock->obj_name, 
			       "Warning! Cannot set SO_RCVBUF as configured,"
			       " now=%d, configured=%d", sobuf_size,
			       turn_sock->setting.so_rcvbuf_size));
		} else {
		    PJ_LOG(5, (turn_sock->obj_name, "SO_RCVBUF set to %d",
			       sobuf_size));
		}
	    }
	}
	if (turn_sock->setting.so_sndbuf_size > 0) {
	    unsigned sobuf_size = turn_sock->setting.so_sndbuf_size;
	    status = pj_sock_setsockopt_sobuf(sock, pj_SO_SNDBUF(),
					      PJ_TRUE, &sobuf_size);
	    if (status != PJ_SUCCESS) {
		pj_perror(3, turn_sock->obj_name, status,
			  "Failed setting SO_SNDBUF");
	    } else {
		if (sobuf_size < turn_sock->setting.so_sndbuf_size) {
		    PJ_LOG(4, (turn_sock->obj_name, 
			       "Warning! Cannot set SO_SNDBUF as configured,"
			       " now=%d, configured=%d", sobuf_size,
			       turn_sock->setting.so_sndbuf_size));
		} else {
		    PJ_LOG(5, (turn_sock->obj_name, "SO_SNDBUF set to %d",
			       sobuf_size));
		}
	    }
	}

	/* Create active socket */
	pj_activesock_cfg_default(&asock_cfg);
	asock_cfg.grp_lock = turn_sock->grp_lock;

	pj_bzero(&asock_cb, sizeof(asock_cb));
	asock_cb.on_data_read = &on_data_read;
	asock_cb.on_connect_complete = &on_connect_complete;
	status = pj_activesock_create(turn_sock->pool, sock,
				      sock_type, &asock_cfg,
				      turn_sock->cfg.ioqueue, &asock_cb, 
				      turn_sock,
				      &turn_sock->active_sock);
	if (status != PJ_SUCCESS) {
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}

	PJ_LOG(5,(turn_sock->pool->obj_name,
		  "Connecting to %s", 
		  pj_sockaddr_print(&info.server, addrtxt, 
				    sizeof(addrtxt), 3)));

	/* Initiate non-blocking connect */
#if PJ_HAS_TCP
	status=pj_activesock_start_connect(turn_sock->active_sock, 
					   turn_sock->pool,
					   &info.server, 
					   pj_sockaddr_get_len(&info.server));
	if (status == PJ_SUCCESS) {
	    on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
	} else if (status != PJ_EPENDING) {
	    pj_turn_sock_destroy(turn_sock);
	    return;
	}
#else
	on_connect_complete(turn_sock->active_sock, PJ_SUCCESS);
#endif

	/* Done for now. Subsequent work will be done in 
	 * on_connect_complete() callback.
	 */
    }

    if (new_state >= PJ_TURN_STATE_DESTROYING && turn_sock->sess) {
	pj_time_val delay = {0, 0};

	turn_sock->sess = NULL;
	pj_turn_session_set_user_data(sess, NULL);

	pj_timer_heap_cancel_if_active(turn_sock->cfg.timer_heap,
	                               &turn_sock->timer, 0);
	pj_timer_heap_schedule_w_grp_lock(turn_sock->cfg.timer_heap,
	                                  &turn_sock->timer,
	                                  &delay, TIMER_DESTROY,
	                                  turn_sock->grp_lock);
    }
}