media/mtransport/third_party/nICEr/src/ice/ice_socket.c

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

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

mercurial