Line data Source code
1 : /*
2 : Copyright (c) 2007, Adobe Systems, Incorporated
3 : All rights reserved.
4 :
5 : Redistribution and use in source and binary forms, with or without
6 : modification, are permitted provided that the following conditions are
7 : met:
8 :
9 : * Redistributions of source code must retain the above copyright
10 : notice, this list of conditions and the following disclaimer.
11 :
12 : * Redistributions in binary form must reproduce the above copyright
13 : notice, this list of conditions and the following disclaimer in the
14 : documentation and/or other materials provided with the distribution.
15 :
16 : * Neither the name of Adobe Systems, Network Resonance nor the names of its
17 : contributors may be used to endorse or promote products derived from
18 : this software without specific prior written permission.
19 :
20 : THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21 : "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22 : LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23 : A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24 : OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 : SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 : LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 : DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 : THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 : (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 : OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 : */
32 :
33 :
34 :
35 : static char *RCSSTRING __UNUSED__="$Id: ice_socket.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
36 :
37 : #include <assert.h>
38 : #include <string.h>
39 : #include "nr_api.h"
40 : #include "ice_ctx.h"
41 : #include "stun.h"
42 : #include "nr_socket_buffered_stun.h"
43 : #include "nr_socket_multi_tcp.h"
44 :
45 0 : static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
46 : {
47 : int r;
48 : nr_ice_stun_ctx *sc1,*sc2;
49 0 : nr_ice_socket *sock=cb_arg;
50 : UCHAR buf[9216];
51 : char string[256];
52 : nr_transport_addr addr;
53 : int len;
54 : size_t len_s;
55 : int is_stun;
56 : int is_req;
57 : int is_ind;
58 0 : int processed_indication=0;
59 :
60 0 : nr_socket *stun_srv_sock=sock->sock;
61 :
62 0 : r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
63 :
64 : /* Re-arm first! */
65 0 : if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP) {
66 0 : r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): rearming",sock->ctx->label);
67 0 : NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
68 : }
69 :
70 0 : if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
71 0 : if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
72 : /* Report this error upward. Bug 946423 */
73 0 : r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket(%p). Abandoning.",sock->ctx->label, r, s);
74 : }
75 0 : return;
76 : }
77 :
78 : /* Deal with the fact that sizeof(int) and sizeof(size_t) may not
79 : be the same */
80 0 : if (len_s > (size_t)INT_MAX)
81 0 : return;
82 :
83 0 : len = (int)len_s;
84 :
85 : #ifdef USE_TURN
86 : re_process:
87 : #endif /* USE_TURN */
88 0 : r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes %sfrom %s",sock->ctx->label,len,(processed_indication ? "relayed " : ""),addr.as_string);
89 :
90 : /* First question: is this STUN or not? */
91 0 : is_stun=nr_is_stun_message(buf,len);
92 :
93 0 : if(is_stun){
94 0 : is_req=nr_is_stun_request_message(buf,len);
95 0 : is_ind=is_req?0:nr_is_stun_indication_message(buf,len);
96 :
97 0 : snprintf(string, sizeof(string)-1, "ICE(%s): Message is STUN (%s)",sock->ctx->label,
98 0 : is_req ? "request" : (is_ind ? "indication" : "other"));
99 0 : r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)buf, len);
100 :
101 :
102 : /* We need to offer it to all of our stun contexts
103 : to see who bites */
104 0 : sc1=TAILQ_FIRST(&sock->stun_ctxs);
105 0 : while(sc1){
106 0 : sc2=TAILQ_NEXT(sc1,entry);
107 :
108 0 : r=-1;
109 0 : switch(sc1->type){
110 : /* This has been deleted, prune... */
111 : case NR_ICE_STUN_NONE:
112 0 : TAILQ_REMOVE(&sock->stun_ctxs,sc1,entry);
113 0 : RFREE(sc1);
114 0 : break;
115 :
116 : case NR_ICE_STUN_CLIENT:
117 0 : if(!(is_req||is_ind)){
118 0 : r=nr_stun_client_process_response(sc1->u.client,buf,len,&addr);
119 : }
120 0 : break;
121 :
122 : case NR_ICE_STUN_SERVER:
123 0 : if(is_req){
124 0 : r=nr_stun_server_process_request(sc1->u.server,stun_srv_sock,(char *)buf,len,&addr,NR_STUN_AUTH_RULE_SHORT_TERM);
125 : }
126 0 : break;
127 : #ifdef USE_TURN
128 : case NR_ICE_TURN_CLIENT:
129 : /* data indications are ok, so don't ignore those */
130 : /* Check that this is from the right TURN server address. Else
131 : skip */
132 0 : if (nr_transport_addr_cmp(
133 0 : &sc1->u.turn_client.turn_client->turn_server_addr,
134 : &addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL))
135 0 : break;
136 :
137 0 : if(!is_req){
138 0 : if(!is_ind)
139 0 : r=nr_turn_client_process_response(sc1->u.turn_client.turn_client,buf,len,&addr);
140 : else{
141 : nr_transport_addr n_addr;
142 : size_t n_len;
143 :
144 0 : if (processed_indication) {
145 : /* Don't allow recursively wrapped indications */
146 0 : r_log(LOG_ICE, LOG_WARNING,
147 : "ICE(%s): discarding recursively wrapped indication",
148 0 : sock->ctx->label);
149 0 : break;
150 : }
151 : /* This is a bit of a hack. If it's a data indication, strip
152 : off the TURN framing and re-enter. This works because
153 : all STUN processing is on the same physical socket.
154 : We don't care about other kinds of indication */
155 0 : r=nr_turn_client_parse_data_indication(
156 : sc1->u.turn_client.turn_client, &addr,
157 : buf, len, buf, &n_len, len, &n_addr);
158 0 : if(!r){
159 0 : r_log(LOG_ICE,LOG_DEBUG,"Unwrapped a data indication.");
160 0 : len=n_len;
161 0 : nr_transport_addr_copy(&addr,&n_addr);
162 0 : stun_srv_sock=sc1->u.turn_client.turn_sock;
163 0 : processed_indication=1;
164 0 : goto re_process;
165 : }
166 : }
167 : }
168 0 : break;
169 : #endif /* USE_TURN */
170 :
171 : default:
172 0 : assert(0); /* Can't happen */
173 : return;
174 : }
175 0 : if(!r) {
176 0 : break;
177 : }
178 :
179 0 : sc1=sc2;
180 : }
181 0 : if(!sc1){
182 0 : if (nr_ice_ctx_is_known_id(sock->ctx,((nr_stun_message_header*)buf)->id.octet))
183 0 : r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is a retransmit",sock->ctx->label);
184 : else
185 0 : r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): Message does not correspond to any registered stun ctx",sock->ctx->label);
186 : }
187 : }
188 : else{
189 0 : r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is not STUN",sock->ctx->label);
190 :
191 0 : nr_ice_ctx_deliver_packet(sock->ctx, sock->component, &addr, buf, len);
192 : }
193 :
194 0 : return;
195 : }
196 :
197 0 : int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, int type, nr_ice_socket **sockp)
198 : {
199 0 : nr_ice_socket *sock=0;
200 : NR_SOCKET fd;
201 : nr_transport_addr addr;
202 : int r,_status;
203 :
204 0 : if(!(sock=RCALLOC(sizeof(nr_ice_socket))))
205 0 : ABORT(R_NO_MEMORY);
206 :
207 0 : sock->sock=nsock;
208 0 : sock->ctx=ctx;
209 0 : sock->component=comp;
210 :
211 0 : if(r=nr_socket_getaddr(nsock, &addr))
212 0 : ABORT(r);
213 :
214 0 : if (type == NR_ICE_SOCKET_TYPE_DGRAM) {
215 0 : assert(addr.protocol == IPPROTO_UDP);
216 : }
217 : else {
218 0 : assert(addr.protocol == IPPROTO_TCP);
219 : }
220 0 : sock->type=type;
221 :
222 0 : TAILQ_INIT(&sock->candidates);
223 0 : TAILQ_INIT(&sock->stun_ctxs);
224 :
225 0 : if (sock->type == NR_ICE_SOCKET_TYPE_DGRAM){
226 0 : if((r=nr_socket_getfd(nsock,&fd)))
227 0 : ABORT(r);
228 0 : NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock);
229 : }
230 0 : else if (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TURN) {
231 : /* some OS's (e.g. Linux) don't like to see un-connected TCP sockets in
232 : * the poll socket set. */
233 0 : nr_socket_buffered_stun_set_readable_cb(nsock,nr_ice_socket_readable_cb,sock);
234 : }
235 0 : else if (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TCP) {
236 : /* in this case we can't hook up using NR_ASYNC_WAIT, because nr_socket_multi_tcp
237 : consists of multiple nr_sockets and file descriptors. */
238 0 : if((r=nr_socket_multi_tcp_set_readable_cb(nsock,nr_ice_socket_readable_cb,sock)))
239 0 : ABORT(r);
240 : }
241 :
242 0 : *sockp=sock;
243 :
244 0 : _status=0;
245 : abort:
246 0 : if(_status) RFREE(sock);
247 0 : return(_status);
248 : }
249 :
250 :
251 0 : int nr_ice_socket_destroy(nr_ice_socket **isockp)
252 : {
253 : nr_ice_stun_ctx *s1,*s2;
254 : nr_ice_socket *isock;
255 :
256 0 : if(!isockp || !*isockp)
257 0 : return(0);
258 :
259 0 : isock=*isockp;
260 0 : *isockp=0;
261 :
262 : /* Close the socket */
263 0 : nr_ice_socket_close(isock);
264 :
265 : /* The STUN server */
266 0 : nr_stun_server_ctx_destroy(&isock->stun_server);
267 :
268 : /* Now clean up the STUN ctxs */
269 0 : TAILQ_FOREACH_SAFE(s1, &isock->stun_ctxs, entry, s2){
270 0 : TAILQ_REMOVE(&isock->stun_ctxs, s1, entry);
271 0 : RFREE(s1);
272 : }
273 :
274 0 : RFREE(isock);
275 :
276 0 : return(0);
277 : }
278 :
279 0 : int nr_ice_socket_close(nr_ice_socket *isock)
280 : {
281 : #ifdef NR_SOCKET_IS_VOID_PTR
282 0 : NR_SOCKET fd=NULL;
283 0 : NR_SOCKET no_socket = NULL;
284 : #else
285 : NR_SOCKET fd=-1;
286 : NR_SOCKET no_socket = -1;
287 : #endif
288 :
289 0 : if (!isock||!isock->sock)
290 0 : return(0);
291 :
292 0 : if (isock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP){
293 0 : nr_socket_getfd(isock->sock,&fd);
294 0 : assert(isock->sock!=0);
295 0 : if(fd != no_socket){
296 0 : NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
297 0 : NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
298 : }
299 : }
300 0 : nr_socket_destroy(&isock->sock);
301 :
302 0 : return(0);
303 : }
304 :
305 0 : int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle)
306 : {
307 0 : nr_ice_stun_ctx *sc=0;
308 : int _status;
309 :
310 0 : if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
311 0 : ABORT(R_NO_MEMORY);
312 :
313 0 : sc->type=NR_ICE_STUN_CLIENT;
314 0 : sc->u.client=srv;
315 :
316 0 : TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
317 :
318 0 : *handle=sc;
319 :
320 0 : _status=0;
321 : abort:
322 0 : return(_status);
323 : }
324 :
325 0 : int nr_ice_socket_register_stun_server(nr_ice_socket *sock, nr_stun_server_ctx *srv,void **handle)
326 : {
327 0 : nr_ice_stun_ctx *sc=0;
328 : int _status;
329 :
330 0 : if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
331 0 : ABORT(R_NO_MEMORY);
332 :
333 0 : sc->type=NR_ICE_STUN_SERVER;
334 0 : sc->u.server=srv;
335 :
336 0 : TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
337 :
338 0 : *handle=sc;
339 :
340 0 : _status=0;
341 : abort:
342 0 : return(_status);
343 : }
344 :
345 0 : int nr_ice_socket_register_turn_client(nr_ice_socket *sock, nr_turn_client_ctx *srv,
346 : nr_socket *turn_socket, void **handle)
347 : {
348 0 : nr_ice_stun_ctx *sc=0;
349 : int _status;
350 :
351 0 : if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
352 0 : ABORT(R_NO_MEMORY);
353 :
354 0 : sc->type=NR_ICE_TURN_CLIENT;
355 0 : sc->u.turn_client.turn_client=srv;
356 0 : sc->u.turn_client.turn_sock=turn_socket;
357 :
358 0 : TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
359 :
360 0 : *handle=sc;
361 :
362 0 : _status=0;
363 : abort:
364 0 : return(_status);
365 : }
366 :
367 : /* Just mark it deregistered. Don't delete it now because it's not safe
368 : in the CB, which is where this is likely to be called */
369 0 : int nr_ice_socket_deregister(nr_ice_socket *sock, void *handle)
370 : {
371 0 : nr_ice_stun_ctx *sc=handle;
372 :
373 0 : if(!sc)
374 0 : return(0);
375 :
376 0 : sc->type=NR_ICE_STUN_NONE;
377 :
378 0 : return(0);
379 : }
380 :
|