Add Youness to contributors
[sipe-libnice.git] / udp / udp-turn.c
blob10f56109c5f2dcfc1a9923918e772601d75707a5
1 /*
2 * This file is part of the Nice GLib ICE library.
4 * (C) 2008 Collabora Ltd.
5 * (C) 2008 Nokia Corporation
6 * Contact: Youness Alaoui
8 * The contents of this file are subject to the Mozilla Public License Version
9 * 1.1 (the "License"); you may not use this file except in compliance with
10 * the License. You may obtain a copy of the License at
11 * http://www.mozilla.org/MPL/
13 * Software distributed under the License is distributed on an "AS IS" basis,
14 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
15 * for the specific language governing rights and limitations under the
16 * License.
18 * The Original Code is the Nice GLib ICE library.
20 * The Initial Developers of the Original Code are Collabora Ltd and Nokia
21 * Corporation. All Rights Reserved.
23 * Contributors:
24 * Dafydd Harries, Collabora Ltd.
25 * Youness Alaoui, Collabora Ltd.
26 * RĂ©mi Denis-Courmont, Nokia
27 * Kai Vehmanen
29 * Alternatively, the contents of this file may be used under the terms of the
30 * the GNU Lesser General Public License Version 2.1 (the "LGPL"), in which
31 * case the provisions of LGPL are applicable instead of those above. If you
32 * wish to allow use of your version of this file only under the terms of the
33 * LGPL and not to allow others to use your version of this file under the
34 * MPL, indicate your decision by deleting the provisions above and replace
35 * them with the notice and other provisions required by the LGPL. If you do
36 * not delete the provisions above, a recipient may use your version of this
37 * file under either the MPL or the LGPL.
41 * Implementation of UDP socket interface using Berkeley sockets. (See
42 * http://en.wikipedia.org/wiki/Berkeley_sockets.)
44 #ifdef HAVE_CONFIG_H
45 # include "config.h"
46 #endif
48 #include <arpa/inet.h>
50 #include <unistd.h>
51 #include <string.h>
52 #include <errno.h>
53 #include <fcntl.h>
55 #include "udp-turn.h"
56 #include "udp-bsd.h"
57 #include <stun/stunagent.h>
59 typedef struct {
60 StunAgent agent;
61 int locked;
62 NiceUDPSocket *udp_socket;
63 NiceAddress server_addr;
64 uint8_t *username;
65 size_t username_len;
66 uint8_t *password;
67 size_t password_len;
68 } turn_priv;
71 gint
72 nice_udp_turn_socket_parse_recv (
73 NiceUDPSocket *sock,
74 NiceAddress *from,
75 guint len,
76 gchar *buf,
77 NiceAddress *recv_from,
78 gchar *recv_buf,
79 guint recv_len)
82 turn_priv *priv = (turn_priv *) sock->priv;
83 StunValidationStatus valid;
84 StunMessage msg;
85 struct sockaddr_storage sa;
86 guint from_len = sizeof (sa);
88 if (nice_address_equal (&priv->server_addr, recv_from)) {
89 valid = stun_agent_validate (&priv->agent, &msg,
90 (uint8_t *) recv_buf, (size_t) recv_len, NULL, NULL);
92 if (valid == STUN_VALIDATION_SUCCESS) {
93 uint32_t cookie;
94 if (stun_message_find32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE, &cookie) != 0)
95 goto recv;
96 if (cookie != TURN_MAGIC_COOKIE)
97 goto recv;
99 if (stun_message_get_class (&msg) == STUN_RESPONSE &&
100 stun_message_get_method (&msg) == STUN_SEND) {
101 return 0;
102 } else if (stun_message_get_class (&msg) == STUN_INDICATION &&
103 stun_message_get_method (&msg) == STUN_IND_DATA) {
104 uint16_t data_len;
105 uint8_t *data;
106 if (stun_message_find_addr (&msg, STUN_ATTRIBUTE_REMOTE_ADDRESS,
107 (struct sockaddr *)&sa, &from_len) != 0)
108 goto recv;
110 data = (uint8_t *) stun_message_find (&msg, STUN_ATTRIBUTE_DATA, &data_len);
111 if (data == NULL)
112 goto recv;
114 nice_address_set_from_sockaddr (from, (struct sockaddr *)&sa);
116 memmove (buf, data, len > data_len ? data_len : len);
117 return len > data_len ? data_len : len;
118 } else {
119 goto recv;
124 recv:
125 *from = *recv_from;
126 memmove (buf, recv_buf, len > recv_len ? recv_len : len);
127 return len > recv_len ? recv_len : len;
130 static gint
131 socket_recv (
132 NiceUDPSocket *sock,
133 NiceAddress *from,
134 guint len,
135 gchar *buf)
137 turn_priv *priv = (turn_priv *) sock->priv;
138 uint8_t recv_buf[STUN_MAX_MESSAGE_SIZE];
139 gint recv_len;
140 NiceAddress recv_from;
142 recv_len = nice_udp_socket_recv (priv->udp_socket, &recv_from,
143 sizeof(recv_buf), (gchar *) recv_buf);
145 return nice_udp_turn_socket_parse_recv (sock, from, len, buf, &recv_from,
146 (gchar *) recv_buf, (guint) recv_len);
149 static gboolean
150 socket_send (
151 NiceUDPSocket *sock,
152 const NiceAddress *to,
153 guint len,
154 const gchar *buf)
156 turn_priv *priv = (turn_priv *) sock->priv;
157 StunMessage msg;
158 uint8_t buffer[STUN_MAX_MESSAGE_SIZE];
159 size_t stun_len;
160 struct sockaddr_storage sa;
162 nice_address_copy_to_sockaddr (to, (struct sockaddr *)&sa);
164 if (!stun_agent_init_request (&priv->agent, &msg, buffer, sizeof(buffer), STUN_SEND))
165 goto send;
167 if (stun_message_append32 (&msg, STUN_ATTRIBUTE_MAGIC_COOKIE,
168 TURN_MAGIC_COOKIE) != 0)
169 goto send;
171 if (priv->username != NULL && priv->username_len > 0) {
172 if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_USERNAME,
173 priv->username, priv->username_len) != 0)
174 goto send;
177 if (stun_message_append_addr (&msg, STUN_ATTRIBUTE_DESTINATION_ADDRESS,
178 (struct sockaddr *)&sa, sizeof(sa)) != 0)
179 goto send;
181 if (stun_message_append_bytes (&msg, STUN_ATTRIBUTE_DATA, buf, len) != 0)
182 goto send;
184 stun_len = stun_agent_finish_message (&priv->agent, &msg,
185 priv->password, priv->password_len);
187 if (stun_len > 0) {
188 nice_udp_socket_send (priv->udp_socket, &priv->server_addr, stun_len, (gchar *)buffer);
189 return TRUE;
191 send:
192 nice_udp_socket_send (priv->udp_socket, to, len, buf);
194 return TRUE;
197 static void
198 socket_close (NiceUDPSocket *sock)
200 turn_priv *priv = (turn_priv *) sock->priv;
201 g_free (priv);
204 /*** NiceUDPSocketFactory ***/
206 static gboolean
207 socket_factory_init_socket (
208 NiceUDPSocketFactory *man,
209 NiceUDPSocket *sock,
210 NiceAddress *addr)
212 return FALSE;
215 NICEAPI_EXPORT gboolean
216 nice_udp_turn_create_socket_full (
217 NiceUDPSocketFactory *man,
218 NiceUDPSocket *sock,
219 NiceAddress *addr,
220 NiceUDPSocket *udp_socket,
221 NiceAddress *server_addr,
222 gchar *username,
223 gchar *password,
224 NiceUdpTurnSocketCompatibility compatibility)
226 turn_priv *priv = g_new0 (turn_priv, 1);
228 stun_agent_init (&priv->agent, STUN_ALL_KNOWN_ATTRIBUTES,
229 STUN_COMPATIBILITY_RFC3489,
230 STUN_AGENT_USAGE_SHORT_TERM_CREDENTIALS |
231 STUN_AGENT_USAGE_IGNORE_CREDENTIALS);
233 priv->locked = FALSE;
234 priv->udp_socket = udp_socket;
235 priv->username = (uint8_t *)username;
236 priv->username_len = (size_t) strlen (username);
237 priv->password = (uint8_t *)password;
238 priv->password_len = (size_t) strlen (password);
239 priv->server_addr = *server_addr;
240 sock->addr = *addr;
241 sock->fileno = udp_socket->fileno;
242 sock->send = socket_send;
243 sock->recv = socket_recv;
244 sock->close = socket_close;
245 sock->priv = (void *) priv;
246 return TRUE;
249 static void
250 socket_factory_close (
251 G_GNUC_UNUSED
252 NiceUDPSocketFactory *man)
256 NICEAPI_EXPORT void
257 nice_udp_turn_socket_factory_init (
258 G_GNUC_UNUSED
259 NiceUDPSocketFactory *man)
262 man->init = socket_factory_init_socket;
263 man->close = socket_factory_close;