Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
1 /*
2 Copyright (c) 2007, Adobe Systems, Incorporated
3 All rights reserved.
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are
7 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
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.
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.
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 */
35 static char *RCSSTRING __UNUSED__="$Id: ice_socket.c,v 1.2 2008/04/28 17:59:01 ekr Exp $";
37 #include <assert.h>
38 #include <string.h>
39 #include "nr_api.h"
40 #include "ice_ctx.h"
41 #include "stun.h"
43 static void nr_ice_socket_readable_cb(NR_SOCKET s, int how, void *cb_arg)
44 {
45 int r;
46 nr_ice_stun_ctx *sc1,*sc2;
47 nr_ice_socket *sock=cb_arg;
48 UCHAR buf[8192];
49 char string[256];
50 nr_transport_addr addr;
51 int len;
52 size_t len_s;
53 int is_stun;
54 int is_req;
55 int is_ind;
56 int processed_indication=0;
58 nr_socket *stun_srv_sock=sock->sock;
60 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
62 /* Re-arm first! */
63 NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
65 if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
66 if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
67 /* Report this error upward. Bug 946423 */
68 r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error on reliable socket. Abandoning.",sock->ctx->label);
69 NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ);
70 }
71 return;
72 }
74 /* Deal with the fact that sizeof(int) and sizeof(size_t) may not
75 be the same */
76 if (len_s > (size_t)INT_MAX)
77 return;
79 len = (int)len_s;
81 #ifdef USE_TURN
82 re_process:
83 #endif /* USE_TURN */
84 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Read %d bytes %sfrom %s",sock->ctx->label,len,(processed_indication ? "relayed " : ""),addr.as_string);
86 /* First question: is this STUN or not? */
87 is_stun=nr_is_stun_message(buf,len);
89 if(is_stun){
90 is_req=nr_is_stun_request_message(buf,len);
91 is_ind=is_req?0:nr_is_stun_indication_message(buf,len);
93 snprintf(string, sizeof(string)-1, "ICE(%s): Message is STUN (%s)",sock->ctx->label,
94 is_req ? "request" : (is_ind ? "indication" : "other"));
95 r_dump(NR_LOG_STUN, LOG_DEBUG, string, (char*)buf, len);
98 /* We need to offer it to all of our stun contexts
99 to see who bites */
100 sc1=TAILQ_FIRST(&sock->stun_ctxs);
101 while(sc1){
102 sc2=TAILQ_NEXT(sc1,entry);
104 r=-1;
105 switch(sc1->type){
106 /* This has been deleted, prune... */
107 case NR_ICE_STUN_NONE:
108 TAILQ_REMOVE(&sock->stun_ctxs,sc1,entry);
109 RFREE(sc1);
110 break;
112 case NR_ICE_STUN_CLIENT:
113 if(!(is_req||is_ind)){
114 r=nr_stun_client_process_response(sc1->u.client,buf,len,&addr);
115 }
116 break;
118 case NR_ICE_STUN_SERVER:
119 if(is_req){
120 r=nr_stun_server_process_request(sc1->u.server,stun_srv_sock,(char *)buf,len,&addr,NR_STUN_AUTH_RULE_SHORT_TERM);
121 }
122 break;
123 #ifdef USE_TURN
124 case NR_ICE_TURN_CLIENT:
125 /* data indications are ok, so don't ignore those */
126 /* Check that this is from the right TURN server address. Else
127 skip */
128 if (nr_transport_addr_cmp(
129 &sc1->u.turn_client.turn_client->turn_server_addr,
130 &addr, NR_TRANSPORT_ADDR_CMP_MODE_ALL))
131 break;
133 if(!is_req){
134 if(!is_ind)
135 r=nr_turn_client_process_response(sc1->u.turn_client.turn_client,buf,len,&addr);
136 else{
137 nr_transport_addr n_addr;
138 size_t n_len;
140 if (processed_indication) {
141 /* Don't allow recursively wrapped indications */
142 r_log(LOG_ICE, LOG_WARNING,
143 "ICE(%s): discarding recursively wrapped indication",
144 sock->ctx->label);
145 break;
146 }
147 /* This is a bit of a hack. If it's a data indication, strip
148 off the TURN framing and re-enter. This works because
149 all STUN processing is on the same physical socket.
150 We don't care about other kinds of indication */
151 r=nr_turn_client_parse_data_indication(
152 sc1->u.turn_client.turn_client, &addr,
153 buf, len, buf, &n_len, len, &n_addr);
154 if(!r){
155 r_log(LOG_ICE,LOG_DEBUG,"Unwrapped a data indication.");
156 len=n_len;
157 nr_transport_addr_copy(&addr,&n_addr);
158 stun_srv_sock=sc1->u.turn_client.turn_sock;
159 processed_indication=1;
160 goto re_process;
161 }
162 }
163 }
164 break;
165 #endif /* USE_TURN */
167 default:
168 assert(0); /* Can't happen */
169 return;
170 }
171 if(!r) {
172 break;
173 }
175 sc1=sc2;
176 }
177 if(!sc1){
178 if (nr_ice_ctx_is_known_id(sock->ctx,((nr_stun_message_header*)buf)->id.octet))
179 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is a retransmit",sock->ctx->label);
180 else
181 r_log(LOG_ICE,LOG_NOTICE,"ICE(%s): Message does not correspond to any registered stun ctx",sock->ctx->label);
182 }
183 }
184 else{
185 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Message is not STUN",sock->ctx->label);
187 nr_ice_ctx_deliver_packet(sock->ctx, sock->component, &addr, buf, len);
188 }
190 return;
191 }
193 int nr_ice_socket_create(nr_ice_ctx *ctx,nr_ice_component *comp, nr_socket *nsock, nr_ice_socket **sockp)
194 {
195 nr_ice_socket *sock=0;
196 NR_SOCKET fd;
197 nr_transport_addr addr;
198 int r,_status;
200 if(!(sock=RCALLOC(sizeof(nr_ice_socket))))
201 ABORT(R_NO_MEMORY);
203 sock->sock=nsock;
204 sock->ctx=ctx;
205 sock->component=comp;
207 if(r=nr_socket_getaddr(nsock, &addr))
208 ABORT(r);
210 if (addr.protocol == IPPROTO_UDP) {
211 sock->type = NR_ICE_SOCKET_TYPE_DGRAM;
212 }
213 else {
214 assert(addr.protocol == IPPROTO_TCP);
215 sock->type = NR_ICE_SOCKET_TYPE_STREAM;
216 }
218 TAILQ_INIT(&sock->candidates);
219 TAILQ_INIT(&sock->stun_ctxs);
221 if(r=nr_socket_getfd(nsock,&fd))
222 ABORT(r);
224 NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock);
226 *sockp=sock;
228 _status=0;
229 abort:
230 if(_status) RFREE(sock);
231 return(_status);
232 }
235 int nr_ice_socket_destroy(nr_ice_socket **isockp)
236 {
237 nr_ice_stun_ctx *s1,*s2;
238 nr_ice_socket *isock;
240 if(!isockp || !*isockp)
241 return(0);
243 isock=*isockp;
244 *isockp=0;
246 /* Close the socket */
247 nr_ice_socket_close(isock);
249 /* The STUN server */
250 nr_stun_server_ctx_destroy(&isock->stun_server);
252 /* Now clean up the STUN ctxs */
253 TAILQ_FOREACH_SAFE(s1, &isock->stun_ctxs, entry, s2){
254 TAILQ_REMOVE(&isock->stun_ctxs, s1, entry);
255 RFREE(s1);
256 }
258 RFREE(isock);
260 return(0);
261 }
263 int nr_ice_socket_close(nr_ice_socket *isock)
264 {
265 #ifdef NR_SOCKET_IS_VOID_PTR
266 NR_SOCKET fd=NULL;
267 NR_SOCKET no_socket = NULL;
268 #else
269 NR_SOCKET fd=-1;
270 NR_SOCKET no_socket = -1;
271 #endif
273 if (!isock||!isock->sock)
274 return(0);
276 nr_socket_getfd(isock->sock,&fd);
277 assert(isock->sock!=0);
278 if(fd != no_socket){
279 NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_READ);
280 NR_ASYNC_CANCEL(fd,NR_ASYNC_WAIT_WRITE);
281 nr_socket_destroy(&isock->sock);
282 }
284 return(0);
285 }
287 int nr_ice_socket_register_stun_client(nr_ice_socket *sock, nr_stun_client_ctx *srv,void **handle)
288 {
289 nr_ice_stun_ctx *sc=0;
290 int _status;
292 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
293 ABORT(R_NO_MEMORY);
295 sc->type=NR_ICE_STUN_CLIENT;
296 sc->u.client=srv;
298 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
300 *handle=sc;
302 _status=0;
303 abort:
304 return(_status);
305 }
307 int nr_ice_socket_register_stun_server(nr_ice_socket *sock, nr_stun_server_ctx *srv,void **handle)
308 {
309 nr_ice_stun_ctx *sc=0;
310 int _status;
312 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
313 ABORT(R_NO_MEMORY);
315 sc->type=NR_ICE_STUN_SERVER;
316 sc->u.server=srv;
318 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
320 *handle=sc;
322 _status=0;
323 abort:
324 return(_status);
325 }
327 int nr_ice_socket_register_turn_client(nr_ice_socket *sock, nr_turn_client_ctx *srv,
328 nr_socket *turn_socket, void **handle)
329 {
330 nr_ice_stun_ctx *sc=0;
331 int _status;
333 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx))))
334 ABORT(R_NO_MEMORY);
336 sc->type=NR_ICE_TURN_CLIENT;
337 sc->u.turn_client.turn_client=srv;
338 sc->u.turn_client.turn_sock=turn_socket;
340 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry);
342 *handle=sc;
344 _status=0;
345 abort:
346 return(_status);
347 }
349 /* Just mark it deregistered. Don't delete it now because it's not safe
350 in the CB, which is where this is likely to be called */
351 int nr_ice_socket_deregister(nr_ice_socket *sock, void *handle)
352 {
353 nr_ice_stun_ctx *sc=handle;
355 if(!sc)
356 return(0);
358 sc->type=NR_ICE_STUN_NONE;
360 return(0);
361 }