source: mediastreamer2/linphone/mediastreamer2/src/ice.c @ 310:de7edfaf7c5b

Last change on this file since 310:de7edfaf7c5b was 310:de7edfaf7c5b, checked in by aymeric <aymeric@…>, 4 years ago

improve logs about ICE

git-svn-id: svn+ssh://svn.savannah.nongnu.org/linphone/trunk@313 3f6dc0c8-ddfe-455d-9043-3cd528dc4637

File size: 41.1 KB
Line 
1/*
2mediastreamer2 library - modular sound and video processing and streaming
3Copyright (C) 2006  Simon MORLAT (simon.morlat@linphone.org)
4
5This program is free software; you can redistribute it and/or
6modify it under the terms of the GNU General Public License
7as published by the Free Software Foundation; either version 2
8of the License, or (at your option) any later version.
9
10This program is distributed in the hope that it will be useful,
11but WITHOUT ANY WARRANTY; without even the implied warranty of
12MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13GNU General Public License for more details.
14
15You should have received a copy of the GNU General Public License
16along with this program; if not, write to the Free Software
17Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18*/
19
20#if !defined(WIN32) && !defined(_WIN32_WCE)
21#ifdef __APPLE__
22#include <sys/types.h>
23#endif
24#include <sys/socket.h>
25#include <netdb.h>
26#endif
27
28#include "mediastreamer2/ice.h"
29#include "mediastreamer2/mscommon.h"
30
31#include <math.h>
32
33static void 
34ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, 
35              const StunAtrString *username, const StunAtrString *password, 
36              UInt96 *tid);
37
38static void 
39ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, 
40              const StunAtrString *username, const StunAtrString *password, 
41              UInt96 *tid)
42{       
43   StunMessage req;
44   char buf[STUN_MAX_MESSAGE_SIZE];
45   int len = STUN_MAX_MESSAGE_SIZE;
46   
47   memset(&req, 0, sizeof(StunMessage));
48
49   stunBuildReqSimple( &req, username, FALSE, FALSE, 1);
50   req.hasMessageIntegrity=TRUE;
51
52   /* 7.1.1.1
53   The attribute MUST be set equal to the priority that would be
54   assigned, based on the algorithm in Section 4.1.2, to a peer
55   reflexive candidate, should one be learned as a consequence of this
56   check */
57   req.hasPriority = TRUE;
58   req.priority.priority = (UInt32)(pow((double)2,(double)24)*(110) + pow((double)2,(double)8)*(65535) + pow((double)2,(double)0)*(256 - remote_candidate->remote_candidate.component_id));
59
60   /* TODO: put this parameter only for the candidate selected */
61   if (remote_candidate->nominated_pair==1)
62           req.hasUseCandidate = TRUE;
63
64   if (remote_candidate->rem_controlling==1)
65           {
66                   req.hasIceControlled = TRUE;
67                   req.iceControlled.value = checklist->tiebreak_value;
68           }
69   else
70           {
71                   req.hasIceControlling = TRUE;
72                   req.iceControlling.value     = checklist->tiebreak_value;
73           }
74
75   /* TODO: not yet implemented? */
76   req.hasFingerprint = TRUE;
77   
78   len = stunEncodeMessage( &req, buf, len, password );
79
80   memcpy(tid , &(req.msgHdr.tr_id), sizeof(req.msgHdr.tr_id));
81
82   sendMessage( myFd, buf, len, dest->addr, dest->port );       
83}
84
85int ice_restart(struct IceCheckList *checklist)
86{
87        struct CandidatePair *remote_candidates = NULL;
88        int pos;
89
90        int count_waiting=0;
91        int count=0;
92
93        if (checklist==NULL)
94                return 0;
95        remote_candidates = checklist->cand_pairs;
96        if (remote_candidates==NULL)
97                return 0;
98
99        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
100        {
101                if (strcasecmp(remote_candidates[pos].local_candidate.cand_type, "srflx")==0)
102                {
103                        /* search for a highest priority "equivalent" pair */
104                        int pos2;
105                        for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
106                        {
107                                /* same "base" address (origin of STUN connectivity check to the remote candidate */
108                                if (strcasecmp(remote_candidates[pos].local_candidate.rel_addr, /* base address for "reflexive" address */
109                                        remote_candidates[pos2].local_candidate.conn_addr)==0) /* base address for "host" address */
110                                {
111                                        /* if same target remote candidate: -> remove the one with lowest priority */
112                                        if (strcasecmp(remote_candidates[pos].remote_candidate.conn_addr,
113                                                remote_candidates[pos2].remote_candidate.conn_addr)==0)
114                                        {   
115                                                /* useless cpair */                 
116                                                ms_message("ice.c: Removing useless pair (idx=%i)", pos);
117                                                remote_candidates[pos].connectivity_check = ICE_PRUNED;
118
119                                        }
120
121                                }
122
123                        }
124                }
125        }
126
127        /* no currently nominated pair */
128        checklist->nominated_pair_index = -1;
129
130        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
131        {
132                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
133                        continue;
134                if (remote_candidates[pos].connectivity_check == ICE_FROZEN)
135                        remote_candidates[pos].connectivity_check = ICE_WAITING;
136        }
137
138        checklist->Ta = 40;
139        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
140        {
141                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
142                        continue;
143                if (remote_candidates[pos].connectivity_check == ICE_WAITING)
144                        count_waiting++;
145                count++;
146        }
147        checklist->RTO = MAX(200, count*checklist->Ta*count_waiting);
148        return 0;
149}
150
151int ice_sound_send_stun_request(RtpSession *session, struct IceCheckList *checklist, uint64_t ctime)
152{
153        struct CandidatePair *remote_candidates = NULL;
154
155        if (checklist==NULL)
156                return 0;
157        remote_candidates = checklist->cand_pairs;
158        if (remote_candidates==NULL)
159                return 0;
160
161        {
162                struct CandidatePair *cand_pair;
163                int media_socket = rtp_session_get_rtp_socket(session);
164                StunAddress4 stunServerAddr;
165                StunAtrString username;
166                StunAtrString password;
167                bool_t res;
168                int pos;
169
170                /* prepare ONCE tie-break value */
171                if (checklist->tiebreak_value==0) {
172                        checklist->tiebreak_value = random() * (0x7fffffffffffffff/0x7fff);
173                }
174
175                cand_pair=NULL;
176                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
177                {
178                        cand_pair = &remote_candidates[pos];
179                        if (cand_pair->connectivity_check == ICE_PRUNED)
180                        {
181                                cand_pair=NULL;
182                                continue;
183                        }
184                        if (cand_pair->connectivity_check == ICE_WAITING)
185                                break;
186                        if (cand_pair->connectivity_check == ICE_IN_PROGRESS)
187                                break;
188                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
189                                break;
190                        cand_pair=NULL;
191                }
192
193                if (cand_pair==NULL)
194                        return 0; /* nothing to do: every pair is FAILED, FROZEN or PRUNED */
195
196                /* start first WAITING pair */
197                cand_pair=NULL;
198                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
199                {
200                        cand_pair = &remote_candidates[pos];
201                        if (cand_pair->connectivity_check == ICE_PRUNED)
202                        {
203                                cand_pair=NULL;
204                                continue;
205                        }
206                        if (cand_pair->connectivity_check == ICE_WAITING)
207                                break;
208                        cand_pair=NULL;
209                }
210
211                if (cand_pair!=NULL)
212                {
213                        cand_pair->connectivity_check = ICE_IN_PROGRESS;
214                        cand_pair->retransmission_number=0;
215                        cand_pair->retransmission_time=ctime+checklist->RTO;
216                        /* keep same rem_controlling for retransmission */
217                        cand_pair->rem_controlling = checklist->rem_controlling;
218                }
219
220                /* try no nominate a pair if we are ready */
221                if (cand_pair==NULL && checklist->nominated_pair_index<0)
222                {
223                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
224                        {
225                                cand_pair = &remote_candidates[pos];
226                                if (cand_pair->connectivity_check == ICE_PRUNED)
227                                {
228                                        cand_pair=NULL;
229                                        continue;
230                                }
231                                if (cand_pair->connectivity_check == ICE_SUCCEEDED)
232                                {
233                                        break;
234                                }
235                                cand_pair=NULL;
236                        }
237
238                        /* ALWAYS accept "host" candidate that have succeeded */
239                        if (cand_pair!=NULL
240                                && (strcasecmp(cand_pair->remote_candidate.cand_type, "host")==0))
241                        {
242                                checklist->nominated_pair_index = pos;
243                                cand_pair->nominated_pair = 1;
244                                cand_pair->connectivity_check = ICE_IN_PROGRESS;
245                                cand_pair->retransmission_number=0;
246                                cand_pair->retransmission_time=ctime+checklist->RTO;
247                                /* keep same rem_controlling for retransmission */
248                                cand_pair->rem_controlling = checklist->rem_controlling;
249                                /* send a new STUN with USE-CANDIDATE */
250                                ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
251                                        pos,
252                                        cand_pair->local_candidate.conn_addr,
253                                        cand_pair->local_candidate.conn_port,
254                                        cand_pair->local_candidate.cand_type,
255                                        cand_pair->remote_candidate.conn_addr,
256                                        cand_pair->remote_candidate.conn_port,
257                                        cand_pair->remote_candidate.cand_type,
258                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
259                                checklist->keepalive_time=ctime+15*1000;
260                        }
261                        else if (cand_pair!=NULL)
262                        {
263                                struct CandidatePair *cand_pair2;
264                                int pos2;
265                                for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
266                                {
267                                        cand_pair2 = &remote_candidates[pos2];
268                                        if (cand_pair2->connectivity_check == ICE_PRUNED)
269                                        {
270                                                cand_pair2=NULL;
271                                                continue;
272                                        }
273                                        if (cand_pair2->connectivity_check == ICE_IN_PROGRESS
274                                                ||cand_pair2->connectivity_check == ICE_WAITING)
275                                        {
276                                                break;
277                                        }
278                                        cand_pair2=NULL;
279                                }
280
281                                if (cand_pair2!=NULL)
282                                {
283                                        /* a better candidate is still tested */
284                                        cand_pair=NULL;
285                                }
286                                else
287                                {
288                                        checklist->nominated_pair_index = pos;
289                                        cand_pair->nominated_pair = 1;
290                                        cand_pair->connectivity_check = ICE_IN_PROGRESS;
291                                        cand_pair->retransmission_number=0;
292                                        cand_pair->retransmission_time=ctime+checklist->RTO;
293                                        /* keep same rem_controlling for retransmission */
294                                        cand_pair->rem_controlling = checklist->rem_controlling;
295                                        /* send a new STUN with USE-CANDIDATE */
296                                        ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
297                                                pos,
298                                                cand_pair->local_candidate.conn_addr,
299                                                cand_pair->local_candidate.conn_port,
300                                                cand_pair->local_candidate.cand_type,
301                                                cand_pair->remote_candidate.conn_addr,
302                                                cand_pair->remote_candidate.conn_port,
303                                                cand_pair->remote_candidate.cand_type,
304                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
305                                        checklist->keepalive_time=ctime+15*1000;
306                                }
307                        }
308                }
309
310                if (cand_pair==NULL)
311                {
312                        /* no WAITING pair: retransmit after RTO */
313                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
314                        {
315                                cand_pair = &remote_candidates[pos];
316                                if (cand_pair->connectivity_check == ICE_PRUNED)
317                                {
318                                        cand_pair=NULL;
319                                        continue;
320                                }
321                                if (cand_pair->connectivity_check == ICE_IN_PROGRESS
322                                        && ctime > cand_pair->retransmission_time)
323                                {
324                                        if (cand_pair->retransmission_number>7)
325                                        {
326                                                ms_message("ice.c: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
327                                                        cand_pair->local_candidate.conn_addr,
328                                                        cand_pair->local_candidate.conn_port,
329                                                        cand_pair->remote_candidate.conn_addr,
330                                                        cand_pair->remote_candidate.conn_port);
331
332                                                cand_pair->connectivity_check = ICE_FAILED;
333                                                cand_pair=NULL;
334                                                continue;
335                                        }
336
337                                        cand_pair->retransmission_number++;
338                                        cand_pair->retransmission_time=ctime+checklist->RTO;
339                                        break;
340                                }
341                                cand_pair=NULL;
342                        }
343                }
344
345                if (cand_pair==NULL)
346                {
347                        if (checklist->nominated_pair_index<0)
348                                return 0;
349
350                        /* send STUN indication each 15 seconds: keepalive */
351                        if (ctime>checklist->keepalive_time)
352                        {
353                                checklist->keepalive_time=ctime+15*1000;
354                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
355                                {
356                                        cand_pair = &remote_candidates[pos];
357                                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
358                                        {
359                                                res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
360                                                        &stunServerAddr);
361                                                if ( res == TRUE )
362                                                {
363                                                        StunMessage req;
364                                                        char buf[STUN_MAX_MESSAGE_SIZE];
365                                                        int len = STUN_MAX_MESSAGE_SIZE;
366                                                        stunServerAddr.port = cand_pair->remote_candidate.conn_port;
367                                                        memset(&req, 0, sizeof(StunMessage));
368                                                        stunBuildReqSimple( &req, NULL, FALSE, FALSE, 1);
369                                                        req.msgHdr.msgType = (STUN_METHOD_BINDING|STUN_INDICATION);
370                                                        req.hasFingerprint = TRUE;
371                                                        len = stunEncodeMessage( &req, buf, len, NULL);
372                                                        sendMessage( media_socket, buf, len, stunServerAddr.addr, stunServerAddr.port );
373                                                }
374                                        }
375                                }
376                        }
377
378                        return 0;
379                }
380
381                username.sizeValue = 0;
382                password.sizeValue = 0;
383
384                /* username comes from "ice-ufrag" (rfrag:lfrag) */
385                /* ufrag and pwd are in first row only */
386                snprintf(username.value, sizeof(username.value), "%s:%s",
387                        checklist->rem_ice_ufrag,
388                        checklist->loc_ice_ufrag);
389                username.sizeValue = (UInt16)strlen(username.value);
390
391
392                snprintf(password.value, sizeof(password.value), "%s",
393                        checklist->rem_ice_pwd);
394                password.sizeValue = (UInt16)strlen(password.value);
395
396
397                res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
398                        &stunServerAddr);
399                if ( res == TRUE )
400                {
401                        ms_message("ice.c: STUN REQ (%s) -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
402                                cand_pair->nominated_pair==0?"":"USE-CANDIDATE",
403                                pos,
404                                cand_pair->local_candidate.conn_addr,
405                                cand_pair->local_candidate.conn_port,
406                                cand_pair->local_candidate.cand_type,
407                                cand_pair->remote_candidate.conn_addr,
408                                cand_pair->remote_candidate.conn_port,
409                                cand_pair->remote_candidate.cand_type,
410                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
411                        stunServerAddr.port = cand_pair->remote_candidate.conn_port;
412                        ice_sendtest(checklist, cand_pair, media_socket, &stunServerAddr, &username, &password,
413                                &(cand_pair->tid));
414                }
415        }
416
417        return 0;
418}
419
420static int
421_ice_get_localip_for (struct sockaddr_storage *saddr, size_t saddr_len, char *loc, int size)
422{
423        int err, tmp;
424        int sock;
425        struct sockaddr_storage addr;
426        socklen_t addr_len;
427
428        strcpy (loc, "127.0.0.1");    /* always fallback to local loopback */
429
430        sock = socket (saddr->ss_family, SOCK_DGRAM, 0);
431        tmp = 1;
432        err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &tmp, sizeof (int));
433        if (err < 0)
434        {
435                ms_error("ice.c: Error in setsockopt");
436                closesocket (sock);
437                return -1;
438        }
439        err = connect (sock, (struct sockaddr*)saddr, saddr_len);
440        if (err < 0)
441        {
442                ms_error("ice.c: Error in connect");
443                closesocket (sock);
444                return -1;
445        }
446        addr_len = sizeof (addr);
447        err = getsockname (sock, (struct sockaddr *) &addr, (socklen_t*)&addr_len);
448        if (err != 0)
449        {
450                ms_error("ice.c: Error in getsockname");
451                closesocket (sock);
452                return -1;
453        }
454
455        err = getnameinfo ((struct sockaddr *) &addr, addr_len, loc, size, NULL, 0, NI_NUMERICHOST);
456        if (err != 0)
457        {
458                ms_error("ice.c: Error in getnameinfo");
459                closesocket (sock);
460                return -1;
461        }
462        closesocket (sock);
463        /* ms_message("ice.c: Outgoing interface for sending STUN answer is %s", loc); */
464        return 0;
465}
466
467static void
468_ice_createErrorResponse(StunMessage *response, int cl, int number, const char* msg)
469{
470        response->msgHdr.msgType = (STUN_METHOD_BINDING | STUN_ERR_RESP);
471        response->hasErrorCode = TRUE;
472        response->errorCode.errorClass = cl;
473        response->errorCode.number = number;
474        strcpy(response->errorCode.reason, msg);
475        response->errorCode.sizeReason = strlen(msg);
476        response->hasFingerprint = TRUE;
477}
478
479int ice_process_stun_message(RtpSession *session, struct IceCheckList *checklist, OrtpEvent *evt)
480{
481        struct CandidatePair *remote_candidates = NULL;
482        StunMessage msg;
483        bool_t res;
484        int highest_priority_success=-1;
485        OrtpEventData *evt_data = ortp_event_get_data(evt);
486        mblk_t *mp = evt_data->packet;
487        struct sockaddr_in *udp_remote;
488        char src6host[NI_MAXHOST];
489        int recvport = 0;
490        int i;
491
492        udp_remote = (struct sockaddr_in*)&evt_data->ep->addr;
493
494        memset( &msg, 0 , sizeof(msg) );
495        res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg);
496        if (!res)
497        {
498                ms_error("ice.c: Malformed STUN packet.");
499                return -1;
500        }
501
502        if (checklist==NULL)
503        {
504                ms_error("ice.c: dropping STUN packet: ice is not configured");
505                return -1;
506        }
507
508        remote_candidates = checklist->cand_pairs;
509        if (remote_candidates==NULL)
510        {
511                ms_error("ice.c: dropping STUN packet: ice is not configured");
512                return -1;
513        }
514
515        /* prepare ONCE tie-break value */
516        if (checklist->tiebreak_value==0) {
517                checklist->tiebreak_value = random() * (0x7fffffffffffffff/0x7fff);
518        }
519
520        memset (src6host, 0, sizeof (src6host));
521
522        {
523                struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr;
524                if (aaddr->ss_family==AF_INET)
525                        recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port);
526                else
527                        recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port);
528        }
529        i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen,
530                src6host, NI_MAXHOST,
531                NULL, 0, NI_NUMERICHOST);
532        if (i != 0)
533        {
534                ms_error("ice.c: Error with getnameinfo");
535                return -1;
536        }
537
538        if (STUN_IS_REQUEST(msg.msgHdr.msgType))
539                ms_message("ice.c: STUN_CONNECTIVITYCHECK: Request received from: %s:%i",
540                src6host, recvport);
541        else if (STUN_IS_INDICATION(msg.msgHdr.msgType))
542                ms_message("ice.c: SUN_INDICATION: Request Indication received from: %s:%i",
543                src6host, recvport);
544        else
545                ms_message("ice.c: STUN_ANSWER: Answer received from: %s:%i",
546                src6host, recvport);
547
548        {
549                int pos;
550                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
551                {
552                        struct CandidatePair *cand_pair = &remote_candidates[pos];
553
554                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
555                        {
556                                highest_priority_success=pos;
557                                break;
558                        }
559                }
560        }
561
562        if (STUN_IS_INDICATION(msg.msgHdr.msgType))
563        {
564                ms_message("ice.c: STUN INDICATION <- (?:?:? <- %s:%i:?)", src6host, recvport);
565                return 0;
566        }
567        else if (STUN_IS_REQUEST(msg.msgHdr.msgType))
568        {
569                StunMessage resp;
570                StunAtrString hmacPassword;
571                StunAddress4 remote_addr;
572                int rtp_socket;
573
574                memset( &resp, 0 , sizeof(resp));
575                remote_addr.addr = ntohl(udp_remote->sin_addr.s_addr);
576                remote_addr.port = ntohs(udp_remote->sin_port);
577
578                rtp_socket = rtp_session_get_rtp_socket(session);
579
580                resp.msgHdr.magic_cookie = ntohl(msg.msgHdr.magic_cookie);
581                for (i=0; i<12; i++ )
582                {
583                        resp.msgHdr.tr_id.octet[i] = msg.msgHdr.tr_id.octet[i];
584                }
585
586                /* check mandatory params */
587
588                if (!msg.hasUsername)
589                {
590                        char buf[STUN_MAX_MESSAGE_SIZE];
591                        int len = sizeof(buf);
592                        ms_error("ice.c: STUN REQ <- Missing USERNAME attribute in connectivity check");
593                        _ice_createErrorResponse(&resp, 4, 32, "Missing USERNAME attribute");
594                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
595                        if (len)
596                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
597                        return -1;
598                }
599                if (!msg.hasMessageIntegrity)
600                {
601                        char buf[STUN_MAX_MESSAGE_SIZE];
602                        int len = sizeof(buf);
603                        ms_error("ice.c: STUN REQ <- Missing MESSAGEINTEGRITY attribute in connectivity check");
604                        _ice_createErrorResponse(&resp, 4, 1, "Missing MESSAGEINTEGRITY attribute");
605                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
606                        if (len)
607                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
608                        return -1;
609                }
610
611                /*
612                The password associated with that transport address ID is used to verify
613                the MESSAGE-INTEGRITY attribute, if one was present in the request.
614                */
615                char hmac[20];
616                /* remove length of fingerprint if present */
617                if (msg.hasFingerprint==TRUE)
618                {
619                        char *lenpos = (char *)mp->b_rptr + sizeof(UInt16);
620                        UInt16 newlen = htons(msg.msgHdr.msgLength-8); /* remove fingerprint size */
621                        memcpy(lenpos, &newlen, sizeof(UInt16));
622                        stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24-8, checklist->loc_ice_pwd);
623                }
624                else
625                        stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24, checklist->loc_ice_pwd);
626                if (memcmp(msg.messageIntegrity.hash, hmac, 20)!=0)
627                {
628                        char buf[STUN_MAX_MESSAGE_SIZE];
629                        int len = sizeof(buf);
630                        ms_error("ice.c: STUN REQ <- Wrong MESSAGEINTEGRITY attribute in connectivity check");
631                        _ice_createErrorResponse(&resp, 4, 1, "Wrong MESSAGEINTEGRITY attribute");
632                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
633                        if (len)
634                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
635                        return -1;
636                }
637                if (msg.hasFingerprint==TRUE)
638                {
639                        char *lenpos = (char *)mp->b_rptr + sizeof(UInt16);
640                        UInt16 newlen = htons(msg.msgHdr.msgLength); /* add back fingerprint size */
641                        memcpy(lenpos, &newlen, sizeof(UInt16));
642                }
643
644
645                /* 7.2.1.1. Detecting and Repairing Role Conflicts */
646                /* TODO */
647                if (!msg.hasIceControlling && !msg.hasIceControlled)
648                {
649                        char buf[STUN_MAX_MESSAGE_SIZE];
650                        int len = sizeof(buf);
651                        ms_error("ice.c: STUN REQ <- Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
652                        _ice_createErrorResponse(&resp, 4, 87, "Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
653                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
654                        if (len)
655                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
656                        return -1;
657                }
658
659                if (checklist->rem_controlling==0 && msg.hasIceControlling) {
660                        /* If the agent's tie-breaker is larger than or equal
661                        to the contents of the ICE-CONTROLLING attribute
662                        -> send 487, and do not change ROLE */
663                        if (checklist->tiebreak_value >= msg.iceControlling.value) {
664                                char buf[STUN_MAX_MESSAGE_SIZE];
665                                int len = sizeof(buf);
666                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
667                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
668                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
669                                if (len)
670                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
671                                return -1;
672                        }
673                        else {
674                                int pos;
675                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
676                                {
677                                        /* controller agent */
678                                        int G = remote_candidates[pos].remote_candidate.priority;
679                                        /* controlled agent */ 
680                                        int D = remote_candidates[pos].local_candidate.priority;
681                                        remote_candidates[pos].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
682
683                                }
684                                checklist->rem_controlling = 1;
685                                /* reset all to initial WAITING state? */
686                                ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
687                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
688                                {
689                                        if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
690                                                continue;
691                                        remote_candidates[pos].connectivity_check = ICE_WAITING;
692                                        memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
693                                        remote_candidates[pos].retransmission_time = 0;
694                                        remote_candidates[pos].retransmission_number = 0;
695                                }
696                        }
697                }
698
699                if (checklist->rem_controlling==1 && msg.hasIceControlled) {
700
701                        /* If the agent's tie-breaker is larger than or equal
702                        to the contents of the ICE-CONTROLLED attribute
703                        -> change ROLE */
704                        if (checklist->tiebreak_value >= msg.iceControlled.value) {
705                                int pos;
706                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
707                                {
708                                        /* controller agent */
709                                        int G = remote_candidates[pos].local_candidate.priority;
710                                        /* controlled agent */ 
711                                        int D = remote_candidates[pos].remote_candidate.priority;
712                                        remote_candidates[pos].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
713
714                                }
715                                checklist->rem_controlling = 0;
716                                /* reset all to initial WAITING state? */
717                                ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
718                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
719                                {
720                                        if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
721                                                continue;
722                                        remote_candidates[pos].connectivity_check = ICE_WAITING;
723                                        memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
724                                        remote_candidates[pos].retransmission_time = 0;
725                                        remote_candidates[pos].retransmission_number = 0;
726                                }
727                        }
728                        else {
729                                char buf[STUN_MAX_MESSAGE_SIZE];
730                                int len = sizeof(buf);
731                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
732                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
733                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
734                                if (len)
735                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
736                                return -1;
737                        }
738                }
739
740                struct CandidatePair *cand_pair;
741                int pos;
742                cand_pair=NULL;
743                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
744                {
745                        cand_pair = &remote_candidates[pos]; 
746                        /* connectivity check is coming from a known remote candidate?
747                        we should also check the port...
748                        */
749                        if (strcmp(cand_pair->remote_candidate.conn_addr, src6host)==0
750                                && cand_pair->remote_candidate.conn_port==recvport)
751                        {
752                                ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) from known peer",
753                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
754                                        pos,
755                                        cand_pair->local_candidate.conn_addr,
756                                        cand_pair->local_candidate.conn_port,
757                                        cand_pair->local_candidate.cand_type,
758                                        cand_pair->remote_candidate.conn_addr,
759                                        cand_pair->remote_candidate.conn_port,
760                                        cand_pair->remote_candidate.cand_type);
761                                if (cand_pair->connectivity_check==ICE_FROZEN
762                                        || cand_pair->connectivity_check==ICE_IN_PROGRESS
763                                        || cand_pair->connectivity_check==ICE_FAILED)
764                                {
765                                        cand_pair->connectivity_check = ICE_WAITING;
766                                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
767                                                cand_pair->nominated_pair = 1;
768                                }
769                                else if (cand_pair->connectivity_check==ICE_SUCCEEDED)
770                                {
771                                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
772                                        {
773                                                cand_pair->nominated_pair = 1;
774
775                                                /* USE-CANDIDATE is in STUN request and we already succeeded on that link */
776                                                ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
777                                                        pos,
778                                                        cand_pair->local_candidate.conn_addr,
779                                                        cand_pair->local_candidate.conn_port,
780                                                        cand_pair->local_candidate.cand_type,
781                                                        cand_pair->remote_candidate.conn_addr,
782                                                        cand_pair->remote_candidate.conn_port,
783                                                        cand_pair->remote_candidate.cand_type,
784                                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
785                                                memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
786                                                session->rtp.rem_addrlen=evt_data->ep->addrlen;
787                                        }
788                                }
789                                break;
790                        }
791                        cand_pair=NULL;
792                }
793                if (cand_pair==NULL)
794                {
795                        struct CandidatePair new_pair;
796                        memset(&new_pair, 0, sizeof(struct CandidatePair));
797
798                        ms_message("ice.c: STUN REQ <- connectivity check received from an unknow candidate (%s:%i)", src6host, recvport);
799                        /* TODO: add the peer-reflexive candidate */
800
801                        memcpy(&new_pair.local_candidate, &remote_candidates[0].local_candidate, sizeof(new_pair.local_candidate));
802
803                        new_pair.remote_candidate.foundation = 6;
804                        new_pair.remote_candidate.component_id = remote_candidates[0].remote_candidate.component_id;
805
806                        /* -> no known base address for peer */
807
808                        new_pair.remote_candidate.conn_port = recvport;
809                        snprintf(new_pair.remote_candidate.conn_addr, sizeof(new_pair.remote_candidate.conn_addr),
810                                "%s", src6host);
811
812                        /* take it from PRIORITY STUN attr */
813                        new_pair.remote_candidate.priority = msg.priority.priority;
814                        if (new_pair.remote_candidate.priority==0)
815                                new_pair.remote_candidate.priority =  (UInt32)(pow((double)2,(double)24)*(110) + pow((double)2,(double)8)*(65535) + pow((double)2,(double)0)*(256 - new_pair.remote_candidate.component_id));
816
817                        snprintf(new_pair.remote_candidate.cand_type, sizeof(cand_pair->remote_candidate.cand_type),
818                                "prflx");
819                        snprintf (new_pair.remote_candidate.transport,
820                                                        sizeof (new_pair.remote_candidate.transport),
821                                                        "UDP");
822
823                        if (checklist->rem_controlling==0)
824                        {
825                                int G = new_pair.local_candidate.priority;
826                                /* controlled agent */ 
827                                int D = new_pair.remote_candidate.priority;
828                                new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
829                        }
830                        else
831                        {
832                                int G = new_pair.remote_candidate.priority;
833                                /* controlled agent */ 
834                                int D = new_pair.local_candidate.priority;
835                                new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
836                        }
837                        new_pair.connectivity_check = ICE_WAITING;
838                        /* insert new pair candidate */
839                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
840                        {
841                                new_pair.nominated_pair = 1;
842                        }
843
844                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
845                        {
846                                if (pos==9)
847                                {
848                                        ms_message("ice.c: STUN REQ (%s) <- X (%s:%i:%s <- %s:%i:%s) no room for new remote reflexive candidate",
849                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
850                                                new_pair.local_candidate.conn_addr,
851                                                new_pair.local_candidate.conn_port,
852                                                new_pair.local_candidate.cand_type,
853                                                new_pair.remote_candidate.conn_addr,
854                                                new_pair.remote_candidate.conn_port,
855                                                new_pair.remote_candidate.cand_type);
856                                        break;
857                                }
858                                if (new_pair.pair_priority > remote_candidates[pos].pair_priority)
859                                {
860                                        /* move upper data */
861                                        memmove(&remote_candidates[pos+1], &remote_candidates[pos], sizeof(struct CandidatePair)*(10-pos-1));
862                                        memcpy(&remote_candidates[pos], &new_pair, sizeof(struct CandidatePair));
863
864                                        if (checklist->nominated_pair_index>=pos)
865                                                checklist->nominated_pair_index++;
866                                        ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) new learned remote reflexive candidate",
867                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
868                                                pos,
869                                                new_pair.local_candidate.conn_addr,
870                                                new_pair.local_candidate.conn_port,
871                                                new_pair.local_candidate.cand_type,
872                                                new_pair.remote_candidate.conn_addr,
873                                                new_pair.remote_candidate.conn_port,
874                                                new_pair.remote_candidate.cand_type);
875                                        break;
876                                }
877                        }
878                }
879
880                UInt32 cookie = 0x2112A442;
881                resp.hasXorMappedAddress = TRUE;
882                resp.xorMappedAddress.ipv4.port = remote_addr.port^(cookie>>16);
883                resp.xorMappedAddress.ipv4.addr = remote_addr.addr^cookie;
884
885
886                resp.msgHdr.msgType = (STUN_METHOD_BINDING | STUN_SUCCESS_RESP);
887
888                resp.hasUsername = TRUE;
889                memcpy(resp.username.value, msg.username.value, msg.username.sizeValue );
890                resp.username.sizeValue = msg.username.sizeValue;
891
892                /* ? any messageintegrity in response? */
893                resp.hasMessageIntegrity = TRUE;
894
895                const char serverName[] = "mediastreamer2 " STUN_VERSION;
896                resp.hasSoftware = TRUE;
897                memcpy( resp.softwareName.value, serverName, sizeof(serverName));
898                resp.softwareName.sizeValue = sizeof(serverName);
899
900                resp.hasFingerprint = TRUE;
901
902                {
903                        char buf[STUN_MAX_MESSAGE_SIZE];
904                        int len = sizeof(buf);
905                        len = stunEncodeMessage( &resp, buf, len, &hmacPassword );
906                        if (len)
907                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
908                }
909        }
910        else if (STUN_IS_SUCCESS_RESP(msg.msgHdr.msgType))
911        {
912                /* set state to RECV-VALID or VALID */
913                StunMessage resp;
914                StunAddress4 mappedAddr;
915                memset(&resp, 0, sizeof(StunMessage));
916                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
917                        &resp );
918                if (!res)
919                {
920                        ms_error("ice.c: STUN RESP <- Bad format for STUN answer.");
921                        return -1;
922                }
923
924                if (resp.hasXorMappedAddress!=TRUE)
925                {
926                        ms_error("ice.c: STUN RESP <- Missing XOR-MAPPED-ADDRESS in STUN answer.");               
927                        return -1;
928                }
929
930                UInt32 cookie = 0x2112A442;
931                UInt16 cookie16 = 0x2112A442 >> 16;
932                mappedAddr.port = resp.xorMappedAddress.ipv4.port^cookie16;
933                mappedAddr.addr = resp.xorMappedAddress.ipv4.addr^cookie;
934
935                struct in_addr inaddr;
936                char mapped_addr[64];
937                inaddr.s_addr = htonl (mappedAddr.addr);
938                snprintf(mapped_addr, sizeof(mapped_addr),
939                        "%s", inet_ntoa (inaddr));
940
941                struct CandidatePair *cand_pair;
942                int pos;
943                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
944                {
945                        cand_pair = &remote_candidates[pos];
946
947                        if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
948                        {
949                                break;
950                        }
951                        cand_pair = NULL;
952                }
953
954                if (cand_pair==NULL)
955                {
956                        ms_message("ice.c: STUN RESP (%s) <- no transaction for STUN answer?",
957                                msg.hasUseCandidate==0?"":"USE-CANDIDATE");
958                }
959                else if (strcmp(src6host, cand_pair->remote_candidate.conn_addr)!=0
960                        || recvport!=cand_pair->remote_candidate.conn_port)
961                {
962                        /* 7.1.2.2.  Success Cases
963                        -> must be a security issue: refuse non-symmetric answer */
964                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s) refused because non-symmetric",
965                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
966                                pos,
967                                cand_pair->local_candidate.conn_addr,
968                                cand_pair->local_candidate.conn_port,
969                                cand_pair->local_candidate.cand_type,
970                                cand_pair->remote_candidate.conn_addr,
971                                cand_pair->remote_candidate.conn_port,
972                                cand_pair->remote_candidate.cand_type,
973                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
974                        cand_pair->connectivity_check = ICE_FAILED;
975                }
976                else
977                {
978                        /* Youhouhouhou */
979                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
980                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
981                                pos,
982                                cand_pair->local_candidate.conn_addr,
983                                cand_pair->local_candidate.conn_port,
984                                cand_pair->local_candidate.cand_type,
985                                cand_pair->remote_candidate.conn_addr,
986                                cand_pair->remote_candidate.conn_port,
987                                cand_pair->remote_candidate.cand_type,
988                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
989                        if (cand_pair->connectivity_check != ICE_SUCCEEDED)
990                        {
991                                if (checklist->rem_controlling==1 && cand_pair->nominated_pair>0)
992                                {
993                                        /* USE-CANDIDATE was in previous STUN request sent */
994                                        ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
995                                                pos,
996                                                cand_pair->local_candidate.conn_addr,
997                                                cand_pair->local_candidate.conn_port,
998                                                cand_pair->local_candidate.cand_type,
999                                                cand_pair->remote_candidate.conn_addr,
1000                                                cand_pair->remote_candidate.conn_port,
1001                                                cand_pair->remote_candidate.cand_type,
1002                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
1003                                        memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1004                                        session->rtp.rem_addrlen=evt_data->ep->addrlen;
1005                                }
1006
1007                                if (cand_pair->nominated_pair>0 && checklist->rem_controlling==0)
1008                                {
1009                                        /* USE-CANDIDATE is in STUN request and we already succeeded on that link */
1010                                        ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
1011                                                pos,
1012                                                cand_pair->local_candidate.conn_addr,
1013                                                cand_pair->local_candidate.conn_port,
1014                                                cand_pair->local_candidate.cand_type,
1015                                                cand_pair->remote_candidate.conn_addr,
1016                                                cand_pair->remote_candidate.conn_port,
1017                                                cand_pair->remote_candidate.cand_type,
1018                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
1019                                        memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1020                                        session->rtp.rem_addrlen=evt_data->ep->addrlen;
1021                                }
1022
1023                                cand_pair->connectivity_check = ICE_FAILED;
1024                                if (mappedAddr.port == cand_pair->local_candidate.conn_port
1025                                        && strcmp(mapped_addr, cand_pair->local_candidate.conn_addr)==0)
1026                                {
1027                                        /* no peer-reflexive candidate was discovered */
1028                                        cand_pair->connectivity_check = ICE_SUCCEEDED;
1029                                }
1030                                else
1031                                {
1032                                        int pos2;
1033                                        for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1034                                        {
1035                                                if (mappedAddr.port == remote_candidates[pos2].local_candidate.conn_port
1036                                                        && strcmp(mapped_addr, remote_candidates[pos2].local_candidate.conn_addr)==0
1037                                                        && cand_pair->remote_candidate.conn_port == remote_candidates[pos2].remote_candidate.conn_port
1038                                                        && strcmp(cand_pair->remote_candidate.conn_addr, remote_candidates[pos2].remote_candidate.conn_addr)==0)
1039                                                {
1040                                                        if (remote_candidates[pos2].connectivity_check==ICE_PRUNED
1041                                                                ||remote_candidates[pos2].connectivity_check==ICE_FROZEN
1042                                                                ||remote_candidates[pos2].connectivity_check==ICE_FAILED
1043                                                                || remote_candidates[pos2].connectivity_check==ICE_IN_PROGRESS)
1044                                                                remote_candidates[pos2].connectivity_check = ICE_WAITING; /* trigger check */
1045                                                        /*
1046                                                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) found candidate pair matching XOR-MAPPED-ADDRESS",
1047                                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1048                                                                pos,
1049                                                                cand_pair->local_candidate.conn_addr,
1050                                                                cand_pair->local_candidate.conn_port,
1051                                                                cand_pair->local_candidate.cand_type,
1052                                                                cand_pair->remote_candidate.conn_addr,
1053                                                                cand_pair->remote_candidate.conn_port,
1054                                                                cand_pair->remote_candidate.cand_type);
1055                                                                */
1056                                                        break;
1057                                                }
1058                                        }
1059                                        if (pos2==10 || remote_candidates[pos2].remote_candidate.conn_addr[0]=='\0')
1060                                        {
1061                                                struct CandidatePair new_pair;
1062                                                memset(&new_pair, 0, sizeof(struct CandidatePair));
1063
1064                                                /* 7.1.2.2.1.  Discovering Peer Reflexive Candidates */
1065                                                /* If IP & port were different than mappedAddr, there was A NAT
1066                                                between me and remote destination. */
1067                                                memcpy(&new_pair.remote_candidate, &cand_pair->remote_candidate, sizeof(new_pair.remote_candidate));
1068
1069                                                new_pair.local_candidate.foundation = 6;
1070                                                new_pair.local_candidate.component_id = cand_pair->local_candidate.component_id;
1071
1072                                                /* what is my base address? */
1073                                                new_pair.local_candidate.rel_port = cand_pair->local_candidate.conn_port;
1074                                                snprintf(new_pair.local_candidate.rel_addr, sizeof(new_pair.local_candidate.rel_addr),
1075                                                        "%s", cand_pair->local_candidate.conn_addr);
1076
1077                                                new_pair.local_candidate.conn_port = mappedAddr.port;
1078                                                snprintf(new_pair.local_candidate.conn_addr, sizeof(new_pair.local_candidate.conn_addr),
1079                                                        "%s", mapped_addr);
1080
1081                                                /* take it from PRIORITY STUN attr */
1082                                                new_pair.local_candidate.priority = (UInt32)(pow((double)2,(double)24)*(110) + pow((double)2,(double)8)*(65535) + pow((double)2,(double)0)*(256 - new_pair.local_candidate.component_id));
1083
1084                                                snprintf(new_pair.local_candidate.cand_type, sizeof(cand_pair->local_candidate.cand_type),
1085                                                        "prflx");
1086                                                snprintf (new_pair.local_candidate.transport,
1087                                                                                sizeof (new_pair.local_candidate.transport),
1088                                                                                "UDP");
1089
1090                                                if (checklist->rem_controlling==0)
1091                                                {
1092                                                        int G = new_pair.local_candidate.priority;
1093                                                        /* controlled agent */ 
1094                                                        int D = new_pair.remote_candidate.priority;
1095                                                        new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1096                                                }
1097                                                else
1098                                                {
1099                                                        int G = new_pair.remote_candidate.priority;
1100                                                        /* controlled agent */ 
1101                                                        int D = new_pair.local_candidate.priority;
1102                                                        new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1103                                                }
1104                                                new_pair.connectivity_check = ICE_WAITING;
1105                                                /* insert new pair candidate */
1106                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1107                                                {
1108                                                        if (pos2==9)
1109                                                        {
1110                                                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) no room for new local peer-reflexive candidate",
1111                                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1112                                                                        pos2,
1113                                                                        new_pair.local_candidate.conn_addr,
1114                                                                        new_pair.local_candidate.conn_port,
1115                                                                        new_pair.local_candidate.cand_type,
1116                                                                        new_pair.remote_candidate.conn_addr,
1117                                                                        new_pair.remote_candidate.conn_port,
1118                                                                        new_pair.remote_candidate.cand_type);
1119                                                                break;
1120                                                        }
1121                                                        if (new_pair.pair_priority > remote_candidates[pos2].pair_priority)
1122                                                        {
1123                                                                /* move upper data */
1124                                                                memmove(&remote_candidates[pos2+1], &remote_candidates[pos2], sizeof(struct CandidatePair)*(10-pos2-1));
1125                                                                memcpy(&remote_candidates[pos2], &new_pair, sizeof(struct CandidatePair));
1126
1127                                                                if (checklist->nominated_pair_index>=pos2)
1128                                                                        checklist->nominated_pair_index++;
1129                                                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) new discovered local peer-reflexive candidate",
1130                                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1131                                                                        pos2,
1132                                                                        new_pair.local_candidate.conn_addr,
1133                                                                        new_pair.local_candidate.conn_port,
1134                                                                        new_pair.local_candidate.cand_type,
1135                                                                        new_pair.remote_candidate.conn_addr,
1136                                                                        new_pair.remote_candidate.conn_port,
1137                                                                        new_pair.remote_candidate.cand_type);
1138                                                                break;
1139                                                        }
1140                                                }
1141                                        }
1142                                }
1143                        }
1144                }
1145        }
1146        else if (STUN_IS_ERR_RESP(msg.msgHdr.msgType))
1147        {
1148                StunMessage resp;
1149                memset(&resp, 0, sizeof(StunMessage));
1150                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
1151                        &resp );
1152                if (!res)
1153                {
1154                        ms_error("ice.c: ERROR_RESPONSE: Bad format for STUN answer.");
1155                        return -1;
1156                }
1157
1158                int pos;
1159                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1160                {
1161                        struct CandidatePair *cand_pair = &remote_candidates[pos];
1162
1163                        if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
1164                        {
1165                                cand_pair->connectivity_check = ICE_FAILED;
1166                                ms_message("ice.c: ERROR_RESPONSE: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
1167                                        cand_pair->local_candidate.conn_addr,
1168                                        cand_pair->local_candidate.conn_port,
1169                                        cand_pair->remote_candidate.conn_addr,
1170                                        cand_pair->remote_candidate.conn_port);
1171                                if (resp.hasErrorCode==TRUE && resp.errorCode.errorClass==4 && resp.errorCode.number==87)
1172                                {
1173                                        if (remote_candidates[pos].rem_controlling==1)
1174                                        {
1175                                                int pos2;
1176                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1177                                                {
1178                                                        /* controller agent */
1179                                                        int G = remote_candidates[pos2].local_candidate.priority;
1180                                                        /* controlled agent */ 
1181                                                        int D = remote_candidates[pos2].remote_candidate.priority;
1182                                                        remote_candidates[pos2].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1183                                                }
1184                                                checklist->rem_controlling=0;
1185                                        }
1186                                        else
1187                                        {
1188                                                int pos2;
1189                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1190                                                {
1191                                                        /* controller agent */
1192                                                        int G = remote_candidates[pos2].remote_candidate.priority;
1193                                                        /* controlled agent */ 
1194                                                        int D = remote_candidates[pos2].local_candidate.priority;
1195                                                        remote_candidates[pos2].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1196                                                }
1197                                                checklist->rem_controlling=1;
1198                                        }
1199                                        /* reset all to initial WAITING state? */
1200                                        ms_message("ice.c: ERROR_RESPONSE: 487 -> reset all to ICE_WAITING state");
1201                                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1202                                        {
1203                                                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
1204                                                        continue;
1205                                                remote_candidates[pos].connectivity_check = ICE_WAITING;
1206                                                memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
1207                                                remote_candidates[pos].retransmission_time = 0;
1208                                                remote_candidates[pos].retransmission_number = 0;
1209                                        }
1210                                }
1211                        }
1212                }
1213        }
1214
1215        return 0;
1216}
1217
Note: See TracBrowser for help on using the repository browser.