Пример #1
0
/* 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;
}
Пример #2
0
/*
 * Create the STUN transport using the specified configuration.
 */
PJ_DEF(pj_status_t) pj_stun_sock_create( pj_stun_config *stun_cfg,
					 const char *name,
					 int af,
					 const pj_stun_sock_cb *cb,
					 const pj_stun_sock_cfg *cfg,
					 void *user_data,
					 pj_stun_sock **p_stun_sock)
{
    pj_pool_t *pool;
    pj_stun_sock *stun_sock;
    pj_stun_sock_cfg default_cfg;
    unsigned i;
    pj_status_t status;

    PJ_ASSERT_RETURN(stun_cfg && cb && p_stun_sock, PJ_EINVAL);
    PJ_ASSERT_RETURN(af==pj_AF_INET()||af==pj_AF_INET6(), PJ_EAFNOTSUP);
    PJ_ASSERT_RETURN(!cfg || pj_stun_sock_cfg_is_valid(cfg), PJ_EINVAL);
    PJ_ASSERT_RETURN(cb->on_status, PJ_EINVAL);

    status = pj_stun_config_check_valid(stun_cfg);
    if (status != PJ_SUCCESS)
	return status;

    if (name == NULL)
	name = "stuntp%p";

    if (cfg == NULL) {
	pj_stun_sock_cfg_default(&default_cfg);
	cfg = &default_cfg;
    }


    /* Create structure */
    pool = pj_pool_create(stun_cfg->pf, name, 256, 512, NULL);
    stun_sock = PJ_POOL_ZALLOC_T(pool, pj_stun_sock);
    stun_sock->pool = pool;
    stun_sock->obj_name = pool->obj_name;
    stun_sock->user_data = user_data;
    stun_sock->af = af;
    stun_sock->sock_fd = PJ_INVALID_SOCKET;
    pj_memcpy(&stun_sock->stun_cfg, stun_cfg, sizeof(*stun_cfg));
    pj_memcpy(&stun_sock->cb, cb, sizeof(*cb));

    stun_sock->ka_interval = cfg->ka_interval;
    if (stun_sock->ka_interval == 0)
	stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;

    /* Create socket and bind socket */
    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd);
    if (status != PJ_SUCCESS)
	goto on_error;

    /* Apply QoS, if specified */
    status = pj_sock_apply_qos2(stun_sock->sock_fd, cfg->qos_type,
				&cfg->qos_params, 2, stun_sock->obj_name,
				NULL);
    if (status != PJ_SUCCESS && !cfg->qos_ignore_error)
	goto on_error;

    /* Bind socket */
    if (pj_sockaddr_has_addr(&cfg->bound_addr)) {
	status = pj_sock_bind(stun_sock->sock_fd, &cfg->bound_addr,
			      pj_sockaddr_get_len(&cfg->bound_addr));
    } else {
	pj_sockaddr bound_addr;

	pj_sockaddr_init(af, &bound_addr, NULL, 0);
	status = pj_sock_bind(stun_sock->sock_fd, &bound_addr,
			      pj_sockaddr_get_len(&bound_addr));
    }

    if (status != PJ_SUCCESS)
	goto on_error;

    /* Create more useful information string about this transport */
#if 0
    {
	pj_sockaddr bound_addr;
	int addr_len = sizeof(bound_addr);

	status = pj_sock_getsockname(stun_sock->sock_fd, &bound_addr, 
				     &addr_len);
	if (status != PJ_SUCCESS)
	    goto on_error;

	stun_sock->info = pj_pool_alloc(pool, PJ_INET6_ADDRSTRLEN+10);
	pj_sockaddr_print(&bound_addr, stun_sock->info, 
			  PJ_INET6_ADDRSTRLEN, 3);
    }
#endif

    /* Init active socket configuration */
    {
	pj_activesock_cfg activesock_cfg;
	pj_activesock_cb activesock_cb;

	pj_activesock_cfg_default(&activesock_cfg);
	activesock_cfg.async_cnt = cfg->async_cnt;
	activesock_cfg.concurrency = 0;

	/* Create the active socket */
	pj_bzero(&activesock_cb, sizeof(activesock_cb));
	activesock_cb.on_data_recvfrom = &on_data_recvfrom;
	activesock_cb.on_data_sent = &on_data_sent;
	status = pj_activesock_create(pool, stun_sock->sock_fd, 
				      pj_SOCK_DGRAM(), 
				      &activesock_cfg, stun_cfg->ioqueue,
				      &activesock_cb, stun_sock,
				      &stun_sock->active_sock);
	if (status != PJ_SUCCESS)
	    goto on_error;

	/* Start asynchronous read operations */
	status = pj_activesock_start_recvfrom(stun_sock->active_sock, pool,
					      cfg->max_pkt_size, 0);
	if (status != PJ_SUCCESS)
	    goto on_error;

	/* Init send keys */
	pj_ioqueue_op_key_init(&stun_sock->send_key, 
			       sizeof(stun_sock->send_key));
	pj_ioqueue_op_key_init(&stun_sock->int_send_key,
			       sizeof(stun_sock->int_send_key));
    }

    /* Create STUN session */
    {
	pj_stun_session_cb sess_cb;

	pj_bzero(&sess_cb, sizeof(sess_cb));
	sess_cb.on_request_complete = &sess_on_request_complete;
	sess_cb.on_send_msg = &sess_on_send_msg;
	status = pj_stun_session_create(&stun_sock->stun_cfg, 
					stun_sock->obj_name,
					&sess_cb, PJ_FALSE, 
					&stun_sock->stun_sess);
	if (status != PJ_SUCCESS)
	    goto on_error;
    }

    /* Associate us with the STUN session */
    pj_stun_session_set_user_data(stun_sock->stun_sess, stun_sock);

    /* Initialize random numbers to be used as STUN transaction ID for
     * outgoing Binding request. We use the 80bit number to distinguish
     * STUN messages we sent with STUN messages that the application sends.
     * The last 16bit value in the array is a counter.
     */
    for (i=0; i<PJ_ARRAY_SIZE(stun_sock->tsx_id); ++i) {
	stun_sock->tsx_id[i] = (pj_uint16_t) pj_rand();
    }
    stun_sock->tsx_id[5] = 0;


    /* Init timer entry */
    stun_sock->ka_timer.cb = &ka_timer_cb;
    stun_sock->ka_timer.user_data = stun_sock;

    /* Done */
    *p_stun_sock = stun_sock;
    return PJ_SUCCESS;

on_error:
    pj_stun_sock_destroy(stun_sock);
    return status;
}
Пример #3
0
static int tcp_perf_test(void)
{
    enum { COUNT=10000 };
    pj_pool_t *pool = NULL;
    pj_ioqueue_t *ioqueue = NULL;
    pj_sock_t sock1=PJ_INVALID_SOCKET, sock2=PJ_INVALID_SOCKET;
    pj_activesock_t *asock1 = NULL, *asock2 = NULL;
    pj_activesock_cb cb;
    struct tcp_state *state1, *state2;
    unsigned i;
    pj_status_t status;

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

    status = app_socketpair(pj_AF_INET(), pj_SOCK_STREAM(), 0, &sock1, 
			    &sock2);
    if (status != PJ_SUCCESS) {
	status = -100;
	goto on_return;
    }

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

    pj_bzero(&cb, sizeof(cb));
    cb.on_data_read = &tcp_on_data_read;
    cb.on_data_sent = &tcp_on_data_sent;

    state1 = PJ_POOL_ZALLOC_T(pool, struct tcp_state);
    status = pj_activesock_create(pool, sock1, pj_SOCK_STREAM(), NULL, ioqueue,
				  &cb, state1, &asock1);
    if (status != PJ_SUCCESS) {
	status = -120;
	goto on_return;
    }

    state2 = PJ_POOL_ZALLOC_T(pool, struct tcp_state);
    status = pj_activesock_create(pool, sock2, pj_SOCK_STREAM(), NULL, ioqueue,
				  &cb, state2, &asock2);
    if (status != PJ_SUCCESS) {
	status = -130;
	goto on_return;
    }

    status = pj_activesock_start_read(asock1, pool, 1000, 0);
    if (status != PJ_SUCCESS) {
	status = -140;
	goto on_return;
    }

    /* Send packet as quickly as possible */
    for (i=0; i<COUNT && !state1->err && !state2->err; ++i) {
	struct tcp_pkt *pkt;
	struct send_key send_key[2], *op_key;
	pj_ssize_t len;

	pkt = (struct tcp_pkt*)state2->pkt;
	pkt->signature = SIGNATURE;
	pkt->seq = i;
	pj_memset(pkt->fill, 'a', sizeof(pkt->fill));

	op_key = &send_key[i%2];
	pj_ioqueue_op_key_init(&op_key->op_key, sizeof(*op_key));

	state2->sent = PJ_FALSE;
	len = sizeof(*pkt);
	status = pj_activesock_send(asock2, &op_key->op_key, pkt, &len, 0);
	if (status == PJ_EPENDING) {
	    do {
#if PJ_SYMBIAN
		pj_symbianos_poll(-1, -1);
#else
		pj_ioqueue_poll(ioqueue, NULL);
#endif
	    } while (!state2->sent);
	} else {
#if PJ_SYMBIAN
		/* The Symbian socket always returns PJ_SUCCESS for TCP send,
		 * eventhough the remote end hasn't received the data yet.
		 * If we continue sending, eventually send() will block,
		 * possibly because the send buffer is full. So we need to
		 * poll the ioqueue periodically, to let receiver gets the 
		 * data.
		 */
		pj_symbianos_poll(-1, 0);
#endif
		if (status != PJ_SUCCESS) {
		    PJ_LOG(1,("", "   err: send status=%d", status));
		    status = -180;
		    break;
		} else if (status == PJ_SUCCESS) {
		    if (len != sizeof(*pkt)) {
			PJ_LOG(1,("", "   err: shouldn't report partial sent"));
			status = -190;
			break;
		    }
		}
	}

#ifndef PJ_SYMBIAN
	for (;;) {
	    pj_time_val timeout = {0, 10};
	    if (pj_ioqueue_poll(ioqueue, &timeout) < 1)
		break;
	}
#endif

    }

    /* Wait until everything has been sent/received */
    if (state1->next_recv_seq < COUNT) {
#ifdef PJ_SYMBIAN
	while (pj_symbianos_poll(-1, 1000) == PJ_TRUE)
	    ;
#else
	pj_time_val delay = {0, 100};
	while (pj_ioqueue_poll(ioqueue, &delay) > 0)
	    ;
#endif
    }

    if (status == PJ_EPENDING)
	status = PJ_SUCCESS;

    if (status != 0)
	goto on_return;

    if (state1->err) {
	status = -183;
	goto on_return;
    }
    if (state2->err) {
	status = -186;
	goto on_return;
    }
    if (state1->next_recv_seq != COUNT) {
	PJ_LOG(3,("", "   err: only %u packets received, expecting %u", 
		      state1->next_recv_seq, COUNT));
	status = -195;
	goto on_return;
    }

on_return:
    if (asock2)
	pj_activesock_close(asock2);
    if (asock1)
	pj_activesock_close(asock1);
    if (ioqueue)
	pj_ioqueue_destroy(ioqueue);
    if (pool)
	pj_pool_release(pool);

    return status;
}
Пример #4
0
/*
 * Common function to create TCP transport, called when pending accept() and
 * pending connect() complete.
 */
static pj_status_t tcp_create( struct tcp_listener *listener,
			       pj_pool_t *pool,
			       pj_sock_t sock, pj_bool_t is_server,
			       const pj_sockaddr *local,
			       const pj_sockaddr *remote,
			       struct tcp_transport **p_tcp)
{
    struct tcp_transport *tcp;
    pj_ioqueue_t *ioqueue;
    pj_activesock_cfg asock_cfg;
    pj_activesock_cb tcp_callback;
    const pj_str_t ka_pkt = PJSIP_TCP_KEEP_ALIVE_DATA;
    char print_addr[PJ_INET6_ADDRSTRLEN+10];
    pj_status_t status;
    

    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_EINVAL);


    if (pool == NULL) {
	pool = pjsip_endpt_create_pool(listener->endpt, "tcp",
				       POOL_TP_INIT, POOL_TP_INC);
	PJ_ASSERT_RETURN(pool != NULL, PJ_ENOMEM);
    }    

    /*
     * Create and initialize basic transport structure.
     */
    tcp = PJ_POOL_ZALLOC_T(pool, struct tcp_transport);
    tcp->is_server = is_server;
    tcp->sock = sock;
    /*tcp->listener = listener;*/
    pj_list_init(&tcp->delayed_list);
    tcp->base.pool = pool;

    pj_ansi_snprintf(tcp->base.obj_name, PJ_MAX_OBJ_NAME, 
		     (is_server ? "tcps%p" :"tcpc%p"), tcp);

    status = pj_atomic_create(pool, 0, &tcp->base.ref_cnt);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    status = pj_lock_create_recursive_mutex(pool, "tcp", &tcp->base.lock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tcp->base.key.type = listener->factory.type;
    pj_sockaddr_cp(&tcp->base.key.rem_addr, remote);
    tcp->base.type_name = (char*)pjsip_transport_get_type_name(
				(pjsip_transport_type_e)tcp->base.key.type);
    tcp->base.flag = pjsip_transport_get_flag_from_type(
				(pjsip_transport_type_e)tcp->base.key.type);

    tcp->base.info = (char*) pj_pool_alloc(pool, 64);
    pj_ansi_snprintf(tcp->base.info, 64, "%s to %s",
                     tcp->base.type_name,
                     pj_sockaddr_print(remote, print_addr,
                                       sizeof(print_addr), 3));

    tcp->base.addr_len = pj_sockaddr_get_len(remote);
    pj_sockaddr_cp(&tcp->base.local_addr, local);
    sockaddr_to_host_port(pool, &tcp->base.local_name, local);
    sockaddr_to_host_port(pool, &tcp->base.remote_name, remote);
    tcp->base.dir = is_server? PJSIP_TP_DIR_INCOMING : PJSIP_TP_DIR_OUTGOING;

    tcp->base.endpt = listener->endpt;
    tcp->base.tpmgr = listener->tpmgr;
    tcp->base.send_msg = &tcp_send_msg;
    tcp->base.do_shutdown = &tcp_shutdown;
    tcp->base.destroy = &tcp_destroy_transport;

    /* Create group lock */
    status = pj_grp_lock_create(pool, NULL, &tcp->grp_lock);
    if (status != PJ_SUCCESS)
	goto on_error;

    pj_grp_lock_add_ref(tcp->grp_lock);
    pj_grp_lock_add_handler(tcp->grp_lock, pool, tcp, &tcp_on_destroy);

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

    pj_bzero(&tcp_callback, sizeof(tcp_callback));
    tcp_callback.on_data_read = &on_data_read;
    tcp_callback.on_data_sent = &on_data_sent;
    tcp_callback.on_connect_complete = &on_connect_complete;

    ioqueue = pjsip_endpt_get_ioqueue(listener->endpt);
    status = pj_activesock_create(pool, sock, pj_SOCK_STREAM(), &asock_cfg,
				  ioqueue, &tcp_callback, tcp, &tcp->asock);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    /* Register transport to transport manager */
    status = pjsip_transport_register(listener->tpmgr, &tcp->base);
    if (status != PJ_SUCCESS) {
	goto on_error;
    }

    tcp->is_registered = PJ_TRUE;

    /* Initialize keep-alive timer */
    tcp->ka_timer.user_data = (void*)tcp;
    tcp->ka_timer.cb = &tcp_keep_alive_timer;
    pj_ioqueue_op_key_init(&tcp->ka_op_key.key, sizeof(pj_ioqueue_op_key_t));
    pj_strdup(tcp->base.pool, &tcp->ka_pkt, &ka_pkt);

    /* Done setting up basic transport. */
    *p_tcp = tcp;

    PJ_LOG(4,(tcp->base.obj_name, "TCP %s transport created",
	      (tcp->is_server ? "server" : "client")));

    return PJ_SUCCESS;

on_error:
    tcp_destroy(&tcp->base, status);
    return status;
}
Пример #5
0
/*
 * 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_bool_t has_listener = PJ_FALSE;
    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, "tcptp", 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_memcpy(&listener->sockopt_params, &cfg->sockopt_params,
	      sizeof(cfg->sockopt_params));

    pj_ansi_strcpy(listener->factory.obj_name, "tcptp");
    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;

#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)

    /* 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");

    /* Apply SO_REUSEADDR */
    if (cfg->reuse_addr) {
	int enabled = 1;
	status = pj_sock_setsockopt(sock, pj_SOL_SOCKET(), pj_SO_REUSEADDR(),
				    &enabled, sizeof(enabled));
	if (status != PJ_SUCCESS) {
	    PJ_PERROR(4,(listener->factory.obj_name, status,
		         "Warning: error applying SO_REUSEADDR"));
	}
    }

    /* Apply socket options, if specified */
    if (cfg->sockopt_params.cnt)
	status = pj_sock_setsockopt_params(sock, &cfg->sockopt_params);

#else
    PJ_UNUSED_ARG(addr_len);
#endif

    /* 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);

#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)

    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;

#endif

    /* 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),
		     "tcptp:%d",  listener->factory.addr_name.port);


#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)

    /* 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;

#endif

    /* Create group lock */
    status = pj_grp_lock_create(pool, NULL, &listener->grp_lock);
    if (status != PJ_SUCCESS)
	return status;

    pj_grp_lock_add_ref(listener->grp_lock);
    pj_grp_lock_add_handler(listener->grp_lock, pool, listener,
			    &lis_on_destroy);

    asock_cfg.grp_lock = listener->grp_lock;

    pj_bzero(&listener_cb, sizeof(listener_cb));
    listener_cb.on_accept_complete = &on_accept_complete;

#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)

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

#endif

    /* 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;
    }

#if !(defined(PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER) && \
      PJSIP_TCP_TRANSPORT_DONT_CREATE_LISTENER != 0)

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

#endif

    if (has_listener) {
        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));
    } else {
	PJ_LOG(4,(listener->factory.obj_name, "SIP TCP is ready "
		  "(client only)"));    
    }

    /* 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;
}
Пример #6
0
/* 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;
}