/* Create and send successful response */ static void send_reply_ok(pj_turn_allocation *alloc, const pj_stun_rx_data *rdata) { pj_status_t status; unsigned interval; pj_stun_tx_data *tdata; status = pj_stun_session_create_res(alloc->sess, rdata, 0, NULL, &tdata); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error creating STUN success response", status); return; } /* Calculate time to expiration */ if (alloc->relay.lifetime != 0) { pj_time_val now; pj_gettimeofday(&now); interval = alloc->relay.expiry.sec - now.sec; } else { interval = 0; } /* Add LIFETIME if this is not ChannelBind. */ if (PJ_STUN_GET_METHOD(tdata->msg->hdr.type)!=PJ_STUN_CHANNEL_BIND_METHOD){ pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_LIFETIME, interval); /* Add BANDWIDTH if lifetime is not zero */ if (interval != 0) { pj_stun_msg_add_uint_attr(tdata->pool, tdata->msg, PJ_STUN_ATTR_BANDWIDTH, alloc->bandwidth); } } status = pj_stun_session_send_msg(alloc->sess, NULL, PJ_TRUE, PJ_FALSE, &alloc->hkey.clt_addr, pj_sockaddr_get_len(&alloc->hkey.clt_addr), tdata); if (status != PJ_SUCCESS) { alloc_err(alloc, "Error sending STUN success response", status); return; } }
/* 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; }