Пример #1
0
/* Callback from active socket about send status */
static pj_bool_t on_data_sent(pj_activesock_t *asock,
			      pj_ioqueue_op_key_t *send_key,
			      pj_ssize_t sent)
{
    pj_stun_sock *stun_sock;

    stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);

    /* Don't report to callback if this is internal message */
    if (send_key == &stun_sock->int_send_key) {
	return PJ_TRUE;
    }

    /* Report to callback */
    if (stun_sock->cb.on_data_sent) {
	pj_bool_t ret;

	/* If app gives NULL send_key in sendto() function, then give
	 * NULL in the callback too 
	 */
	if (send_key == &stun_sock->send_key)
	    send_key = NULL;

	/* Call callback */
	ret = (*stun_sock->cb.on_data_sent)(stun_sock, send_key, sent);

	return ret;
    }

    return PJ_TRUE;
}
Пример #2
0
/*
 * Notification when outgoing TCP socket has been connected.
 */
static pj_bool_t on_connect_complete(pj_activesock_t *asock,
				     pj_status_t status)
{
    pj_turn_sock *turn_sock;

    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);

    if (status != PJ_SUCCESS) {
	sess_fail(turn_sock, "TCP connect() error", status);
	return PJ_FALSE;
    }

    if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
	PJ_LOG(5,(turn_sock->obj_name, "TCP connected"));
    }

    /* Kick start pending read operation */
    status = pj_activesock_start_read(asock, turn_sock->pool, 
				      PJ_TURN_MAX_PKT_LEN, 0);

    /* Init send_key */
    pj_ioqueue_op_key_init(&turn_sock->send_key, sizeof(turn_sock->send_key));

    /* Send Allocate request */
    status = pj_turn_session_alloc(turn_sock->sess, &turn_sock->alloc_param);
    if (status != PJ_SUCCESS) {
	sess_fail(turn_sock, "Error sending ALLOCATE", status);
	return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #3
0
static pj_bool_t asock_on_data_read(pj_activesock_t *asock,
				    void *data,
				    pj_size_t size,
				    pj_status_t status,
				    pj_size_t *remainder)
{
    struct test_state *st = (struct test_state*)
			     pj_activesock_get_user_data(asock);

    PJ_UNUSED_ARG(data);
    PJ_UNUSED_ARG(size);
    PJ_UNUSED_ARG(remainder);

    if (status != PJ_SUCCESS) {
	if (status == PJ_EEOF) {
	    status = PJ_SUCCESS;
	    st->done = PJ_TRUE;
	} else {
	    app_perror("...ERROR asock_on_data_read()", status);
	}
    }

    st->err = status;

    if (st->err != PJ_SUCCESS || st->done) {
	pj_activesock_close(asock);
	if (!st->is_server)
	    clients_num--;
	return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #4
0
static pj_bool_t asock_on_connect_complete(pj_activesock_t *asock,
					   pj_status_t status)
{
    struct test_state *st = (struct test_state*)
			     pj_activesock_get_user_data(asock);

    if (status == PJ_SUCCESS) {
	void *read_buf[1];

	/* Start reading data */
	read_buf[0] = st->read_buf;
	status = pj_activesock_start_read2(asock, st->pool, sizeof(st->read_buf), (void**)read_buf, 0);
	if (status != PJ_SUCCESS) {
	    app_perror("...ERROR pj_ssl_sock_start_read2()", status);
	}
    }

    st->err = status;

    if (st->err != PJ_SUCCESS) {
	pj_activesock_close(asock);
	if (!st->is_server)
	    clients_num--;
	return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #5
0
/*
 * This callback is called by active socket when pending accept() operation
 * has completed.
 */
static pj_bool_t on_accept_complete(pj_activesock_t *asock,
				    pj_sock_t sock,
				    const pj_sockaddr_t *src_addr,
				    int src_addr_len)
{
    struct tcp_listener *listener;
    struct tcp_transport *tcp;
    char addr[PJ_INET6_ADDRSTRLEN+10];
    pj_status_t status;

    PJ_UNUSED_ARG(src_addr_len);

    listener = (struct tcp_listener*) pj_activesock_get_user_data(asock);

    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_TRUE);

    PJ_LOG(4,(listener->factory.obj_name, 
	      "TCP listener %.*s:%d: got incoming TCP connection "
	      "from %s, sock=%d",
	      (int)listener->factory.addr_name.host.slen,
	      listener->factory.addr_name.host.ptr,
	      listener->factory.addr_name.port,
	      pj_sockaddr_print(src_addr, addr, sizeof(addr), 3),
	      sock));

    /* 
     * Incoming connection!
     * Create TCP transport for the new socket.
     */
    status = tcp_create( listener, NULL, sock, PJ_TRUE,
			 (const pj_sockaddr_in*)&listener->factory.local_addr,
			 (const pj_sockaddr_in*)src_addr, &tcp);
    if (status == PJ_SUCCESS) {
	status = tcp_start_read(tcp);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled"));
	    tcp_destroy(&tcp->base, status);
	} else {
	    /* Start keep-alive timer */
	    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
		pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
		pjsip_endpt_schedule_timer(listener->endpt, 
					   &tcp->ka_timer, 
					   &delay);
		tcp->ka_timer.id = PJ_TRUE;
		pj_gettimeofday(&tcp->last_activity);
	    }
	}
    }

    return PJ_TRUE;
}
Пример #6
0
static pj_bool_t stun_on_data_recvfrom(pj_activesock_t *asock,
				       void *data,
				       pj_size_t size,
				       const pj_sockaddr_t *src_addr,
				       int addr_len,
				       pj_status_t status)
{
    test_server *test_srv;
    pj_stun_msg *req, *resp = NULL;
    pj_pool_t *pool;
    pj_ssize_t len;

    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    test_srv = (test_server*) pj_activesock_get_user_data(asock);
    pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);

    status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, 
				PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET, 
				&req, NULL, NULL);
    if (status != PJ_SUCCESS)
	goto on_return;

    if (req->hdr.type != PJ_STUN_BINDING_REQUEST) {
	pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, 
				    NULL, &resp);
	goto send_pkt;
    }

    status = pj_stun_msg_create_response(pool, req, 0, NULL, &resp);
    if (status != PJ_SUCCESS)
	goto on_return;

    pj_stun_msg_add_sockaddr_attr(pool, resp, PJ_STUN_ATTR_XOR_MAPPED_ADDR,
				  PJ_TRUE, src_addr, addr_len);

send_pkt:
    status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT, 
				0, NULL, &size);
    if (status != PJ_SUCCESS)
	goto on_return;

    len = size;
    status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len,
				  0, src_addr, addr_len);

on_return:
    pj_pool_release(pool);
    return PJ_TRUE;
}
Пример #7
0
/*
 * Notification when outgoing TCP socket has been connected.
 */
static pj_bool_t on_connect_complete(pj_activesock_t *asock,
				     pj_status_t status)
{
    pj_turn_sock *turn_sock;

    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
    if (!turn_sock)
        return PJ_FALSE;

    pj_grp_lock_acquire(turn_sock->grp_lock);

    /* TURN session may have already been destroyed here.
     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557).
     */
    if (!turn_sock->sess) {
	sess_fail(turn_sock, "TURN session already destroyed", status);
	pj_grp_lock_release(turn_sock->grp_lock);
	return PJ_FALSE;
    }

    if (status != PJ_SUCCESS) {
	sess_fail(turn_sock, "TCP connect() error", status);
	pj_grp_lock_release(turn_sock->grp_lock);
	return PJ_FALSE;
    }

    if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
	PJ_LOG(5,(turn_sock->obj_name, "TCP connected"));
    }

    /* Kick start pending read operation */
    status = pj_activesock_start_read(asock, turn_sock->pool, 
				      turn_sock->setting.max_pkt_size, 0);

    /* Init send_key */
    pj_ioqueue_op_key_init(&turn_sock->send_key, sizeof(turn_sock->send_key));

    /* Send Allocate request */
    status = pj_turn_session_alloc(turn_sock->sess, &turn_sock->alloc_param);
    if (status != PJ_SUCCESS) {
	sess_fail(turn_sock, "Error sending ALLOCATE", status);
	pj_grp_lock_release(turn_sock->grp_lock);
	return PJ_FALSE;
    }

    pj_grp_lock_release(turn_sock->grp_lock);
    return PJ_TRUE;
}
Пример #8
0
static pj_bool_t tcp_on_data_sent(pj_activesock_t *asock,
				  pj_ioqueue_op_key_t *op_key,
				  pj_ssize_t sent)
{
    struct tcp_state *st=(struct tcp_state*)pj_activesock_get_user_data(asock);

    PJ_UNUSED_ARG(op_key);

    st->sent = 1;

    if (sent < 1) {
	st->err = PJ_TRUE;
	return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #9
0
/* 
 * Callback from ioqueue when packet is sent.
 */
static pj_bool_t on_data_sent(pj_activesock_t *asock,
			      pj_ioqueue_op_key_t *op_key,
			      pj_ssize_t bytes_sent)
{
    struct tcp_transport *tcp = (struct tcp_transport*) 
    				pj_activesock_get_user_data(asock);
    pjsip_tx_data_op_key *tdata_op_key = (pjsip_tx_data_op_key*)op_key;

    /* Note that op_key may be the op_key from keep-alive, thus
     * it will not have tdata etc.
     */

    tdata_op_key->tdata = NULL;

    if (tdata_op_key->callback) {
	/*
	 * Notify sip_transport.c that packet has been sent.
	 */
	if (bytes_sent == 0)
	    bytes_sent = -PJ_RETURN_OS_ERROR(OSERR_ENOTCONN);

	tdata_op_key->callback(&tcp->base, tdata_op_key->token, bytes_sent);

	/* Mark last activity time */
	pj_gettimeofday(&tcp->last_activity);

    }

    /* Check for error/closure */
    if (bytes_sent <= 0) {
	pj_status_t status;

	PJ_LOG(5,(tcp->base.obj_name, "TCP send() error, sent=%d", 
		  bytes_sent));

	status = (bytes_sent == 0) ? PJ_RETURN_OS_ERROR(OSERR_ENOTCONN) :
				     -bytes_sent;

	tcp_init_shutdown(tcp, status);

	return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #10
0
static pj_bool_t tcp_on_data_read(pj_activesock_t *asock,
				  void *data,
				  pj_size_t size,
				  pj_status_t status,
				  pj_size_t *remainder)
{
    struct tcp_state *st = (struct tcp_state*) pj_activesock_get_user_data(asock);
    char *next = (char*) data;

    if (status != PJ_SUCCESS && status != PJ_EPENDING) {
	PJ_LOG(1,("", "   err: status=%d", status));
	st->err = PJ_TRUE;
	return PJ_FALSE;
    }

    while (size >= sizeof(struct tcp_pkt)) {
	struct tcp_pkt *tcp_pkt = (struct tcp_pkt*) next;

	if (tcp_pkt->signature != SIGNATURE) {
	    PJ_LOG(1,("", "   err: invalid signature at seq=%d", 
			  st->next_recv_seq));
	    st->err = PJ_TRUE;
	    return PJ_FALSE;
	}
	if (tcp_pkt->seq != st->next_recv_seq) {
	    PJ_LOG(1,("", "   err: wrong sequence"));
	    st->err = PJ_TRUE;
	    return PJ_FALSE;
	}

	st->next_recv_seq++;
	next += sizeof(struct tcp_pkt);
	size -= sizeof(struct tcp_pkt);
    }

    if (size) {
	pj_memmove(data, next, size);
	*remainder = size;
    }

    return PJ_TRUE;
}
Пример #11
0
static pj_bool_t asock_on_accept_complete(pj_activesock_t *asock,
					  pj_sock_t newsock,
					  const pj_sockaddr_t *src_addr,
					  int src_addr_len)
{
    struct test_state *st;
    void *read_buf[1];
    pj_activesock_t *new_asock;
    pj_activesock_cb asock_cb = { 0 };
    pj_status_t status;

    PJ_UNUSED_ARG(src_addr);
    PJ_UNUSED_ARG(src_addr_len);

    st = (struct test_state*) pj_activesock_get_user_data(asock);

    asock_cb.on_data_read = &asock_on_data_read;
    status = pj_activesock_create(st->pool, newsock, pj_SOCK_STREAM(), NULL, 
				  st->ioqueue, &asock_cb, st, &new_asock);
    if (status != PJ_SUCCESS) {
	goto on_return;
    }

    /* Start reading data */
    read_buf[0] = st->read_buf;
    status = pj_activesock_start_read2(new_asock, st->pool, 
				       sizeof(st->read_buf), 
				       (void**)read_buf, 0);
    if (status != PJ_SUCCESS) {
	app_perror("...ERROR pj_ssl_sock_start_read2()", status);
    }

on_return:
    st->err = status;

    if (st->err != PJ_SUCCESS)
	pj_activesock_close(new_asock);

    return PJ_TRUE;
}
Пример #12
0
static pj_bool_t udp_echo_srv_on_data_recvfrom(pj_activesock_t *asock,
					       void *data,
					       pj_size_t size,
					       const pj_sockaddr_t *src_addr,
					       int addr_len,
					       pj_status_t status)
{
    struct udp_echo_srv *srv;
    pj_ssize_t sent;


    srv = (struct udp_echo_srv*) pj_activesock_get_user_data(asock);

    if (status != PJ_SUCCESS) {
	srv->status = status;
	srv->rx_err_cnt++;
	udp_echo_err("recvfrom() callback", status);
	return PJ_TRUE;
    }

    srv->rx_cnt++;

    /* Send back if echo is enabled */
    if (srv->echo_enabled) {
	sent = size;
	srv->status = pj_activesock_sendto(asock, &srv->send_key, data, 
					   &sent, 0,
					   src_addr, addr_len);
	if (srv->status != PJ_SUCCESS) {
	    srv->tx_err_cnt++;
	    udp_echo_err("sendto()", status);
	}
    }

    return PJ_TRUE;
}
Пример #13
0
/* Callback from active socket when incoming packet is received */
static pj_bool_t on_data_recvfrom(pj_activesock_t *asock,
				  void *data,
				  pj_size_t size,
				  const pj_sockaddr_t *src_addr,
				  int addr_len,
				  pj_status_t status)
{
    pj_stun_sock *stun_sock;
    pj_stun_msg_hdr *hdr;
    pj_uint16_t type;

    stun_sock = (pj_stun_sock*) pj_activesock_get_user_data(asock);

    /* Log socket error */
    if (status != PJ_SUCCESS) {
	PJ_PERROR(2,(stun_sock->obj_name, status, "recvfrom() error"));
	return PJ_TRUE;
    }

    /* Check that this is STUN message */
    status = pj_stun_msg_check((const pj_uint8_t*)data, size, 
    			       PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET);
    if (status != PJ_SUCCESS) {
	/* Not STUN -- give it to application */
	goto process_app_data;
    }

    /* Treat packet as STUN header and copy the STUN message type.
     * We don't want to access the type directly from the header
     * since it may not be properly aligned.
     */
    hdr = (pj_stun_msg_hdr*) data;
    pj_memcpy(&type, &hdr->type, 2);
    type = pj_ntohs(type);

    /* If the packet is a STUN Binding response and part of the
     * transaction ID matches our internal ID, then this is
     * our internal STUN message (Binding request or keep alive).
     * Give it to our STUN session.
     */
    if (!PJ_STUN_IS_RESPONSE(type) ||
	PJ_STUN_GET_METHOD(type) != PJ_STUN_BINDING_METHOD ||
	pj_memcmp(hdr->tsx_id, stun_sock->tsx_id, 10) != 0) 
    {
	/* Not STUN Binding response, or STUN transaction ID mismatch.
	 * This is not our message too -- give it to application.
	 */
	goto process_app_data;
    }

    /* This is our STUN Binding response. Give it to the STUN session */
    status = pj_stun_session_on_rx_pkt(stun_sock->stun_sess, data, size,
				       PJ_STUN_IS_DATAGRAM, NULL, NULL,
				       src_addr, addr_len);
    return status!=PJNATH_ESTUNDESTROYED ? PJ_TRUE : PJ_FALSE;

process_app_data:
    if (stun_sock->cb.on_rx_data) {
	pj_bool_t ret;

	ret = (*stun_sock->cb.on_rx_data)(stun_sock, data, size,
					  src_addr, addr_len);
	return ret;
    }

    return PJ_TRUE;
}
Пример #14
0
/*
 * Notification when outgoing TCP socket has been connected.
 */
static pj_bool_t on_connect_complete(pj_activesock_t *asock,
				     pj_status_t status)
{
    pj_turn_sock *turn_sock;

    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
    if (!turn_sock)
        return PJ_FALSE;

    /* TURN session may have already been destroyed here.
     * See ticket #1557 (http://trac.pjsip.org/repos/ticket/1557).
     */
	if (!turn_sock->sess) {
		PJ_LOG(1, ("turn_sock.c", "!!! TURN DEALLOCATE !!! in on_connect_complete() turn_sock->sess is NULL status=%d", status));
		sess_fail(turn_sock, "TURN session already destroyed", status);
		return PJ_FALSE;
    }

    if (status != PJ_SUCCESS) {

		// DEAN assigned next turn server 
		if (turn_sock->turn_cnt <= ++turn_sock->curr_turn) {
			PJ_LOG(1, ("turn_sock.c", "!!! TURN DEALLOCATE !!! in on_connect_complete() turn_sock->turn_cnt <= ++turn_sock->curr_turn (%d,%d)", 
				turn_sock->turn_cnt, turn_sock->curr_turn));
			sess_fail(turn_sock, "TCP connect() error", status);
			turn_sock->curr_turn = 0;
			PJ_LOG(3, (__FILE__, "Failed(%d) connect to all turn servers.", status));
		} else {

			set_state(turn_sock->sess, PJ_TURN_STATE_NULL);

			PJ_LOG(3, (__FILE__, "Failed(%d) connect to turn server [%.*s:%d].",
				status,
				turn_sock->turn.domain->slen, 
				turn_sock->turn.domain->ptr, 
				turn_sock->turn.default_port));
			turn_sock->turn.domain = &turn_sock->turn_list[turn_sock->curr_turn].server;
			turn_sock->turn.default_port = turn_sock->turn_list[turn_sock->curr_turn].port;
			PJ_LOG(3, (__FILE__, "Try another turn server [%.*s:%d].",
				turn_sock->turn.domain->slen, 
				turn_sock->turn.domain->ptr, 
				turn_sock->turn.default_port));
			
			/* Resolve server */
			status = pj_turn_session_set_server(turn_sock->sess, turn_sock->turn.domain, 
				turn_sock->turn.default_port, turn_sock->turn.resolver);
			if (status != PJ_SUCCESS) {
				PJ_LOG(1, ("turn_sock.c", "!!! TURN DEALLOCATE !!! in on_connect_complete() pj_turn_session_set_server failed status=%d", 
					status));
				sess_fail(turn_sock, "Error setting TURN server", status);
				return status;
			}
		}
		return PJ_FALSE;
    }

    if (turn_sock->conn_type != PJ_TURN_TP_UDP) {
	PJ_LOG(5,(turn_sock->obj_name, "TCP connected"));
    }

    /* Kick start pending read operation */
    status = pj_activesock_start_read(asock, turn_sock->pool, 
				      PJ_TURN_MAX_PKT_LEN, 0);

    /* Init send_key */
    pj_ioqueue_op_key_init(&turn_sock->send_key, sizeof(turn_sock->send_key));

   /* Send Allocate request */
    status = pj_turn_session_alloc(turn_sock->sess, &turn_sock->alloc_param);
	if (status != PJ_SUCCESS) {
		PJ_LOG(1, ("turn_sock.c", "!!! TURN DEALLOCATE !!! in on_connect_complete() pj_turn_session_alloc failed status=%d", 
			status));
		sess_fail(turn_sock, "Error sending ALLOCATE", status);
		return PJ_FALSE;
    }

    return PJ_TRUE;
}
Пример #15
0
/*
 * This callback is called by active socket when pending accept() operation
 * has completed.
 */
static pj_bool_t on_accept_complete(pj_activesock_t *asock,
				    pj_sock_t sock,
				    const pj_sockaddr_t *src_addr,
				    int src_addr_len)
{
    struct tcp_listener *listener;
    struct tcp_transport *tcp;
    char addr[PJ_INET6_ADDRSTRLEN+10];
    pjsip_tp_state_callback state_cb;
    pj_sockaddr tmp_src_addr;
    pj_status_t status;

    PJ_UNUSED_ARG(src_addr_len);

    listener = (struct tcp_listener*) pj_activesock_get_user_data(asock);

    PJ_ASSERT_RETURN(sock != PJ_INVALID_SOCKET, PJ_TRUE);

    PJ_LOG(4,(listener->factory.obj_name, 
	      "TCP listener %.*s:%d: got incoming TCP connection "
	      "from %s, sock=%d",
	      (int)listener->factory.addr_name.host.slen,
	      listener->factory.addr_name.host.ptr,
	      listener->factory.addr_name.port,
	      pj_sockaddr_print(src_addr, addr, sizeof(addr), 3),
	      sock));

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

    /* tcp_create() expect pj_sockaddr, so copy src_addr to temporary var,
     * just in case.
     */
    pj_bzero(&tmp_src_addr, sizeof(tmp_src_addr));
    pj_sockaddr_cp(&tmp_src_addr, src_addr);

    /* 
     * Incoming connection!
     * Create TCP transport for the new socket.
     */
    status = tcp_create( listener, NULL, sock, PJ_TRUE,
			 &listener->factory.local_addr,
			 &tmp_src_addr, &tcp);
    if (status == PJ_SUCCESS) {
	status = tcp_start_read(tcp);
	if (status != PJ_SUCCESS) {
	    PJ_LOG(3,(tcp->base.obj_name, "New transport cancelled"));
	    tcp_destroy(&tcp->base, status);
	} else {
	    /* Start keep-alive timer */
	    if (PJSIP_TCP_KEEP_ALIVE_INTERVAL) {
		pj_time_val delay = {PJSIP_TCP_KEEP_ALIVE_INTERVAL, 0};
		pjsip_endpt_schedule_timer(listener->endpt, 
					   &tcp->ka_timer, 
					   &delay);
		tcp->ka_timer.id = PJ_TRUE;
		pj_gettimeofday(&tcp->last_activity);
	    }

	    /* Notify application of transport state accepted */
	    state_cb = pjsip_tpmgr_get_state_cb(tcp->base.tpmgr);
	    if (state_cb) {
		pjsip_transport_state_info state_info;
            
		pj_bzero(&state_info, sizeof(state_info));
		(*state_cb)(&tcp->base, PJSIP_TP_STATE_CONNECTED, &state_info);
	    }
	}
    }

    return PJ_TRUE;
}
Пример #16
0
/*
 * Notification from ioqueue when incoming UDP packet is received.
 */
static pj_bool_t on_data_read(pj_activesock_t *asock,
			      void *data,
			      pj_size_t size,
			      pj_status_t status,
			      pj_size_t *remainder)
{
    pj_turn_sock *turn_sock;
    pj_bool_t ret = PJ_TRUE;

    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
    pj_grp_lock_acquire(turn_sock->grp_lock);

    if (status == PJ_SUCCESS && turn_sock->sess && !turn_sock->is_destroying) {
	/* Report incoming packet to TURN session, repeat while we have
	 * "packet" in the buffer (required for stream-oriented transports)
	 */
	unsigned pkt_len;

	//PJ_LOG(5,(turn_sock->pool->obj_name, 
	//	  "Incoming data, %lu bytes total buffer", size));

	while ((pkt_len=has_packet(turn_sock, data, size)) != 0) {
	    pj_size_t parsed_len;
	    //const pj_uint8_t *pkt = (const pj_uint8_t*)data;

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Packet start: %02X %02X %02X %02X", 
	    //	      pkt[0], pkt[1], pkt[2], pkt[3]));

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Processing %lu bytes packet of %lu bytes total buffer",
	    //	      pkt_len, size));

	    parsed_len = (unsigned)size;
	    pj_turn_session_on_rx_pkt(turn_sock->sess, data,  size, &parsed_len);

	    /* parsed_len may be zero if we have parsing error, so use our
	     * previous calculation to exhaust the bad packet.
	     */
	    if (parsed_len == 0)
		parsed_len = pkt_len;

	    if (parsed_len < (unsigned)size) {
		*remainder = size - parsed_len;
		pj_memmove(data, ((char*)data)+parsed_len, *remainder);
	    } else {
		*remainder = 0;
	    }
	    size = *remainder;

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Buffer size now %lu bytes", size));
	}
    } else if (status != PJ_SUCCESS && 
	       turn_sock->conn_type != PJ_TURN_TP_UDP) 
    {
	sess_fail(turn_sock, "TCP connection closed", status);
	ret = PJ_FALSE;
	goto on_return;
    }

on_return:
    pj_grp_lock_release(turn_sock->grp_lock);

    return ret;
}
Пример #17
0
/*
 * Notification from ioqueue when incoming UDP packet is received.
 */
static pj_bool_t on_data_read(pj_activesock_t *asock,
			      void *data,
			      pj_size_t size,
			      pj_status_t status,
			      pj_size_t *remainder)
{
    pj_turn_sock *turn_sock;
    pj_bool_t ret = PJ_TRUE;

    turn_sock = (pj_turn_sock*) pj_activesock_get_user_data(asock);
    pj_lock_acquire(turn_sock->lock);

    if (status == PJ_SUCCESS && turn_sock->sess) {
	/* Report incoming packet to TURN session, repeat while we have
	 * "packet" in the buffer (required for stream-oriented transports)
	 */
	unsigned pkt_len;

	//PJ_LOG(5,(turn_sock->pool->obj_name, 
	//	  "Incoming data, %lu bytes total buffer", size));

	while ((pkt_len=has_packet(turn_sock, data, size)) != 0) {
	    pj_size_t parsed_len;
	    //const pj_uint8_t *pkt = (const pj_uint8_t*)data;

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Packet start: %02X %02X %02X %02X", 
	    //	      pkt[0], pkt[1], pkt[2], pkt[3]));

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Processing %lu bytes packet of %lu bytes total buffer",
	    //	      pkt_len, size));

	    parsed_len = (unsigned)size;
	    pj_turn_session_on_rx_pkt(turn_sock->sess, data,  size, &parsed_len);

	    /* parsed_len may be zero if we have parsing error, so use our
	     * previous calculation to exhaust the bad packet.
	     */
	    if (parsed_len == 0)
		parsed_len = pkt_len;

	    if (parsed_len < (unsigned)size) {
		*remainder = size - parsed_len;
		pj_memmove(data, ((char*)data)+parsed_len, *remainder);
	    } else {
		*remainder = 0;
		}
	    size = *remainder;

	    //PJ_LOG(5,(turn_sock->pool->obj_name, 
	    //	      "Buffer size now %lu bytes", size));
	}
	/* Assigned remainder as size. Because ioqueue may 
	   skip the packet if never enter while loop. */
	if (pkt_len == 0)
		*remainder = size;

	PJ_LOG(5, (__FILE__, "on_data_read() leaving still remainder=[%d].", 
		*remainder));
    } else if (status != PJ_SUCCESS && 
	       turn_sock->conn_type != PJ_TURN_TP_UDP) 
    {
		// DEAN don't destroy TURN session, if connection aborted.
		// To avoid the situation of ip changing caused crash.
		if (status != 130053) 
		{
			PJ_LOG(1, ("turn_sock.c", "!!! TURN DEALLOCATE !!! in on_data_read() read failed status=%d", 
				status));
			sess_fail(turn_sock, "TURN TCP connection closed", status);
		}

		ret = PJ_FALSE;
		goto on_return;
    }

on_return:
    pj_lock_release(turn_sock->lock);

    return ret;
}
Пример #18
0
/* On received data from peer */
static pj_bool_t alloc_on_data_recvfrom(pj_activesock_t *asock,
				       void *data,
				       pj_size_t size,
				       const pj_sockaddr_t *src_addr,
				       int addr_len,
				       pj_status_t status)
{
    turn_allocation *alloc;
    pj_stun_xor_peer_addr_attr *pa;
    pj_stun_data_attr *da;
    char peer_info[PJ_INET6_ADDRSTRLEN+10];
    char client_info[PJ_INET6_ADDRSTRLEN+10];
    pj_uint8_t buffer[1500];
    pj_ssize_t sent;
    unsigned i;

    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    alloc = (turn_allocation*) pj_activesock_get_user_data(asock);

    pj_sockaddr_print(&alloc->client_addr, client_info, sizeof(client_info), 3);
    pj_sockaddr_print(src_addr, peer_info, sizeof(peer_info), 3);

    /* Check that this peer has a permission */
    for (i=0; i<alloc->perm_cnt; ++i) {
	if (pj_sockaddr_get_len(&alloc->perm[i]) == (unsigned)addr_len &&
	    pj_memcmp(pj_sockaddr_get_addr(&alloc->perm[i]),
		      pj_sockaddr_get_addr(src_addr),
		      addr_len) == 0)
	{
	    break;
	}
    }
    if (i==alloc->perm_cnt) {
	PJ_LOG(5,("", "Client %s received %d bytes unauthorized data from peer %s", 
		      client_info, size, peer_info));
	if (alloc->perm_cnt == 0)
	    PJ_LOG(5,("", "Client %s has no permission", client_info));
	return PJ_TRUE;
    }

    /* Format a Data indication */
    pa = (pj_stun_xor_peer_addr_attr*)
	 pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
    da = (pj_stun_data_attr*)
	 pj_stun_msg_find_attr(alloc->data_ind, PJ_STUN_ATTR_DATA, 0);
    pj_assert(pa && da);

    pj_sockaddr_cp(&pa->sockaddr, src_addr);
    da->data = (pj_uint8_t*)data;
    da->length = size;

    /* Encode Data indication */
    status = pj_stun_msg_encode(alloc->data_ind, buffer, sizeof(buffer), 0,
				NULL, &size);
    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    /* Send */
    sent = size;
    PJ_LOG(5,("", "Forwarding %d bytes data from peer %s to client %s", 
		   sent, peer_info, client_info));

    pj_activesock_sendto(alloc->test_srv->turn_sock, &alloc->send_key, buffer,
			 &sent, 0, &alloc->client_addr,
			 pj_sockaddr_get_len(&alloc->client_addr));

    return PJ_TRUE;
}
Пример #19
0
static pj_bool_t turn_on_data_recvfrom(pj_activesock_t *asock,
				       void *data,
				       pj_size_t size,
				       const pj_sockaddr_t *src_addr,
				       int addr_len,
				       pj_status_t status)
{
    test_server *test_srv;
    pj_pool_t *pool;
    turn_allocation *alloc;
    pj_stun_msg *req, *resp = NULL;
    pj_str_t auth_key = { NULL, 0 };
    char client_info[PJ_INET6_ADDRSTRLEN+10];
    unsigned i;
    pj_ssize_t len;

    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    pj_sockaddr_print(src_addr, client_info, sizeof(client_info), 3);

    test_srv = (test_server*) pj_activesock_get_user_data(asock);
    pool = pj_pool_create(test_srv->stun_cfg->pf, NULL, 512, 512, NULL);

    /* Find the client */
    for (i=0; i<test_srv->turn_alloc_cnt; i++) {
	if (pj_sockaddr_cmp(&test_srv->turn_alloc[i].client_addr, src_addr)==0)
	    break;
    }


    if (pj_stun_msg_check((pj_uint8_t*)data, size, PJ_STUN_NO_FINGERPRINT_CHECK)!=PJ_SUCCESS)  {
	/* Not STUN message, this probably is a ChannelData */
	pj_turn_channel_data cd;
	const pj_turn_channel_data *pcd = (const pj_turn_channel_data*)data;
	pj_ssize_t sent;

	if (i==test_srv->turn_alloc_cnt) {
	    /* Invalid data */
	    PJ_LOG(1,(THIS_FILE, 
		      "TURN Server received strayed data"));
	    goto on_return;
	}

	alloc = &test_srv->turn_alloc[i];

	cd.ch_number = pj_ntohs(pcd->ch_number);
	cd.length = pj_ntohs(pcd->length);

	/* For UDP check the packet length */
	if (size < cd.length+sizeof(cd)) {
	    PJ_LOG(1,(THIS_FILE, 
		      "TURN Server: ChannelData discarded: UDP size error"));
	    goto on_return;
	}

	/* Lookup peer */
	for (i=0; i<alloc->perm_cnt; ++i) {
	    if (alloc->chnum[i] == cd.ch_number)
		break;
	}

	if (i==alloc->perm_cnt) {
	    PJ_LOG(1,(THIS_FILE, 
		      "TURN Server: ChannelData discarded: invalid channel number"));
	    goto on_return;
	}

	/* Relay the data to peer */
	sent = cd.length;
	pj_activesock_sendto(alloc->sock, &alloc->send_key,
			     pcd+1, &sent, 0,
			     &alloc->perm[i],
			     pj_sockaddr_get_len(&alloc->perm[i]));

	/* Done */
	goto on_return;
    }

    status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, 
				PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET |
				    PJ_STUN_NO_FINGERPRINT_CHECK, 
				&req, NULL, NULL);
    if (status != PJ_SUCCESS) {
	char errmsg[PJ_ERR_MSG_SIZE];
	pj_strerror(status, errmsg, sizeof(errmsg));
	PJ_LOG(1,("", "STUN message decode error from client %s: %s", client_info, errmsg));
	goto on_return;
    }

    if (i==test_srv->turn_alloc_cnt) {
	/* New client */
	//pj_str_t ip_addr;
	pj_stun_username_attr *uname;
	pj_activesock_cb alloc_sock_cb;
	turn_allocation *alloc;

	/* Must be Allocate request */
	if (req->hdr.type != PJ_STUN_ALLOCATE_REQUEST) {
	    PJ_LOG(1,(THIS_FILE, "Invalid %s %s from client %s",
		      pj_stun_get_method_name(req->hdr.type),
		      pj_stun_get_class_name(req->hdr.type),
		      client_info));

	    if (PJ_STUN_IS_REQUEST(req->hdr.type))
		pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp);
	    goto send_pkt;
	}

	test_srv->turn_stat.rx_allocate_cnt++;

	/* Skip if we're not responding to Allocate request */
	if (!test_srv->turn_respond_allocate)
	    return PJ_TRUE;

	/* Check if we have too many clients */
	if (test_srv->turn_alloc_cnt == MAX_TURN_ALLOC) {
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_INSUFFICIENT_CAPACITY, NULL, &resp);
	    goto send_pkt;
	}

	/* Get USERNAME attribute */
	uname = (pj_stun_username_attr*)
		pj_stun_msg_find_attr(req, PJ_STUN_ATTR_USERNAME, 0);

	/* Reject if it doesn't have MESSAGE-INTEGRITY or USERNAME attributes or
	 * the user is incorrect
	 */
	if (pj_stun_msg_find_attr(req, PJ_STUN_ATTR_MESSAGE_INTEGRITY, 0) == NULL ||
	    uname==NULL || pj_stricmp2(&uname->value, TURN_USERNAME) != 0) 
	{
	    pj_str_t tmp;

	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_UNAUTHORIZED, NULL, &resp);
	    pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_REALM, &test_srv->domain);
	    pj_stun_msg_add_string_attr(pool, resp, PJ_STUN_ATTR_NONCE, pj_cstr(&tmp, TURN_NONCE));
	    goto send_pkt;
	}

	pj_bzero(&alloc_sock_cb, sizeof(alloc_sock_cb));
	alloc_sock_cb.on_data_recvfrom = &alloc_on_data_recvfrom;

	/* Create allocation */
	alloc = &test_srv->turn_alloc[test_srv->turn_alloc_cnt];
	alloc->perm_cnt = 0;
	alloc->test_srv = test_srv;
	pj_memcpy(&alloc->client_addr, src_addr, addr_len);
	pj_ioqueue_op_key_init(&alloc->send_key, sizeof(alloc->send_key));

	alloc->pool = pj_pool_create(test_srv->stun_cfg->pf, "alloc", 512, 512, NULL);

	/* Create relay socket */
	pj_sockaddr_in_init(&alloc->alloc_addr.ipv4, NULL, 0);
	pj_gethostip(pj_AF_INET(), &alloc->alloc_addr);

	status = pj_activesock_create_udp(alloc->pool, &alloc->alloc_addr, NULL, 
					  test_srv->stun_cfg->ioqueue,
					  &alloc_sock_cb, alloc, 
					  &alloc->sock, &alloc->alloc_addr);
	if (status != PJ_SUCCESS) {
	    pj_pool_release(alloc->pool);
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
	    goto send_pkt;
	}
	//pj_sockaddr_set_str_addr(pj_AF_INET(), &alloc->alloc_addr, &ip_addr);

	pj_activesock_set_user_data(alloc->sock, alloc);

	status = pj_activesock_start_recvfrom(alloc->sock, alloc->pool, 1500, 0);
	if (status != PJ_SUCCESS) {
	    pj_activesock_close(alloc->sock);
	    pj_pool_release(alloc->pool);
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
	    goto send_pkt;
	}

	/* Create Data indication */
	status = pj_stun_msg_create(alloc->pool, PJ_STUN_DATA_INDICATION,
				    PJ_STUN_MAGIC, NULL, &alloc->data_ind);
	if (status != PJ_SUCCESS) {
	    pj_activesock_close(alloc->sock);
	    pj_pool_release(alloc->pool);
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
	    goto send_pkt;
	}
	pj_stun_msg_add_sockaddr_attr(alloc->pool, alloc->data_ind, 
				      PJ_STUN_ATTR_XOR_PEER_ADDR, PJ_TRUE,
				      &alloc->alloc_addr,
				      pj_sockaddr_get_len(&alloc->alloc_addr));
	pj_stun_msg_add_binary_attr(alloc->pool, alloc->data_ind,
				    PJ_STUN_ATTR_DATA, (pj_uint8_t*)"", 1);

	/* Create response */
	resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key);
	if (resp == NULL) {
	    pj_activesock_close(alloc->sock);
	    pj_pool_release(alloc->pool);
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_SERVER_ERROR, NULL, &resp);
	    goto send_pkt;
	}

	++test_srv->turn_alloc_cnt;

    } else {
	alloc = &test_srv->turn_alloc[i];

	if (req->hdr.type == PJ_STUN_ALLOCATE_REQUEST) {

	    test_srv->turn_stat.rx_allocate_cnt++;

	    /* Skip if we're not responding to Allocate request */
	    if (!test_srv->turn_respond_allocate)
		return PJ_TRUE;

	    resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);

	} else if (req->hdr.type == PJ_STUN_REFRESH_REQUEST) {
	    pj_stun_lifetime_attr *lf_attr;

	    test_srv->turn_stat.rx_refresh_cnt++;

	    /* Skip if we're not responding to Refresh request */
	    if (!test_srv->turn_respond_refresh)
		return PJ_TRUE;

	    lf_attr = (pj_stun_lifetime_attr*)
		      pj_stun_msg_find_attr(req, PJ_STUN_ATTR_LIFETIME, 0);
	    if (lf_attr && lf_attr->value != 0) {
		resp = create_success_response(test_srv, alloc, req, pool, 600, &auth_key);
		pj_array_erase(test_srv->turn_alloc, sizeof(test_srv->turn_alloc[0]),
			       test_srv->turn_alloc_cnt, i);
		--test_srv->turn_alloc_cnt;
	    } else
		resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);
	} else if (req->hdr.type == PJ_STUN_CREATE_PERM_REQUEST) {
	    for (i=0; i<req->attr_count; ++i) {
		if (req->attr[i]->type == PJ_STUN_ATTR_XOR_PEER_ADDR) {
		    pj_stun_xor_peer_addr_attr *pa = (pj_stun_xor_peer_addr_attr*)req->attr[i];
		    unsigned j;

		    for (j=0; j<alloc->perm_cnt; ++j) {
			if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0)
			    break;
		    }

		    if (j==alloc->perm_cnt && alloc->perm_cnt < MAX_TURN_PERM) {
			char peer_info[PJ_INET6_ADDRSTRLEN];
			pj_sockaddr_print(&pa->sockaddr, peer_info, sizeof(peer_info), 3);

			pj_sockaddr_cp(&alloc->perm[alloc->perm_cnt], &pa->sockaddr);
			++alloc->perm_cnt;

			PJ_LOG(5,("", "Permission %s added to client %s, perm_cnt=%d", 
				      peer_info, client_info, alloc->perm_cnt));
		    }

		}
	    }
	    resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);
	} else if (req->hdr.type == PJ_STUN_SEND_INDICATION) {
	    pj_stun_xor_peer_addr_attr *pa;
	    pj_stun_data_attr *da;

	    test_srv->turn_stat.rx_send_ind_cnt++;

	    pa = (pj_stun_xor_peer_addr_attr*)
		 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
	    da = (pj_stun_data_attr*)
		 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_DATA, 0);
	    if (pa && da) {
		unsigned j;
		char peer_info[PJ_INET6_ADDRSTRLEN];
		pj_ssize_t sent;

		pj_sockaddr_print(&pa->sockaddr, peer_info, sizeof(peer_info), 3);

		for (j=0; j<alloc->perm_cnt; ++j) {
		    if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0)
			break;
		}

		if (j==alloc->perm_cnt) {
		    PJ_LOG(5,("", "SendIndication to %s is rejected (no permission)", 
			          peer_info, client_info, alloc->perm_cnt));
		} else {
		    PJ_LOG(5,(THIS_FILE, "Relaying %d bytes data from client %s to peer %s, "
					 "perm_cnt=%d", 
			      da->length, client_info, peer_info, alloc->perm_cnt));

		    sent = da->length;
		    pj_activesock_sendto(alloc->sock, &alloc->send_key,
					 da->data, &sent, 0,
					 &pa->sockaddr,
					 pj_sockaddr_get_len(&pa->sockaddr));
		}
	    } else {
		PJ_LOG(1,(THIS_FILE, "Invalid Send Indication from %s", client_info));
	    }
	} else if (req->hdr.type == PJ_STUN_CHANNEL_BIND_REQUEST) {
	    pj_stun_xor_peer_addr_attr *pa;
	    pj_stun_channel_number_attr *cna;
	    unsigned j, cn;

	    pa = (pj_stun_xor_peer_addr_attr*)
		 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_XOR_PEER_ADDR, 0);
	    cna = (pj_stun_channel_number_attr*)
		 pj_stun_msg_find_attr(req, PJ_STUN_ATTR_CHANNEL_NUMBER, 0);
	    cn = PJ_STUN_GET_CH_NB(cna->value);

	    resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);

	    for (j=0; j<alloc->perm_cnt; ++j) {
		if (pj_sockaddr_cmp(&alloc->perm[j], &pa->sockaddr)==0)
		    break;
	    }

	    if (i==alloc->perm_cnt) {
		if (alloc->perm_cnt==MAX_TURN_PERM) {
		    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_INSUFFICIENT_CAPACITY, NULL, &resp);
		    goto send_pkt;
		}
		pj_sockaddr_cp(&alloc->perm[i], &pa->sockaddr);
		++alloc->perm_cnt;
	    }
	    alloc->chnum[i] = cn;

	    resp = create_success_response(test_srv, alloc, req, pool, 0, &auth_key);

	} else if (PJ_STUN_IS_REQUEST(req->hdr.type)) {
	    pj_stun_msg_create_response(pool, req, PJ_STUN_SC_BAD_REQUEST, NULL, &resp);
	}
    }


send_pkt:
    if (resp) {
	status = pj_stun_msg_encode(resp, (pj_uint8_t*)data, MAX_STUN_PKT, 
				    0, &auth_key, &size);
	if (status != PJ_SUCCESS)
	    goto on_return;

	len = size;
	status = pj_activesock_sendto(asock, &test_srv->send_key, data, &len,
				      0, src_addr, addr_len);
    }

on_return:
    pj_pool_release(pool);
    return PJ_TRUE;
}
Пример #20
0
static pj_bool_t srv_on_data_recvfrom(pj_activesock_t *asock,
				      void *data,
				      pj_size_t size,
				      const pj_sockaddr_t *src_addr,
				      int addr_len,
				      pj_status_t status)
{
    struct stun_srv *srv;
    pj_ssize_t sent;

    srv = (struct stun_srv*) pj_activesock_get_user_data(asock);

    /* Ignore error */
    if (status != PJ_SUCCESS)
	return PJ_TRUE;

    ++srv->rx_cnt;

    /* Ignore if we're not responding */
    if (srv->flag & RESPOND_STUN) {
	pj_pool_t *pool;
	pj_stun_msg *req_msg, *res_msg;

	pool = pj_pool_create(mem, "stunsrv", 512, 512, NULL);
    
	/* Parse request */
	status = pj_stun_msg_decode(pool, (pj_uint8_t*)data, size, 
				    PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET,
				    &req_msg, NULL, NULL);
	if (status != PJ_SUCCESS) {
	    app_perror("   pj_stun_msg_decode()", status);
	    pj_pool_release(pool);
	    return PJ_TRUE;
	}

	/* Create response */
	status = pj_stun_msg_create(pool, PJ_STUN_BINDING_RESPONSE, PJ_STUN_MAGIC,
				    req_msg->hdr.tsx_id, &res_msg);
	if (status != PJ_SUCCESS) {
	    app_perror("   pj_stun_msg_create()", status);
	    pj_pool_release(pool);
	    return PJ_TRUE;
	}

	/* Add MAPPED-ADDRESS or XOR-MAPPED-ADDRESS (or don't add) */
	if (srv->flag & WITH_MAPPED) {
	    pj_sockaddr_in addr;

	    pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
	    pj_stun_msg_add_sockaddr_attr(pool, res_msg, PJ_STUN_ATTR_MAPPED_ADDR,
					  PJ_FALSE, &addr, sizeof(addr));
	} else if (srv->flag & WITH_XOR_MAPPED) {
	    pj_sockaddr_in addr;

	    pj_sockaddr_in_init(&addr, &srv->ip_to_send, srv->port_to_send);
	    pj_stun_msg_add_sockaddr_attr(pool, res_msg, 
					  PJ_STUN_ATTR_XOR_MAPPED_ADDR,
					  PJ_TRUE, &addr, sizeof(addr));
	}

	/* Encode */
	status = pj_stun_msg_encode(res_msg, (pj_uint8_t*)data, 100, 0, 
				    NULL, &size);
	if (status != PJ_SUCCESS) {
	    app_perror("   pj_stun_msg_encode()", status);
	    pj_pool_release(pool);
	    return PJ_TRUE;
	}

	/* Send back */
	sent = size;
	pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, 
			     src_addr, addr_len);

	pj_pool_release(pool);

    } else if (srv->flag & ECHO) {
	/* Send back */
	sent = size;
	pj_activesock_sendto(asock, &srv->send_key, data, &sent, 0, 
			     src_addr, addr_len);

    }

    return PJ_TRUE;
}