|
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 |
|
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; |
|
57 |
|
58 nr_socket *stun_srv_sock=sock->sock; |
|
59 |
|
60 r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label); |
|
61 |
|
62 /* Re-arm first! */ |
|
63 NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg); |
|
64 |
|
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 } |
|
73 |
|
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; |
|
78 |
|
79 len = (int)len_s; |
|
80 |
|
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); |
|
85 |
|
86 /* First question: is this STUN or not? */ |
|
87 is_stun=nr_is_stun_message(buf,len); |
|
88 |
|
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); |
|
92 |
|
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); |
|
96 |
|
97 |
|
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); |
|
103 |
|
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; |
|
111 |
|
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; |
|
117 |
|
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; |
|
132 |
|
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; |
|
139 |
|
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 */ |
|
166 |
|
167 default: |
|
168 assert(0); /* Can't happen */ |
|
169 return; |
|
170 } |
|
171 if(!r) { |
|
172 break; |
|
173 } |
|
174 |
|
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); |
|
186 |
|
187 nr_ice_ctx_deliver_packet(sock->ctx, sock->component, &addr, buf, len); |
|
188 } |
|
189 |
|
190 return; |
|
191 } |
|
192 |
|
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; |
|
199 |
|
200 if(!(sock=RCALLOC(sizeof(nr_ice_socket)))) |
|
201 ABORT(R_NO_MEMORY); |
|
202 |
|
203 sock->sock=nsock; |
|
204 sock->ctx=ctx; |
|
205 sock->component=comp; |
|
206 |
|
207 if(r=nr_socket_getaddr(nsock, &addr)) |
|
208 ABORT(r); |
|
209 |
|
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 } |
|
217 |
|
218 TAILQ_INIT(&sock->candidates); |
|
219 TAILQ_INIT(&sock->stun_ctxs); |
|
220 |
|
221 if(r=nr_socket_getfd(nsock,&fd)) |
|
222 ABORT(r); |
|
223 |
|
224 NR_ASYNC_WAIT(fd,NR_ASYNC_WAIT_READ,nr_ice_socket_readable_cb,sock); |
|
225 |
|
226 *sockp=sock; |
|
227 |
|
228 _status=0; |
|
229 abort: |
|
230 if(_status) RFREE(sock); |
|
231 return(_status); |
|
232 } |
|
233 |
|
234 |
|
235 int nr_ice_socket_destroy(nr_ice_socket **isockp) |
|
236 { |
|
237 nr_ice_stun_ctx *s1,*s2; |
|
238 nr_ice_socket *isock; |
|
239 |
|
240 if(!isockp || !*isockp) |
|
241 return(0); |
|
242 |
|
243 isock=*isockp; |
|
244 *isockp=0; |
|
245 |
|
246 /* Close the socket */ |
|
247 nr_ice_socket_close(isock); |
|
248 |
|
249 /* The STUN server */ |
|
250 nr_stun_server_ctx_destroy(&isock->stun_server); |
|
251 |
|
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 } |
|
257 |
|
258 RFREE(isock); |
|
259 |
|
260 return(0); |
|
261 } |
|
262 |
|
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 |
|
272 |
|
273 if (!isock||!isock->sock) |
|
274 return(0); |
|
275 |
|
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 } |
|
283 |
|
284 return(0); |
|
285 } |
|
286 |
|
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; |
|
291 |
|
292 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
|
293 ABORT(R_NO_MEMORY); |
|
294 |
|
295 sc->type=NR_ICE_STUN_CLIENT; |
|
296 sc->u.client=srv; |
|
297 |
|
298 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
|
299 |
|
300 *handle=sc; |
|
301 |
|
302 _status=0; |
|
303 abort: |
|
304 return(_status); |
|
305 } |
|
306 |
|
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; |
|
311 |
|
312 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
|
313 ABORT(R_NO_MEMORY); |
|
314 |
|
315 sc->type=NR_ICE_STUN_SERVER; |
|
316 sc->u.server=srv; |
|
317 |
|
318 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
|
319 |
|
320 *handle=sc; |
|
321 |
|
322 _status=0; |
|
323 abort: |
|
324 return(_status); |
|
325 } |
|
326 |
|
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; |
|
332 |
|
333 if(!(sc=RCALLOC(sizeof(nr_ice_stun_ctx)))) |
|
334 ABORT(R_NO_MEMORY); |
|
335 |
|
336 sc->type=NR_ICE_TURN_CLIENT; |
|
337 sc->u.turn_client.turn_client=srv; |
|
338 sc->u.turn_client.turn_sock=turn_socket; |
|
339 |
|
340 TAILQ_INSERT_TAIL(&sock->stun_ctxs,sc,entry); |
|
341 |
|
342 *handle=sc; |
|
343 |
|
344 _status=0; |
|
345 abort: |
|
346 return(_status); |
|
347 } |
|
348 |
|
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; |
|
354 |
|
355 if(!sc) |
|
356 return(0); |
|
357 |
|
358 sc->type=NR_ICE_STUN_NONE; |
|
359 |
|
360 return(0); |
|
361 } |
|
362 |