Esempio n. 1
0
static pj_status_t udp_echo_srv_create(pj_pool_t *pool,
				       pj_ioqueue_t *ioqueue,
				       pj_bool_t enable_echo,
				       struct udp_echo_srv **p_srv)
{
    struct udp_echo_srv *srv;
    pj_sock_t sock_fd = PJ_INVALID_SOCKET;
    pj_sockaddr addr;
    int addr_len;
    pj_activesock_cb activesock_cb;
    pj_status_t status;

    srv = PJ_POOL_ZALLOC_T(pool, struct udp_echo_srv);
    srv->echo_enabled = enable_echo;

    pj_sockaddr_in_init(&addr.ipv4, NULL, 0);
    addr_len = sizeof(addr);

    pj_bzero(&activesock_cb, sizeof(activesock_cb));
    activesock_cb.on_data_recvfrom = &udp_echo_srv_on_data_recvfrom;

    status = pj_activesock_create_udp(pool, &addr, NULL, ioqueue, &activesock_cb, 
				      srv, &srv->asock, &addr);
    if (status != PJ_SUCCESS) {
			pj_sock_close(sock_fd);
			udp_echo_err("pj_activesock_create()", status);
			return status;
    }

    srv->port = pj_ntohs(addr.ipv4.sin_port);

    pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));

    status = pj_activesock_start_recvfrom(srv->asock, pool, 32, 0);
    if (status != PJ_SUCCESS) {
			pj_activesock_close(srv->asock);
			udp_echo_err("pj_activesock_start_recvfrom()", status);
			return status;
    }


    *p_srv = srv;
    return PJ_SUCCESS;
}
Esempio n. 2
0
static pj_status_t create_server(pj_pool_t *pool,
				 pj_ioqueue_t *ioqueue,
				 unsigned flag,
				 struct stun_srv **p_srv)
{
    struct stun_srv *srv;
    pj_activesock_cb activesock_cb;
    pj_status_t status;

    srv = PJ_POOL_ZALLOC_T(pool, struct stun_srv);
    srv->flag = flag;
    srv->ip_to_send = pj_str("1.1.1.1");
    srv->port_to_send = 1000;

    status = pj_sockaddr_in_init(&srv->addr.ipv4, NULL, 0);
    if (status != PJ_SUCCESS)
	return status;

    pj_bzero(&activesock_cb, sizeof(activesock_cb));
    activesock_cb.on_data_recvfrom = &srv_on_data_recvfrom;
    status = pj_activesock_create_udp(pool, &srv->addr, NULL, ioqueue,
				      &activesock_cb, srv, &srv->asock, 
				      &srv->addr);
    if (status != PJ_SUCCESS)
	return status;

    pj_ioqueue_op_key_init(&srv->send_key, sizeof(srv->send_key));

    status = pj_activesock_start_recvfrom(srv->asock, pool, 512, 0);
    if (status != PJ_SUCCESS) {
	pj_activesock_close(srv->asock);
	return status;
    }

    *p_srv = srv;
    return PJ_SUCCESS;
}
Esempio n. 3
0
pj_status_t create_test_server(pj_stun_config *stun_cfg,
			       pj_uint32_t flags,
			       const char *domain,
			       test_server **p_test_srv)
{
    pj_pool_t *pool;
    test_server *test_srv;
    pj_sockaddr hostip;
    char strbuf[100];
    pj_status_t status;

    PJ_ASSERT_RETURN(stun_cfg && domain && p_test_srv, PJ_EINVAL);

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

    pool = pj_pool_create(mem, THIS_FILE, 512, 512, NULL);
    test_srv = (test_server*) PJ_POOL_ZALLOC_T(pool, test_server);
    test_srv->pool = pool;
    test_srv->flags = flags;
    test_srv->stun_cfg = stun_cfg;

    pj_strdup2(pool, &test_srv->domain, domain);
    test_srv->username = pj_str(TURN_USERNAME);
    test_srv->passwd = pj_str(TURN_PASSWD);

    pj_ioqueue_op_key_init(&test_srv->send_key, sizeof(test_srv->send_key));

    if (flags & CREATE_DNS_SERVER) {
	status = pj_dns_server_create(mem, test_srv->stun_cfg->ioqueue,
				      pj_AF_INET(), DNS_SERVER_PORT,
				      0, &test_srv->dns_server);
	if (status != PJ_SUCCESS) {
	    destroy_test_server(test_srv);
	    return status;
	}

	/* Add DNS A record for the domain, for fallback */
	if (flags & CREATE_A_RECORD_FOR_DOMAIN) {
	    pj_dns_parsed_rr rr;
	    pj_str_t res_name;
	    pj_in_addr ip_addr;

	    pj_strdup2(pool, &res_name, domain);
	    ip_addr = hostip.ipv4.sin_addr;
	    pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
	    pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
	}

    }

    if (flags & CREATE_STUN_SERVER) {
	pj_activesock_cb stun_sock_cb;
	pj_sockaddr bound_addr;

	pj_bzero(&stun_sock_cb, sizeof(stun_sock_cb));
	stun_sock_cb.on_data_recvfrom = &stun_on_data_recvfrom;

	pj_sockaddr_in_init(&bound_addr.ipv4, NULL, STUN_SERVER_PORT);

	status = pj_activesock_create_udp(pool, &bound_addr, NULL, 
					  test_srv->stun_cfg->ioqueue,
					  &stun_sock_cb, test_srv, 
					  &test_srv->stun_sock, NULL);
	if (status != PJ_SUCCESS) {
	    destroy_test_server(test_srv);
	    return status;
	}

	status = pj_activesock_start_recvfrom(test_srv->stun_sock, pool,
					      MAX_STUN_PKT, 0);
	if (status != PJ_SUCCESS) {
	    destroy_test_server(test_srv);
	    return status;
	}

	if (test_srv->dns_server && (flags & CREATE_STUN_SERVER_DNS_SRV)) {
	    pj_str_t res_name, target;
	    pj_dns_parsed_rr rr;
	    pj_in_addr ip_addr;

	    /* Add DNS entries:
	     *  _stun._udp.domain 60 IN SRV 0 0 PORT stun.domain.
	     *  stun.domain IN A 127.0.0.1
	     */
	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
			     "_stun._udp.%s", domain);
	    pj_strdup2(pool, &res_name, strbuf);
	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
			     "stun.%s", domain);
	    pj_strdup2(pool, &target, strbuf);
	    pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0, 
			       STUN_SERVER_PORT, &target);
	    pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);

	    res_name = target;
	    ip_addr = hostip.ipv4.sin_addr;
	    pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
	    pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
	}

    }

    if (flags & CREATE_TURN_SERVER) {
	pj_activesock_cb turn_sock_cb;
	pj_sockaddr bound_addr;

	pj_bzero(&turn_sock_cb, sizeof(turn_sock_cb));
	turn_sock_cb.on_data_recvfrom = &turn_on_data_recvfrom;

	pj_sockaddr_in_init(&bound_addr.ipv4, NULL, TURN_SERVER_PORT);

	status = pj_activesock_create_udp(pool, &bound_addr, NULL, 
					  test_srv->stun_cfg->ioqueue,
					  &turn_sock_cb, test_srv,
					  &test_srv->turn_sock, NULL);
	if (status != PJ_SUCCESS) {
	    destroy_test_server(test_srv);
	    return status;
	}

	status = pj_activesock_start_recvfrom(test_srv->turn_sock, pool,
					      MAX_STUN_PKT, 0);
	if (status != PJ_SUCCESS) {
	    destroy_test_server(test_srv);
	    return status;
	}

	if (test_srv->dns_server && (flags & CREATE_TURN_SERVER_DNS_SRV)) {
	    pj_str_t res_name, target;
	    pj_dns_parsed_rr rr;
	    pj_in_addr ip_addr;

	    /* Add DNS entries:
	     *  _turn._udp.domain 60 IN SRV 0 0 PORT turn.domain.
	     *  turn.domain IN A 127.0.0.1
	     */
	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
			     "_turn._udp.%s", domain);
	    pj_strdup2(pool, &res_name, strbuf);
	    pj_ansi_snprintf(strbuf, sizeof(strbuf),
			     "turn.%s", domain);
	    pj_strdup2(pool, &target, strbuf);
	    pj_dns_init_srv_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, 0, 0, 
			       TURN_SERVER_PORT, &target);
	    pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);

	    res_name = target;
	    ip_addr = hostip.ipv4.sin_addr;
	    pj_dns_init_a_rr(&rr, &res_name, PJ_DNS_CLASS_IN, 60, &ip_addr);
	    pj_dns_server_add_rec(test_srv->dns_server, 1, &rr);
	}
    }

    *p_test_srv = test_srv;
    return PJ_SUCCESS;
}
Esempio n. 4
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;
}
Esempio n. 5
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;
}
Esempio n. 6
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;
    pj_sockaddr bound_addr;
    unsigned i;
    pj_uint16_t max_bind_retry;
    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;
    		stun_sock->timerstat = cfg->timerstat;
    if (stun_sock->ka_interval == 0)
	stun_sock->ka_interval = PJ_STUN_KEEP_ALIVE_SEC;
    printf(": cfg->stunProtocol=%d\n", cfg->stunProtocol);
    printf("%s", cfg->timerstat ? "SBR keepalive enabled\n": "SBR keepalive disabled\n");

    if (cfg->grp_lock) {
	stun_sock->grp_lock = cfg->grp_lock;
    } else {
	status = pj_grp_lock_create(pool, NULL, &stun_sock->grp_lock);
	if (status != PJ_SUCCESS) {
	    pj_pool_release(pool);
	    return status;
	}
    }

    pj_grp_lock_add_ref(stun_sock->grp_lock);
    pj_grp_lock_add_handler(stun_sock->grp_lock, pool, stun_sock,
			    &stun_sock_destructor);

    /* Create socket and bind socket */
//    status = pj_sock_socket(af, pj_SOCK_DGRAM(), 0, &stun_sock->sock_fd);
    if(cfg->stunProtocol == 1)
    status = pj_sock_socket(af, PJ_SOCK_STREAM, 0, &stun_sock->sock_fd);
    else
    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;

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

#if 1
    /* Bind socket */
    max_bind_retry = MAX_BIND_RETRY;
    if (cfg->port_range && cfg->port_range < max_bind_retry)
	max_bind_retry = cfg->port_range;
    pj_sockaddr_init(af, &bound_addr, NULL, 0);
    if (cfg->bound_addr.addr.sa_family == pj_AF_INET() || 
	cfg->bound_addr.addr.sa_family == pj_AF_INET6())
    {
	pj_sockaddr_cp(&bound_addr, &cfg->bound_addr);
    }
    status = pj_sock_bind_random(stun_sock->sock_fd, &bound_addr,
				 cfg->port_range, max_bind_retry);
    if (status != PJ_SUCCESS)
	goto on_error;
#endif

    /* 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.grp_lock = stun_sock->grp_lock;
	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;
        if(cfg->stunProtocol == 1)
	{
	status = pj_activesock_create(pool, stun_sock->sock_fd, 
				      PJ_SOCK_STREAM, 
				      &activesock_cfg, stun_cfg->ioqueue,
				      &activesock_cb, stun_sock,
				      &stun_sock->active_sock);
	}
	else
	{
	    status = pj_activesock_create(pool, stun_sock->sock_fd, 
				      pj_SOCK_DGRAM(), 		//nish
				      &activesock_cfg, stun_cfg->ioqueue,
				      &activesock_cb, stun_sock,
				      &stun_sock->active_sock);
	}

	if (status != PJ_SUCCESS)
	    goto on_error;
        if(cfg->stunProtocol == 1)
	{
		stun_sock->srv_addr.addr.sa_family = AF_INET;
		stun_sock->srv_addr.ipv4.sin_port= pj_htons(cfg->sin_port);
		stun_sock->srv_addr.ipv4.sin_addr = (cfg->sin_addr);

		status=pj_activesock_start_connect(stun_sock->active_sock, 
				pool,
				&(stun_sock->srv_addr), 
				pj_sockaddr_get_len(&(stun_sock->srv_addr)));

		if (status == PJ_SUCCESS) {
			printf("actie sock connect succesful");
		}
	}

	
	/* 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;
//	stun_sock->stunProtocol = 1; //FIXME: cfg->stunProtocol;
//	stun_sock->stunProtocol = 0; //FIXME: cfg->stunProtocol;
	printf(" stun_sock->stunProtocol=%d\n", stun_sock->stunProtocol);
	status = pj_stun_session_create(&stun_sock->stun_cfg, 
					stun_sock->obj_name,
					&sess_cb, PJ_FALSE, 
					stun_sock->grp_lock,
					&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;
}