blob: ff74c715f19e621d81a36370d3da969863d99418 [file] [log] [blame]
#include "helper.h"
#include "../ice_gatherer/gatherer.h"
#include "../ice_server/server.h"
#include <rawrtc/main.h>
#include <rawrtcc/code.h>
#include <rawrtcc/utils.h>
#include <re.h>
#include <rew.h>
/*
* Destructor for an existing candidate helper.
*/
static void rawrtc_candidate_helper_destroy(void* arg) {
struct rawrtc_candidate_helper* const local_candidate = arg;
// Un-reference
list_flush(&local_candidate->stun_sessions);
mem_deref(local_candidate->udp_helper);
mem_deref(local_candidate->candidate);
mem_deref(local_candidate->gatherer);
}
/*
* Create a candidate helper.
*/
enum rawrtc_code rawrtc_candidate_helper_create(
struct rawrtc_candidate_helper** const candidate_helperp, // de-referenced
struct rawrtc_ice_gatherer* gatherer,
struct ice_lcand* const candidate,
udp_helper_recv_h* const receive_handler,
void* const arg) {
struct rawrtc_candidate_helper* candidate_helper;
enum rawrtc_code error;
// Check arguments
if (!candidate_helperp || !gatherer || !candidate || !receive_handler) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Create candidate helper
candidate_helper = mem_zalloc(sizeof(*candidate_helper), rawrtc_candidate_helper_destroy);
if (!candidate_helper) {
return RAWRTC_CODE_NO_MEMORY;
}
// Set fields
candidate_helper->gatherer = mem_ref(gatherer);
candidate_helper->candidate = mem_ref(candidate);
candidate_helper->srflx_pending_count = 0;
candidate_helper->relay_pending_count = 0;
// Set receive handler
error = rawrtc_candidate_helper_set_receive_handler(candidate_helper, receive_handler, arg);
if (error) {
goto out;
}
out:
if (error) {
mem_deref(candidate_helper);
} else {
// Set pointer
*candidate_helperp = candidate_helper;
}
return error;
}
/*
* Set a candidate helper's receive handler.
*/
enum rawrtc_code rawrtc_candidate_helper_set_receive_handler(
struct rawrtc_candidate_helper* const candidate_helper,
udp_helper_recv_h* const receive_handler,
void* const arg) {
enum rawrtc_code error;
struct udp_helper* udp_helper;
struct udp_sock* udp_socket;
// Check arguments
if (!candidate_helper || !receive_handler) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Get local candidate's UDP socket
udp_socket = trice_lcand_sock(candidate_helper->gatherer->ice, candidate_helper->candidate);
if (!udp_socket) {
return RAWRTC_CODE_NO_SOCKET;
}
// Create UDP helper
error = rawrtc_error_to_code(udp_register_helper(
&udp_helper, udp_socket, RAWRTC_LAYER_DTLS_SRTP_STUN, NULL, receive_handler, arg));
if (error) {
return error;
}
// Unset current helper (if any) and set new helper
mem_deref(candidate_helper->udp_helper);
candidate_helper->udp_helper = udp_helper;
// TODO: What about TCP helpers?
// Done
return RAWRTC_CODE_SUCCESS;
}
/*
* Find a specific candidate helper by re candidate.
*/
enum rawrtc_code rawrtc_candidate_helper_find(
struct rawrtc_candidate_helper** const candidate_helperp,
struct list* const candidate_helpers,
struct ice_lcand* re_candidate) {
struct le* le;
// Check arguments
if (!candidate_helperp || !candidate_helpers || !re_candidate) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Lookup candidate helper
for (le = list_head(candidate_helpers); le != NULL; le = le->next) {
struct rawrtc_candidate_helper* const candidate_helper = le->data;
if (candidate_helper->candidate->us == re_candidate->us) {
// Found
*candidate_helperp = candidate_helper;
return RAWRTC_CODE_SUCCESS;
}
}
// Not found
return RAWRTC_CODE_NO_VALUE;
}
static void rawrtc_candidate_helper_stun_session_destroy(void* arg) {
struct rawrtc_candidate_helper_stun_session* const session = arg;
// Remove from list
list_unlink(&session->le);
// Un-reference
mem_deref(session->url);
mem_deref(session->stun_keepalive);
mem_deref(session->candidate_helper);
}
/*
* Create a STUN session.
*/
enum rawrtc_code rawrtc_candidate_helper_stun_session_create(
struct rawrtc_candidate_helper_stun_session** const sessionp, // de-referenced
struct rawrtc_ice_server_url* const url) {
struct rawrtc_candidate_helper_stun_session* session;
// Check arguments
if (!sessionp || !url) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Allocate
session = mem_zalloc(sizeof(*session), rawrtc_candidate_helper_stun_session_destroy);
if (!session) {
return RAWRTC_CODE_NO_MEMORY;
}
// Set fields/reference
session->url = mem_ref(url);
session->pending = true;
// Set pointer & done
*sessionp = session;
return RAWRTC_CODE_SUCCESS;
}
/*
* Add a STUN session to a candidate helper.
*/
enum rawrtc_code rawrtc_candidate_helper_stun_session_add(
struct rawrtc_candidate_helper_stun_session* const session,
struct rawrtc_candidate_helper* const candidate_helper,
struct stun_keepalive* const stun_keepalive) {
// Check arguments
if (!session || !candidate_helper || !stun_keepalive) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Set fields/reference
session->candidate_helper = mem_ref(candidate_helper);
session->stun_keepalive = mem_ref(stun_keepalive);
// Append to STUN sessions
list_append(&candidate_helper->stun_sessions, &session->le, session);
// Done
return RAWRTC_CODE_SUCCESS;
}
/*
* Remove STUN sessions list handler (for candidate helper lists).
*/
bool rawrtc_candidate_helper_remove_stun_sessions_handler(struct le* le, void* arg) {
struct rawrtc_candidate_helper* const candidate_helper = le->data;
(void) arg;
// Flush STUN sessions
list_flush(&candidate_helper->stun_sessions);
return false; // continue traversing
}