/* Send application data */ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, pj_ioqueue_op_key_t *send_key, const void *pkt, unsigned pkt_len, unsigned flag, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_ssize_t size; pj_status_t status; pj_bool_t is_stun = PJ_FALSE; pj_bool_t is_tnl_data = PJ_FALSE; PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL); pj_grp_lock_acquire(stun_sock->grp_lock); if (!stun_sock->active_sock) { /* We have been shutdown, but this callback may still get called * by retransmit timer. */ pj_grp_lock_release(stun_sock->grp_lock); return PJ_EINVALIDOP; } if (send_key==NULL) send_key = &stun_sock->send_key; size = pkt_len; if (!stun_sock || !stun_sock->active_sock) return PJ_EINVALIDOP; /* Check that this is STUN message */ status = pj_stun_msg_check((const pj_uint8_t*)pkt, size, PJ_STUN_IS_DATAGRAM | PJ_STUN_CHECK_PACKET); if (status == PJ_SUCCESS) is_stun = PJ_TRUE; else is_tnl_data = (((pj_uint8_t*)pkt)[pkt_len] == 1); if(is_stun || !is_tnl_data) { pj_ioqueue_op_key_t *op_key = (pj_ioqueue_op_key_t*)pj_mem_alloc(sizeof(pj_ioqueue_op_key_t)); pj_ioqueue_op_key_init(op_key, sizeof(pj_ioqueue_op_key_t)); status = pj_activesock_sendto(stun_sock->active_sock, op_key, pkt, &size, (flag | PJ_IOQUEUE_URGENT_DATA), dst_addr, addr_len); } else { status = pj_activesock_sendto(stun_sock->active_sock, &stun_sock->send_key, pkt, &size, flag, dst_addr, addr_len); } pj_grp_lock_release(stun_sock->grp_lock); return status; }
/* This callback is called by the STUN session to send packet */ static pj_status_t sess_on_send_msg(pj_stun_session *sess, void *token, const void *pkt, pj_size_t pkt_size, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_stun_sock *stun_sock; pj_ssize_t size; stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); if (!stun_sock || !stun_sock->active_sock) { /* We have been shutdown, but this callback may still get called * by retransmit timer. */ return PJ_EINVALIDOP; } pj_assert(token==INTERNAL_MSG_TOKEN); PJ_UNUSED_ARG(token); size = pkt_size; return pj_activesock_sendto(stun_sock->active_sock, &stun_sock->int_send_key, pkt, &size, 0, dst_addr, addr_len); }
/* Send application data */ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, pj_ioqueue_op_key_t *send_key, const void *pkt, unsigned pkt_len, unsigned flag, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_ssize_t size; pj_status_t status; PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL); pj_grp_lock_acquire(stun_sock->grp_lock); if (!stun_sock->active_sock) { /* We have been shutdown, but this callback may still get called * by retransmit timer. */ pj_grp_lock_release(stun_sock->grp_lock); return PJ_EINVALIDOP; } if (send_key==NULL) send_key = &stun_sock->send_key; size = pkt_len; status = pj_activesock_sendto(stun_sock->active_sock, send_key, pkt, &size, flag, dst_addr, addr_len); pj_grp_lock_release(stun_sock->grp_lock); return status; }
/* This callback is called by the STUN session to send packet */ static pj_status_t sess_on_send_msg(pj_stun_session *sess, void *token, const void *pkt, pj_size_t pkt_size, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_stun_sock *stun_sock; pj_ssize_t size; pj_status_t status; pj_bool_t is_stun = PJ_FALSE; pj_bool_t is_tnl_data = PJ_FALSE; stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); if (!stun_sock || !stun_sock->active_sock) { /* We have been shutdown, but this callback may still get called * by retransmit timer. */ return PJ_EINVALIDOP; } pj_assert(token==INTERNAL_MSG_TOKEN); PJ_UNUSED_ARG(token); /* Check that this is STUN message */ status = pj_stun_msg_check((const pj_uint8_t*)pkt, pkt_size, /*PJ_STUN_IS_DATAGRAM | */PJ_STUN_CHECK_PACKET); if (status == PJ_SUCCESS) is_stun = PJ_TRUE; else is_tnl_data = (((pj_uint8_t*)pkt)[pkt_size] == 1); size = pkt_size; if(is_stun || !is_tnl_data) { pj_ioqueue_op_key_t *op_key = (pj_ioqueue_op_key_t*)pj_mem_alloc(sizeof(pj_ioqueue_op_key_t)); pj_ioqueue_op_key_init(op_key, sizeof(pj_ioqueue_op_key_t)); return pj_activesock_sendto(stun_sock->active_sock, op_key, pkt, &size, PJ_IOQUEUE_URGENT_DATA, dst_addr, addr_len); } else { return pj_activesock_sendto(stun_sock->active_sock, &stun_sock->send_key, pkt, &size, 0, dst_addr, addr_len); } }
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; }
/* Send application data */ PJ_DEF(pj_status_t) pj_stun_sock_sendto( pj_stun_sock *stun_sock, pj_ioqueue_op_key_t *send_key, const void *pkt, unsigned pkt_len, unsigned flag, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_ssize_t size; PJ_ASSERT_RETURN(stun_sock && pkt && dst_addr && addr_len, PJ_EINVAL); if (send_key==NULL) send_key = &stun_sock->send_key; size = pkt_len; return pj_activesock_sendto(stun_sock->active_sock, send_key, pkt, &size, flag, dst_addr, addr_len); }
/* This callback is called by the STUN session to send packet */ static pj_status_t sess_on_send_msg(pj_stun_session *sess, void *token, const void *pkt, pj_size_t pkt_size, const pj_sockaddr_t *dst_addr, unsigned addr_len) { pj_stun_sock *stun_sock; pj_ssize_t size; stun_sock = (pj_stun_sock *) pj_stun_session_get_user_data(sess); pj_assert(token==INTERNAL_MSG_TOKEN); PJ_UNUSED_ARG(token); size = pkt_size; return pj_activesock_sendto(stun_sock->active_sock, &stun_sock->int_send_key, pkt, &size, 0, dst_addr, addr_len); }
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; }
/* 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; }
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; }
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; }
/******************************************************************* * UDP ping pong test (send packet back and forth between two UDP echo * servers. */ static int udp_ping_pong_test(void) { pj_ioqueue_t *ioqueue = NULL; pj_pool_t *pool = NULL; struct udp_echo_srv *srv1=NULL, *srv2=NULL; pj_bool_t need_send = PJ_TRUE; unsigned data = 0; int count, ret; pj_status_t status; pool = pj_pool_create(mem, "pingpong", 512, 512, NULL); if (!pool) return -10; status = pj_ioqueue_create(pool, 4, &ioqueue); if (status != PJ_SUCCESS) { ret = -20; udp_echo_err("pj_ioqueue_create()", status); goto on_return; } status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv1); if (status != PJ_SUCCESS) { ret = -30; goto on_return; } status = udp_echo_srv_create(pool, ioqueue, PJ_TRUE, &srv2); if (status != PJ_SUCCESS) { ret = -40; goto on_return; } /* initiate the first send */ for (count=0; count<1000; ++count) { unsigned last_rx1, last_rx2; unsigned i; if (need_send) { pj_str_t loopback; pj_sockaddr_in addr; pj_ssize_t sent; ++data; sent = sizeof(data); loopback = pj_str("127.0.0.1"); pj_sockaddr_in_init(&addr, &loopback, srv2->port); status = pj_activesock_sendto(srv1->asock, &srv1->send_key, &data, &sent, 0, &addr, sizeof(addr)); if (status != PJ_SUCCESS && status != PJ_EPENDING) { ret = -50; udp_echo_err("sendto()", status); goto on_return; } need_send = PJ_FALSE; } last_rx1 = srv1->rx_cnt; last_rx2 = srv2->rx_cnt; for (i=0; i<10 && last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt; ++i) { pj_time_val delay = {0, 10}; #ifdef PJ_SYMBIAN pj_symbianos_poll(-1, 100); #else pj_ioqueue_poll(ioqueue, &delay); #endif } if (srv1->rx_err_cnt+srv1->tx_err_cnt != 0 || srv2->rx_err_cnt+srv2->tx_err_cnt != 0) { /* Got error */ ret = -60; goto on_return; } if (last_rx1 == srv1->rx_cnt && last_rx2 == srv2->rx_cnt) { /* Packet lost */ ret = -70; udp_echo_err("packets have been lost", PJ_ETIMEDOUT); goto on_return; } } ret = 0; on_return: if (srv2) udp_echo_srv_destroy(srv2); if (srv1) udp_echo_srv_destroy(srv1); if (ioqueue) pj_ioqueue_destroy(ioqueue); if (pool) pj_pool_release(pool); return ret; }