blob: a6bee78eef092cfb2d0770ac49017f083243ca9d [file] [log] [blame]
#include "candidate.h"
#include <rawrtc/ice_candidate.h>
#include <rawrtcc/code.h>
#include <re.h>
#include <netinet/in.h> // IPPROTO_UDP, IPPROTO_TCP
/*
* Translate an ICE candidate type to the corresponding re type.
*/
enum ice_cand_type rawrtc_ice_candidate_type_to_ice_cand_type(
enum rawrtc_ice_candidate_type const type) {
// No conversion needed
return (enum ice_cand_type) type;
}
/*
* Translate a re ICE candidate type to the corresponding rawrtc type.
*/
enum rawrtc_code rawrtc_ice_cand_type_to_ice_candidate_type(
enum rawrtc_ice_candidate_type* const typep, // de-referenced
enum ice_cand_type const re_type) {
// Check arguments
if (!typep) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert ice_cand_type
switch (re_type) {
case ICE_CAND_TYPE_HOST:
*typep = RAWRTC_ICE_CANDIDATE_TYPE_HOST;
return RAWRTC_CODE_SUCCESS;
case ICE_CAND_TYPE_SRFLX:
*typep = RAWRTC_ICE_CANDIDATE_TYPE_SRFLX;
return RAWRTC_CODE_SUCCESS;
case ICE_CAND_TYPE_PRFLX:
*typep = RAWRTC_ICE_CANDIDATE_TYPE_PRFLX;
return RAWRTC_CODE_SUCCESS;
case ICE_CAND_TYPE_RELAY:
*typep = RAWRTC_ICE_CANDIDATE_TYPE_RELAY;
return RAWRTC_CODE_SUCCESS;
default:
return RAWRTC_CODE_INVALID_ARGUMENT;
}
}
/*
* Translate an ICE TCP candidate type to the corresponding re type.
*/
enum ice_tcptype rawrtc_ice_tcp_candidate_type_to_ice_tcptype(
enum rawrtc_ice_tcp_candidate_type const type) {
// No conversion needed
return (enum ice_tcptype) type;
}
/*
* Translate a re ICE TCP candidate type to the corresponding rawrtc type.
*/
enum rawrtc_code rawrtc_ice_tcptype_to_ice_tcp_candidate_type(
enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
enum ice_tcptype const re_type) {
// Check arguments
if (!typep) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert ice_cand_type
switch (re_type) {
case ICE_TCP_ACTIVE:
*typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
return RAWRTC_CODE_SUCCESS;
case ICE_TCP_PASSIVE:
*typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_PASSIVE;
return RAWRTC_CODE_SUCCESS;
case ICE_TCP_SO:
*typep = RAWRTC_ICE_TCP_CANDIDATE_TYPE_SO;
return RAWRTC_CODE_SUCCESS;
default:
return RAWRTC_CODE_INVALID_ARGUMENT;
}
}
/*
* Translate a protocol to the corresponding IPPROTO_*.
*/
int rawrtc_ice_protocol_to_ipproto(enum rawrtc_ice_protocol const protocol) {
// No conversion needed
return (int) protocol;
}
/*
* Translate a IPPROTO_* to the corresponding protocol.
*/
enum rawrtc_code rawrtc_ipproto_to_ice_protocol(
enum rawrtc_ice_protocol* const protocolp, // de-referenced
int const ipproto) {
// Check arguments
if (!protocolp) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert IPPROTO_*
switch (ipproto) {
case IPPROTO_UDP:
*protocolp = RAWRTC_ICE_PROTOCOL_UDP;
return RAWRTC_CODE_SUCCESS;
case IPPROTO_TCP:
*protocolp = RAWRTC_ICE_PROTOCOL_TCP;
return RAWRTC_CODE_SUCCESS;
default:
return RAWRTC_CODE_INVALID_ARGUMENT;
}
}
static enum rawrtc_ice_protocol const map_enum_ice_protocol[] = {
RAWRTC_ICE_PROTOCOL_UDP,
RAWRTC_ICE_PROTOCOL_TCP,
};
static char const* const map_str_ice_protocol[] = {
"udp",
"tcp",
};
static size_t const map_ice_protocol_length = ARRAY_SIZE(map_enum_ice_protocol);
/*
* Translate an ICE protocol to str.
*/
char const* rawrtc_ice_protocol_to_str(enum rawrtc_ice_protocol const protocol) {
size_t i;
for (i = 0; i < map_ice_protocol_length; ++i) {
if (map_enum_ice_protocol[i] == protocol) {
return map_str_ice_protocol[i];
}
}
return "???";
}
/*
* Translate a pl to an ICE protocol (case-insensitive).
*/
enum rawrtc_code rawrtc_pl_to_ice_protocol(
enum rawrtc_ice_protocol* const protocolp, // de-referenced
struct pl const* const pl) {
size_t i;
// Check arguments
if (!protocolp || !pl_isset(pl)) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
for (i = 0; i < map_ice_protocol_length; ++i) {
if (pl_strcasecmp(pl, map_str_ice_protocol[i]) == 0) {
*protocolp = map_enum_ice_protocol[i];
return RAWRTC_CODE_SUCCESS;
}
}
return RAWRTC_CODE_NO_VALUE;
}
/*
* Translate a str to an ICE protocol (case-insensitive).
*/
enum rawrtc_code rawrtc_str_to_ice_protocol(
enum rawrtc_ice_protocol* const protocolp, // de-referenced
char const* const str) {
struct pl pl;
// Check arguments
if (!str) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert str to pl
pl_set_str(&pl, str);
return rawrtc_pl_to_ice_protocol(protocolp, &pl);
}
static enum rawrtc_ice_candidate_type const map_enum_ice_candidate_type[] = {
RAWRTC_ICE_CANDIDATE_TYPE_HOST,
RAWRTC_ICE_CANDIDATE_TYPE_SRFLX,
RAWRTC_ICE_CANDIDATE_TYPE_PRFLX,
RAWRTC_ICE_CANDIDATE_TYPE_RELAY,
};
static char const* const map_str_ice_candidate_type[] = {
"host",
"srflx",
"prflx",
"relay",
};
static size_t const map_ice_candidate_type_length = ARRAY_SIZE(map_enum_ice_candidate_type);
/*
* Translate an ICE candidate type to str.
*/
char const* rawrtc_ice_candidate_type_to_str(enum rawrtc_ice_candidate_type const type) {
size_t i;
for (i = 0; i < map_ice_candidate_type_length; ++i) {
if (map_enum_ice_candidate_type[i] == type) {
return map_str_ice_candidate_type[i];
}
}
return "???";
}
/*
* Translate a pl to an ICE candidate type (case-insensitive).
*/
enum rawrtc_code rawrtc_pl_to_ice_candidate_type(
enum rawrtc_ice_candidate_type* const typep, // de-referenced
struct pl const* const pl) {
size_t i;
// Check arguments
if (!typep || !pl_isset(pl)) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
for (i = 0; i < map_ice_candidate_type_length; ++i) {
if (pl_strcasecmp(pl, map_str_ice_candidate_type[i]) == 0) {
*typep = map_enum_ice_candidate_type[i];
return RAWRTC_CODE_SUCCESS;
}
}
return RAWRTC_CODE_NO_VALUE;
}
/*
* Translate a str to an ICE candidate type (case-insensitive).
*/
enum rawrtc_code rawrtc_str_to_ice_candidate_type(
enum rawrtc_ice_candidate_type* const typep, // de-referenced
char const* const str) {
struct pl pl;
// Check arguments
if (!str) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert str to pl
pl_set_str(&pl, str);
return rawrtc_pl_to_ice_candidate_type(typep, &pl);
}
static enum rawrtc_ice_tcp_candidate_type const map_enum_ice_tcp_candidate_type[] = {
RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE,
RAWRTC_ICE_TCP_CANDIDATE_TYPE_PASSIVE,
RAWRTC_ICE_TCP_CANDIDATE_TYPE_SO,
};
static char const* const map_str_ice_tcp_candidate_type[] = {
"active",
"passive",
"so",
};
static size_t const map_ice_tcp_candidate_type_length = ARRAY_SIZE(map_enum_ice_tcp_candidate_type);
/*
* Translate an ICE TCP candidate type to str.
*/
char const* rawrtc_ice_tcp_candidate_type_to_str(enum rawrtc_ice_tcp_candidate_type const type) {
size_t i;
for (i = 0; i < map_ice_tcp_candidate_type_length; ++i) {
if (map_enum_ice_tcp_candidate_type[i] == type) {
return map_str_ice_tcp_candidate_type[i];
}
}
return "???";
}
/*
* Translate a str to an ICE TCP candidate type (case-insensitive).
*/
enum rawrtc_code rawrtc_pl_to_ice_tcp_candidate_type(
enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
struct pl const* const pl) {
size_t i;
// Check arguments
if (!typep || !pl_isset(pl)) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
for (i = 0; i < map_ice_tcp_candidate_type_length; ++i) {
if (pl_strcasecmp(pl, map_str_ice_tcp_candidate_type[i]) == 0) {
*typep = map_enum_ice_tcp_candidate_type[i];
return RAWRTC_CODE_SUCCESS;
}
}
return RAWRTC_CODE_NO_VALUE;
}
/*
* Translate a str to an ICE TCP candidate type (case-insensitive).
*/
enum rawrtc_code rawrtc_str_to_ice_tcp_candidate_type(
enum rawrtc_ice_tcp_candidate_type* const typep, // de-referenced
char const* const str) {
struct pl pl;
// Check arguments
if (!str) {
return RAWRTC_CODE_INVALID_ARGUMENT;
}
// Convert str to pl
pl_set_str(&pl, str);
return rawrtc_pl_to_ice_tcp_candidate_type(typep, &pl);
}
static char const* const map_str_ice_candidate_storage[] = {
"raw",
"lcand",
"rcand",
};
static enum rawrtc_ice_candidate_storage const map_enum_ice_candidate_storage[] = {
RAWRTC_ICE_CANDIDATE_STORAGE_RAW,
RAWRTC_ICE_CANDIDATE_STORAGE_LCAND,
RAWRTC_ICE_CANDIDATE_STORAGE_RCAND,
};
static size_t const map_ice_candidate_storage_length = ARRAY_SIZE(map_enum_ice_candidate_storage);
/*
* Translate an ICE candidate storage type to str.
*/
static char const* ice_candidate_storage_to_str(enum rawrtc_ice_candidate_storage const type) {
size_t i;
for (i = 0; i < map_ice_candidate_storage_length; ++i) {
if (map_enum_ice_candidate_storage[i] == type) {
return map_str_ice_candidate_storage[i];
}
}
return "???";
}
/*
* Print debug information for an ICE candidate.
*/
int rawrtc_ice_candidate_debug(
struct re_printf* const pf, struct rawrtc_ice_candidate* const candidate) {
int err = 0;
enum rawrtc_code error;
char* foundation = NULL;
uint32_t priority;
char* ip = NULL;
enum rawrtc_ice_protocol protocol;
uint16_t port;
enum rawrtc_ice_candidate_type type;
enum rawrtc_ice_tcp_candidate_type tcp_type;
char* related_address = NULL;
uint16_t related_port;
// Check arguments
if (!candidate) {
return 0;
}
err |= re_hprintf(pf, " ICE Candidate <%p>:\n", candidate);
// Storage type
err |= re_hprintf(
pf, " storage_type=%s\n", ice_candidate_storage_to_str(candidate->storage_type));
// Foundation
error = rawrtc_ice_candidate_get_foundation(&foundation, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " foundation=\"%s\"\n", foundation);
// Priority
error = rawrtc_ice_candidate_get_priority(&priority, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " priority=%" PRIu32 "\n", priority);
// IP
error = rawrtc_ice_candidate_get_ip(&ip, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " ip=%s\n", ip);
// Protocol
error = rawrtc_ice_candidate_get_protocol(&protocol, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " protocol=%s\n", rawrtc_ice_protocol_to_str(protocol));
// Port
error = rawrtc_ice_candidate_get_port(&port, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " port=%" PRIu16 "\n", port);
// Type
error = rawrtc_ice_candidate_get_type(&type, candidate);
if (error) {
goto out;
}
err |= re_hprintf(pf, " type=%s\n", rawrtc_ice_candidate_type_to_str(type));
// TCP type (if any)
err |= re_hprintf(pf, " tcp_type=");
error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate);
switch (error) {
case RAWRTC_CODE_SUCCESS:
err |= re_hprintf(pf, "%s\n", rawrtc_ice_tcp_candidate_type_to_str(tcp_type));
break;
case RAWRTC_CODE_NO_VALUE:
err |= re_hprintf(pf, "n/a\n");
break;
default:
goto out;
}
// Related address (if any)
err |= re_hprintf(pf, " related_address=");
error = rawrtc_ice_candidate_get_related_address(&related_address, candidate);
switch (error) {
case RAWRTC_CODE_SUCCESS:
err |= re_hprintf(pf, "%s\n", related_address);
break;
case RAWRTC_CODE_NO_VALUE:
err |= re_hprintf(pf, "n/a\n");
break;
default:
goto out;
}
// Related port (if any)
err |= re_hprintf(pf, " related_port=");
error = rawrtc_ice_candidate_get_related_port(&related_port, candidate);
switch (error) {
case RAWRTC_CODE_SUCCESS:
err |= re_hprintf(pf, "%" PRIu16 "\n", related_port);
break;
case RAWRTC_CODE_NO_VALUE:
err |= re_hprintf(pf, "n/a\n");
break;
default:
goto out;
}
out:
// Un-reference
mem_deref(related_address);
mem_deref(ip);
mem_deref(foundation);
// Translate error & done
if (!err && error) {
err = EINVAL;
}
return err;
}