turn_usage.c
来自「一个开源的sip源代码」· C语言 代码 · 共 1,431 行 · 第 1/3 页
C
1,431 行
/* Process REQUESTED-IP attribute */
if (a_rip && a_rip->sockaddr.addr.sa_family != PJ_AF_INET) {
client_respond(client, msg, PJ_STUN_SC_INVALID_IP_ADDR, NULL,
src_addr, src_addr_len);
return PJ_SUCCESS;
} else if (a_rip) {
req_addr.sin_addr.s_addr = a_rip->sockaddr.ipv4.sin_addr.s_addr;
}
/* Process REQUESTED-PORT-PROPS attribute */
if (a_rpp) {
unsigned port;
rpp_bits = (a_rpp->value & 0x00030000) >> 16;
port = (a_rpp->value & 0xFFFF);
req_addr.sin_port = pj_htons((pj_uint8_t)port);
} else {
rpp_bits = 0;
}
/* Process LIFETIME attribute */
if (a_lf && a_lf->value > client->tu->max_lifetime) {
client->lifetime = client->tu->max_lifetime;
} else if (a_lf) {
client->lifetime = a_lf->value;
} else {
client->lifetime = client->tu->max_lifetime;
}
/* Allocate socket if we don't have one */
if (client->key == NULL) {
int err_code;
PJ_LOG(4,(THIS_FILE, "TURN client %s: received initial Allocate "
"request, requested type:addr:port=%s:%s:%d, rpp "
"bits=%d, bw=%dkbps, lifetime=%d",
client->obj_name, get_tp_type(client->sock_type),
pj_inet_ntoa(req_addr.sin_addr), pj_ntohs(req_addr.sin_port),
rpp_bits, client->bw_kbps, client->lifetime));
status = tu_alloc_port(client->tu, client->sock_type, rpp_bits,
&req_addr, &client->sock, &err_code);
if (status != PJ_SUCCESS) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(status, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE, "TURN client %s: error allocating relay port"
": %s",
client->obj_name, errmsg));
client_respond(client, msg, err_code, NULL,
src_addr, src_addr_len);
return status;
}
status = client_create_relay(client);
if (status != PJ_SUCCESS) {
client_respond(client, msg, PJ_STUN_SC_SERVER_ERROR, NULL,
src_addr, src_addr_len);
return status;
}
} else {
/* Otherwise check if the port parameter stays the same */
/* TODO */
PJ_LOG(4,(THIS_FILE, "TURN client %s: received Allocate refresh, "
"lifetime=%d",
client->obj_name, client->lifetime));
}
/* Refresh timer */
if (client->expiry_timer.id != PJ_FALSE) {
pj_timer_heap_cancel(client->tu->timer_heap, &client->expiry_timer);
client->expiry_timer.id = PJ_FALSE;
}
timeout.sec = client->lifetime;
timeout.msec = 0;
pj_timer_heap_schedule(client->tu->timer_heap, &client->expiry_timer, &timeout);
client->expiry_timer.id = PJ_TRUE;
/* Done successfully, create and send success response */
status = pj_stun_session_create_res(client->session, msg,
0, NULL, &response);
if (status != PJ_SUCCESS) {
return status;
}
pj_stun_msg_add_uint_attr(response->pool, response->msg,
PJ_STUN_ATTR_BANDWIDTH, client->bw_kbps);
pj_stun_msg_add_uint_attr(response->pool, response->msg,
PJ_STUN_ATTR_LIFETIME, client->lifetime);
pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_MAPPED_ADDR, PJ_FALSE,
src_addr, src_addr_len);
pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_XOR_MAPPED_ADDR, PJ_TRUE,
src_addr, src_addr_len);
addr_len = sizeof(req_addr);
pj_sock_getsockname(client->sock, &req_addr, &addr_len);
pj_stun_msg_add_sockaddr_attr(response->pool, response->msg,
PJ_STUN_ATTR_RELAY_ADDR, PJ_FALSE,
&client->alloc_addr, addr_len);
PJ_LOG(4,(THIS_FILE, "TURN client %s: relay allocated or refreshed, "
"internal address is %s:%s:%d",
client->obj_name,
get_tp_type(client->sock_type),
pj_inet_ntoa(req_addr.sin_addr),
(int)pj_ntohs(req_addr.sin_port)));
return pj_stun_session_send_msg(client->session, PJ_TRUE,
src_addr, src_addr_len, response);
}
/*
* Handle incoming Binding request.
* This function is called by client_handle_stun_msg() below.
*/
static pj_status_t handle_binding_req(pj_stun_session *session,
const pj_stun_msg *msg,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len)
{
pj_stun_tx_data *tdata;
pj_status_t status;
/* Create response */
status = pj_stun_session_create_res(session, msg, 0, NULL,
&tdata);
if (status != PJ_SUCCESS)
return status;
/* Create MAPPED-ADDRESS attribute */
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_MAPPED_ADDR,
PJ_FALSE,
src_addr, src_addr_len);
/* On the presence of magic, create XOR-MAPPED-ADDRESS attribute */
if (msg->hdr.magic == PJ_STUN_MAGIC) {
status =
pj_stun_msg_add_sockaddr_attr(tdata->pool, tdata->msg,
PJ_STUN_ATTR_XOR_MAPPED_ADDR,
PJ_TRUE,
src_addr, src_addr_len);
}
/* Send */
status = pj_stun_session_send_msg(session, PJ_TRUE,
src_addr, src_addr_len, tdata);
return status;
}
/*
* client handling incoming STUN Set Active Destination request
* This function is called by client_handle_stun_msg() below.
*/
static pj_status_t client_handle_sad(struct turn_client *client,
const pj_stun_msg *msg,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len)
{
pj_stun_remote_addr_attr *a_raddr;
a_raddr = (pj_stun_remote_addr_attr*)
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REMOTE_ADDR, 0);
if (!a_raddr) {
/* Remote active destination needs to be cleared */
client->active_peer = NULL;
} else if (a_raddr->sockaddr.addr.sa_family != PJ_AF_INET) {
/* Bad request (not IPv4) */
client_respond(client, msg, PJ_STUN_SC_BAD_REQUEST, NULL,
src_addr, src_addr_len);
return PJ_SUCCESS;
} else if (client->active_peer) {
/* Client tries to set new active destination without clearing
* it first. Reject with 439.
*/
client_respond(client, msg, PJ_STUN_SC_TRANSITIONING, NULL,
src_addr, src_addr_len);
return PJ_SUCCESS;
} else {
struct peer *peer;
pj_uint32_t hval = 0;
/* Add a new peer/permission if we don't have one for this address */
peer = client_get_peer(client, &a_raddr->sockaddr.ipv4, &hval);
if (peer==NULL) {
peer = client_add_peer(client, &a_raddr->sockaddr.ipv4, hval);
}
/* Set active destination */
client->active_peer = peer;
}
if (client->active_peer) {
PJ_LOG(4,(THIS_FILE,
"TURN client %s: active destination set to %s:%d",
client->obj_name,
pj_inet_ntoa(client->active_peer->addr.sin_addr),
(int)pj_ntohs(client->active_peer->addr.sin_port)));
} else {
PJ_LOG(4,(THIS_FILE, "TURN client %s: active destination cleared",
client->obj_name));
}
/* Respond with successful response */
client_respond(client, msg, 0, NULL, src_addr, src_addr_len);
return PJ_SUCCESS;
}
/*
* client handling incoming STUN Send Indication
* This function is called by client_handle_stun_msg() below.
*/
static pj_status_t client_handle_send_ind(struct turn_client *client,
const pj_stun_msg *msg)
{
pj_stun_remote_addr_attr *a_raddr;
pj_stun_data_attr *a_data;
pj_uint32_t hval = 0;
const pj_uint8_t *data;
pj_ssize_t datalen;
/* Get REMOTE-ADDRESS attribute */
a_raddr = (pj_stun_remote_addr_attr*)
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_REMOTE_ADDR, 0);
if (!a_raddr) {
/* REMOTE-ADDRESS not present, discard packet */
return PJ_SUCCESS;
} else if (a_raddr->sockaddr.addr.sa_family != PJ_AF_INET) {
/* REMOTE-ADDRESS present but not IPv4, discard packet */
return PJ_SUCCESS;
}
/* Get the DATA attribute */
a_data = (pj_stun_data_attr*)
pj_stun_msg_find_attr(msg, PJ_STUN_ATTR_DATA, 0);
if (a_data) {
data = (const pj_uint8_t *)a_data->data;
datalen = a_data->length;
} else if (client->sock_type == PJ_SOCK_STREAM) {
/* Discard if no Data and Allocation type is TCP */
return PJ_SUCCESS;
} else {
data = (const pj_uint8_t *)"";
datalen = 0;
}
/* Add to peer table if necessary */
if (client_get_peer(client, &a_raddr->sockaddr.ipv4, &hval)==NULL)
client_add_peer(client, &a_raddr->sockaddr.ipv4, hval);
/* Send the packet */
pj_ioqueue_sendto(client->key, &client->pkt_write_key,
data, &datalen, 0,
&a_raddr->sockaddr.ipv4, sizeof(pj_sockaddr_in));
return PJ_SUCCESS;
}
/*
* client handling unknown incoming STUN message.
* This function is called by client_handle_stun_msg() below.
*/
static pj_status_t client_handle_unknown_msg(struct turn_client *client,
const pj_stun_msg *msg,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len)
{
PJ_LOG(4,(THIS_FILE, "TURN client %s: unhandled %s %s",
client->obj_name, pj_stun_get_method_name(msg->hdr.type),
pj_stun_get_class_name(msg->hdr.type)));
if (PJ_STUN_IS_REQUEST(msg->hdr.type)) {
return client_respond(client, msg, PJ_STUN_SC_BAD_REQUEST, NULL,
src_addr, src_addr_len);
} else {
/* Ignore */
return PJ_SUCCESS;
}
}
/*
* Main entry for handling STUN messages arriving on the main TURN port,
* for this client
*/
static pj_status_t client_handle_stun_msg(struct turn_client *client,
const pj_stun_msg *msg,
const pj_sockaddr_t *src_addr,
unsigned src_addr_len)
{
pj_status_t status;
switch (msg->hdr.type) {
case PJ_STUN_SEND_INDICATION:
status = client_handle_send_ind(client, msg);
break;
case PJ_STUN_SET_ACTIVE_DESTINATION_REQUEST:
status = client_handle_sad(client, msg,
src_addr, src_addr_len);
break;
case PJ_STUN_ALLOCATE_REQUEST:
status = client_handle_allocate_req(client, msg,
src_addr, src_addr_len);
break;
case PJ_STUN_BINDING_REQUEST:
status = handle_binding_req(client->session, msg,
src_addr, src_addr_len);
break;
default:
status = client_handle_unknown_msg(client, msg,
src_addr, src_addr_len);
break;
}
return status;
}
PJ_INLINE(pj_uint32_t) GET_VAL32(const pj_uint8_t *pdu, unsigned pos)
{
return (pdu[pos+0] << 24) +
(pdu[pos+1] << 16) +
(pdu[pos+2] << 8) +
(pdu[pos+3]);
}
/*
* Handle incoming data from peer
* This function is called by client_on_read_complete() below.
*/
static void client_handle_peer_data(struct turn_client *client,
unsigned bytes_read)
{
struct peer *peer;
pj_bool_t has_magic_cookie;
pj_status_t status;
/* Has the sender been registered as peer? */
peer = client_get_peer(client, &client->pkt_src_addr, NULL);
if (peer == NULL) {
/* Nope. Discard packet */
PJ_LOG(5,(THIS_FILE,
"TURN client %s: discarded data from %s:%d",
client->obj_name,
pj_inet_ntoa(client->pkt_src_addr.sin_addr),
(int)pj_ntohs(client->pkt_src_addr.sin_port)));
return;
}
/* Check if packet has STUN magic cookie */
has_magic_cookie = (GET_VAL32(client->pkt, 4) == PJ_STUN_MAGIC);
/* If this is the Active Destination and the packet doesn't have
* STUN magic cookie, send the packet to client as is.
*/
if (peer == client->active_peer && !has_magic_cookie) {
pj_stun_usage_sendto(client->tu->usage, client->pkt, bytes_read, 0,
&client->client_src_addr, sizeof(pj_sockaddr_in));
} else {
/* Otherwise wrap in Data Indication */
pj_stun_tx_data *data_ind;
status = pj_stun_session_create_ind(client->session,
PJ_STUN_DATA_INDICATION,
&data_ind);
if (status != PJ_SUCCESS)
return;
pj_stun_msg_add_sockaddr_attr(data_ind->pool, data_ind->msg,
PJ_STUN_ATTR_REMOTE_ADDR, PJ_FALSE,
&client->pkt_src_addr,
client->pkt_src_addr_len);
pj_stun_msg_add_binary_attr(data_ind->pool, data_ind->msg,
PJ_STUN_ATTR_DATA,
client->pkt, bytes_read);
pj_stun_session_send_msg(client->session, PJ_FALSE,
&client->client_src_addr,
sizeof(pj_sockaddr_in),
data_ind);
}
}
/*
* This callback is called by the ioqueue when read operation has
* completed on the allocated relay port.
*/
static void client_on_read_complete(pj_ioqueue_key_t *key,
pj_ioqueue_op_key_t *op_key,
pj_ssize_t bytes_read)
{
enum { MAX_LOOP = 10 };
struct turn_client *client;
unsigned count;
pj_status_t status;
PJ_UNUSED_ARG(op_key);
client = (struct turn_client*) pj_ioqueue_get_user_data(key);
/* Lock client */
pj_mutex_lock(client->mutex);
for (count=0; ; ++count) {
unsigned flags;
if (bytes_read > 0) {
/* Received data from peer! */
client_handle_peer_data(client, bytes_read);
} else if (bytes_read < 0) {
char errmsg[PJ_ERR_MSG_SIZE];
pj_strerror(-bytes_read, errmsg, sizeof(errmsg));
PJ_LOG(4,(THIS_FILE, "TURN client %s: error reading data "
"from allocated relay port: %s",
client->obj_name, errmsg));
}
bytes_read = sizeof(client->pkt);
flags = (count >= MAX_LOOP) ? PJ_IOQUEUE_ALWAYS_ASYNC : 0;
client->pkt_src_addr_len = sizeof(client->pkt_src_addr);
status = pj_ioqueue_recvfrom(client->key,
&client->pkt_read_key,
client->pkt, &bytes_read, flags,
&client->pkt_src_addr,
&client->pkt_src_addr_len);
if (status == PJ_EPENDING)
break;
}
/* Unlock client */
pj_mutex_unlock(client->mutex);
}
/* On Allocation timer timeout (i.e. we don't receive new Allocate request
* to refresh the allocation in time)
*/
static void client_on_expired(pj_timer_heap_t *th, pj_timer_entry *e)
{
struct turn_client *client;
PJ_UNUSED_ARG(th);
client = (struct turn_client*) e->user_data;
PJ_LOG(4,(THIS_FILE, "TURN client %s: allocation timer timeout, "
"destroying client",
client->obj_name));
client_destroy(client, PJ_SUCCESS);
}
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?