blob: eed012582aac5001310e81ebaf0da85e29dbeea5 [file] [log] [blame]
James Kuszmaul4a42b182021-01-17 11:32:46 -08001#include "candidate.h"
2#include <rawrtc/ice_candidate.h>
3#include <rawrtc/peer_connection_ice_candidate.h>
4#include <rawrtcc/code.h>
5#include <rawrtcc/utils.h>
6#include <re.h>
7
8/*
9 * Encode the ICE candidate into SDP.
10 * `*sdpp` will be set to a copy of the SDP attribute that must be
11 * unreferenced.
12 *
13 * Note: This is equivalent to the `candidate` attribute of the W3C
14 * WebRTC specification's `RTCIceCandidateInit`.
15 */
16enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp(
17 char** const sdpp, // de-referenced
18 struct rawrtc_peer_connection_ice_candidate* const candidate) {
19 enum rawrtc_code error;
20 char* foundation = NULL;
21 uint16_t component_id = 1;
22 enum rawrtc_ice_protocol protocol;
23 char const* protocol_str;
24 uint32_t priority;
25 char* ip = NULL;
26 uint16_t port;
27 enum rawrtc_ice_candidate_type type;
28 char const* type_str;
29 struct mbuf* sdp = NULL;
30 char* related_address = NULL;
31 uint16_t related_port = 0;
32 enum rawrtc_ice_tcp_candidate_type tcp_type = RAWRTC_ICE_TCP_CANDIDATE_TYPE_ACTIVE;
33 char const* tcp_type_str;
34
35 // Check arguments
36 if (!sdpp || !candidate) {
37 return RAWRTC_CODE_INVALID_ARGUMENT;
38 }
39
40 // Get values for mandatory fields
41 error = rawrtc_ice_candidate_get_foundation(&foundation, candidate->candidate);
42 if (error) {
43 goto out;
44 }
45 // TODO: Get component ID from candidate/gatherer/transport
46 error = rawrtc_ice_candidate_get_protocol(&protocol, candidate->candidate);
47 if (error) {
48 goto out;
49 }
50 error = rawrtc_ice_candidate_get_priority(&priority, candidate->candidate);
51 if (error) {
52 goto out;
53 }
54 error = rawrtc_ice_candidate_get_ip(&ip, candidate->candidate);
55 if (error) {
56 goto out;
57 }
58 error = rawrtc_ice_candidate_get_port(&port, candidate->candidate);
59 if (error) {
60 goto out;
61 }
62 error = rawrtc_ice_candidate_get_type(&type, candidate->candidate);
63 if (error) {
64 goto out;
65 }
66 error = rawrtc_ice_candidate_get_related_address(&related_address, candidate->candidate);
67 if (error && error != RAWRTC_CODE_NO_VALUE) {
68 goto out;
69 }
70 error = rawrtc_ice_candidate_get_related_port(&related_port, candidate->candidate);
71 if (error && error != RAWRTC_CODE_NO_VALUE) {
72 goto out;
73 }
74 protocol_str = rawrtc_ice_protocol_to_str(protocol);
75 type_str = rawrtc_ice_candidate_type_to_str(type);
76
77 // Initialise SDP attribute buffer
78 sdp = mbuf_alloc(RAWRTC_PEER_CONNECTION_CANDIDATE_DEFAULT_SIZE);
79 if (!sdp) {
80 error = RAWRTC_CODE_NO_MEMORY;
81 goto out;
82 }
83
84 // Encode candidate's mandatory fields
85 error = rawrtc_error_to_code(mbuf_printf(
86 sdp, "candidate:%s %" PRIu16 " %s %" PRIu32 " %s %" PRIu16 " typ %s", foundation,
87 component_id, protocol_str, priority, ip, port, type_str));
88 if (error) {
89 goto out;
90 }
91 if (related_address) {
92 error = rawrtc_error_to_code(mbuf_printf(sdp, " raddr %s", related_address));
93 if (error) {
94 goto out;
95 }
96 }
97 if (related_port > 0) {
98 error = rawrtc_error_to_code(mbuf_printf(sdp, " rport %" PRIu16, related_port));
99 if (error) {
100 goto out;
101 }
102 }
103
104 // Get value for 'tcptype' extension field and encode it (if available)
105 error = rawrtc_ice_candidate_get_tcp_type(&tcp_type, candidate->candidate);
106 switch (error) {
107 case RAWRTC_CODE_SUCCESS:
108 tcp_type_str = rawrtc_ice_tcp_candidate_type_to_str(tcp_type);
109 mbuf_printf(sdp, " tcptype %s", tcp_type_str);
110 break;
111 case RAWRTC_CODE_NO_VALUE:
112 break;
113 default:
114 goto out;
115 }
116
117 // Copy SDP attribute
118 error = rawrtc_sdprintf(sdpp, "%b", sdp->buf, sdp->end);
119 if (error) {
120 goto out;
121 }
122
123out:
124 // Un-reference
125 mem_deref(related_address);
126 mem_deref(sdp);
127 mem_deref(ip);
128 mem_deref(foundation);
129 return error;
130}
131
132/*
133 * Get the media stream identification tag the ICE candidate is
134 * associated to.
135 * `*midp` will be set to a copy of the candidate's mid and must be
136 * unreferenced.
137 *
138 * Return `RAWRTC_CODE_NO_VALUE` in case no 'mid' has been set.
139 * Otherwise, `RAWRTC_CODE_SUCCESS` will be returned and `*midp* must
140 * be unreferenced.
141 */
142enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp_mid(
143 char** const midp, // de-referenced
144 struct rawrtc_peer_connection_ice_candidate* const candidate) {
145 // Check arguments
146 if (!midp || !candidate) {
147 return RAWRTC_CODE_INVALID_ARGUMENT;
148 }
149
150 // Copy mid (if any)
151 if (candidate->mid) {
152 return rawrtc_strdup(midp, candidate->mid);
153 } else {
154 return RAWRTC_CODE_NO_VALUE;
155 }
156}
157
158/*
159 * Get the media stream line index the ICE candidate is associated to.
160 * Return `RAWRTC_CODE_NO_VALUE` in case no media line index has been
161 * set.
162 */
163enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_sdp_media_line_index(
164 uint8_t* const media_line_index, // de-referenced
165 struct rawrtc_peer_connection_ice_candidate* const candidate) {
166 // Check arguments
167 if (!media_line_index || !candidate) {
168 return RAWRTC_CODE_INVALID_ARGUMENT;
169 }
170
171 // Set media line index (if any)
172 if (candidate->media_line_index >= 0 && candidate->media_line_index <= UINT8_MAX) {
173 *media_line_index = (uint8_t) candidate->media_line_index;
174 return RAWRTC_CODE_SUCCESS;
175 } else {
176 return RAWRTC_CODE_NO_VALUE;
177 }
178}
179
180/*
181 * Get the username fragment the ICE candidate is associated to.
182 * `*username_fragmentp` will be set to a copy of the candidate's
183 * username fragment and must be unreferenced.
184 *
185 * Return `RAWRTC_CODE_NO_VALUE` in case no username fragment has been
186 * set. Otherwise, `RAWRTC_CODE_SUCCESS` will be returned and
187 * `*username_fragmentp* must be unreferenced.
188 */
189enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_username_fragment(
190 char** const username_fragmentp, // de-referenced
191 struct rawrtc_peer_connection_ice_candidate* const candidate) {
192 // Check arguments
193 if (!username_fragmentp || !candidate) {
194 return RAWRTC_CODE_INVALID_ARGUMENT;
195 }
196
197 // Copy username fragment (if any)
198 if (candidate->username_fragment) {
199 return rawrtc_strdup(username_fragmentp, candidate->username_fragment);
200 } else {
201 return RAWRTC_CODE_NO_VALUE;
202 }
203}
204
205/*
206 * Get the underlying ORTC ICE candidate from the ICE candidate.
207 * `*ortc_candidatep` must be unreferenced.
208 */
209enum rawrtc_code rawrtc_peer_connection_ice_candidate_get_ortc_candidate(
210 struct rawrtc_ice_candidate** const ortc_candidatep, // de-referenced
211 struct rawrtc_peer_connection_ice_candidate* const candidate) {
212 // Check arguments
213 if (!ortc_candidatep || !candidate) {
214 return RAWRTC_CODE_INVALID_ARGUMENT;
215 }
216
217 // Reference ORTC ICE candidate
218 *ortc_candidatep = mem_ref(candidate->candidate);
219 return RAWRTC_CODE_SUCCESS;
220}