1 /**
2  * Copyright (c) 2020 Paul-Louis Ageneau
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
17  */
18 
19 #include "juice.h"
20 #include "addr.h"
21 #include "agent.h"
22 #include "ice.h"
23 
24 #ifndef NO_SERVER
25 #include "server.h"
26 #endif
27 
28 #include <stdio.h>
29 
juice_create(const juice_config_t * config)30 JUICE_EXPORT juice_agent_t *juice_create(const juice_config_t *config) {
31 	if (!config)
32 		return NULL;
33 
34 	return agent_create(config);
35 }
36 
juice_destroy(juice_agent_t * agent)37 JUICE_EXPORT void juice_destroy(juice_agent_t *agent) {
38 	if (agent)
39 		agent_destroy(agent);
40 }
41 
juice_gather_candidates(juice_agent_t * agent)42 JUICE_EXPORT int juice_gather_candidates(juice_agent_t *agent) {
43 	if (!agent)
44 		return JUICE_ERR_INVALID;
45 
46 	if (agent_gather_candidates(agent) < 0)
47 		return JUICE_ERR_FAILED;
48 
49 	return JUICE_ERR_SUCCESS;
50 }
51 
juice_get_local_description(juice_agent_t * agent,char * buffer,size_t size)52 JUICE_EXPORT int juice_get_local_description(juice_agent_t *agent, char *buffer, size_t size) {
53 	if (!agent || (!buffer && size))
54 		return JUICE_ERR_INVALID;
55 
56 	if (agent_get_local_description(agent, buffer, size) < 0)
57 		return JUICE_ERR_FAILED;
58 
59 	return JUICE_ERR_SUCCESS;
60 }
61 
juice_set_remote_description(juice_agent_t * agent,const char * sdp)62 JUICE_EXPORT int juice_set_remote_description(juice_agent_t *agent, const char *sdp) {
63 	if (!agent || !sdp)
64 		return JUICE_ERR_INVALID;
65 
66 	if (agent_set_remote_description(agent, sdp) < 0)
67 		return JUICE_ERR_FAILED;
68 
69 	return JUICE_ERR_SUCCESS;
70 }
71 
juice_add_remote_candidate(juice_agent_t * agent,const char * sdp)72 JUICE_EXPORT int juice_add_remote_candidate(juice_agent_t *agent, const char *sdp) {
73 	if (!agent || !sdp)
74 		return JUICE_ERR_INVALID;
75 
76 	if (agent_add_remote_candidate(agent, sdp) < 0)
77 		return JUICE_ERR_FAILED;
78 
79 	return JUICE_ERR_SUCCESS;
80 }
81 
juice_set_remote_gathering_done(juice_agent_t * agent)82 JUICE_EXPORT int juice_set_remote_gathering_done(juice_agent_t *agent) {
83 	if (!agent)
84 		return JUICE_ERR_INVALID;
85 
86 	if (agent_set_remote_gathering_done(agent) < 0)
87 		return JUICE_ERR_FAILED;
88 
89 	return JUICE_ERR_SUCCESS;
90 }
91 
juice_send(juice_agent_t * agent,const char * data,size_t size)92 JUICE_EXPORT int juice_send(juice_agent_t *agent, const char *data, size_t size) {
93 	if (!agent || (!data && size))
94 		return JUICE_ERR_INVALID;
95 
96 	if (agent_send(agent, data, size, 0) < 0)
97 		return JUICE_ERR_FAILED;
98 
99 	return JUICE_ERR_SUCCESS;
100 }
101 
juice_send_diffserv(juice_agent_t * agent,const char * data,size_t size,int ds)102 JUICE_EXPORT int juice_send_diffserv(juice_agent_t *agent, const char *data, size_t size, int ds) {
103 	if (!agent || (!data && size))
104 		return JUICE_ERR_INVALID;
105 
106 	if (agent_send(agent, data, size, ds) < 0)
107 		return JUICE_ERR_FAILED;
108 
109 	return JUICE_ERR_SUCCESS;
110 }
111 
juice_get_state(juice_agent_t * agent)112 JUICE_EXPORT juice_state_t juice_get_state(juice_agent_t *agent) { return agent_get_state(agent); }
113 
juice_get_selected_candidates(juice_agent_t * agent,char * local,size_t local_size,char * remote,size_t remote_size)114 JUICE_EXPORT int juice_get_selected_candidates(juice_agent_t *agent, char *local, size_t local_size,
115                                                char *remote, size_t remote_size) {
116 	if (!agent || (!local && local_size) || (!remote && remote_size))
117 		return JUICE_ERR_INVALID;
118 
119 	ice_candidate_t local_cand, remote_cand;
120 	if (agent_get_selected_candidate_pair(agent, &local_cand, &remote_cand))
121 		return JUICE_ERR_NOT_AVAIL;
122 
123 	if (local_size && ice_generate_candidate_sdp(&local_cand, local, local_size) < 0)
124 		return JUICE_ERR_FAILED;
125 
126 	if (remote_size && ice_generate_candidate_sdp(&remote_cand, remote, remote_size) < 0)
127 		return JUICE_ERR_FAILED;
128 
129 	return JUICE_ERR_SUCCESS;
130 }
131 
juice_get_selected_addresses(juice_agent_t * agent,char * local,size_t local_size,char * remote,size_t remote_size)132 JUICE_EXPORT int juice_get_selected_addresses(juice_agent_t *agent, char *local, size_t local_size,
133                                               char *remote, size_t remote_size) {
134 	if (!agent || (!local && local_size) || (!remote && remote_size))
135 		return JUICE_ERR_INVALID;
136 
137 	ice_candidate_t local_cand, remote_cand;
138 	if (agent_get_selected_candidate_pair(agent, &local_cand, &remote_cand))
139 		return JUICE_ERR_NOT_AVAIL;
140 
141 	if (local_size && addr_record_to_string(&local_cand.resolved, local, local_size) < 0)
142 		return JUICE_ERR_FAILED;
143 
144 	if (remote_size && addr_record_to_string(&remote_cand.resolved, remote, remote_size) < 0)
145 		return JUICE_ERR_FAILED;
146 
147 	return JUICE_ERR_SUCCESS;
148 }
149 
juice_state_to_string(juice_state_t state)150 JUICE_EXPORT const char *juice_state_to_string(juice_state_t state) {
151 	switch (state) {
152 	case JUICE_STATE_DISCONNECTED:
153 		return "disconnected";
154 	case JUICE_STATE_GATHERING:
155 		return "gathering";
156 	case JUICE_STATE_CONNECTING:
157 		return "connecting";
158 	case JUICE_STATE_CONNECTED:
159 		return "connected";
160 	case JUICE_STATE_COMPLETED:
161 		return "completed";
162 	case JUICE_STATE_FAILED:
163 		return "failed";
164 	default:
165 		return "unknown";
166 	}
167 }
168 
juice_server_create(const juice_server_config_t * config)169 JUICE_EXPORT juice_server_t *juice_server_create(const juice_server_config_t *config) {
170 #ifndef NO_SERVER
171 	if (!config)
172 		return NULL;
173 
174 	return server_create(config);
175 #else
176 	(void)config;
177 	JLOG_FATAL("The library was compiled without server support");
178 	return NULL;
179 #endif
180 }
181 
juice_server_destroy(juice_server_t * server)182 JUICE_EXPORT void juice_server_destroy(juice_server_t *server) {
183 #ifndef NO_SERVER
184 	if (server)
185 		server_destroy(server);
186 #else
187 	(void)server;
188 #endif
189 }
190 
juice_server_get_port(juice_server_t * server)191 JUICE_EXPORT uint16_t juice_server_get_port(juice_server_t *server) {
192 #ifndef NO_SERVER
193 	return server ? server_get_port(server) : 0;
194 #else
195 	(void)server;
196 	return 0;
197 #endif
198 }
199 
juice_server_add_credentials(juice_server_t * server,const juice_server_credentials_t * credentials,unsigned long lifetime_ms)200 JUICE_EXPORT int juice_server_add_credentials(juice_server_t *server,
201                                               const juice_server_credentials_t *credentials,
202                                               unsigned long lifetime_ms) {
203 #ifndef NO_SERVER
204 	if (!server || !credentials)
205 		return JUICE_ERR_INVALID;
206 
207 	if (server_add_credentials(server, credentials, (timediff_t)lifetime_ms) < 0)
208 		return JUICE_ERR_FAILED;
209 
210 	return JUICE_ERR_SUCCESS;
211 #else
212 	(void)server;
213 	(void)credentials;
214 	(void)lifetime_ms;
215 	return JUICE_ERR_INVALID;
216 #endif
217 }
218