source: mediastreamer2/linphone/mediastreamer2/src/ice.c @ 355:87138af50068

Last change on this file since 355:87138af50068 was 355:87138af50068, checked in by smorlat <smorlat@…>, 4 years ago

tuning of echo limiter

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

File size: 44.2 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/msticker.h"
29#include "mediastreamer2/ice.h"
30#include "mediastreamer2/mscommon.h"
31
32static void 
33ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, 
34              const StunAtrString *username, const StunAtrString *password, 
35              UInt96 *tid)
36{       
37   StunMessage req;
38   char buf[STUN_MAX_MESSAGE_SIZE];
39   int len = STUN_MAX_MESSAGE_SIZE;
40   
41   memset(&req, 0, sizeof(StunMessage));
42
43   stunBuildReqSimple( &req, username, FALSE, FALSE, 1);
44   req.hasMessageIntegrity=TRUE;
45
46   /* 7.1.1.1
47   The attribute MUST be set equal to the priority that would be
48   assigned, based on the algorithm in Section 4.1.2, to a peer
49   reflexive candidate, should one be learned as a consequence of this
50   check */
51   req.hasPriority = TRUE;
52
53   req.priority.priority = (110 << 24) | (255 << 16) | (255 << 8)
54           | (256 - remote_candidate->remote_candidate.component_id);
55
56   /* TODO: put this parameter only for the candidate selected */
57   if (remote_candidate->nominated_pair==1)
58           req.hasUseCandidate = TRUE;
59
60   if (remote_candidate->rem_controlling==1)
61           {
62                   req.hasIceControlled = TRUE;
63                   req.iceControlled.value = checklist->tiebreak_value;
64           }
65   else
66           {
67                   req.hasIceControlling = TRUE;
68                   req.iceControlling.value     = checklist->tiebreak_value;
69           }
70
71   /* TODO: not yet implemented? */
72   req.hasFingerprint = TRUE;
73   
74   len = stunEncodeMessage( &req, buf, len, password );
75
76   memcpy(tid , &(req.msgHdr.tr_id), sizeof(req.msgHdr.tr_id));
77
78   sendMessage( myFd, buf, len, dest->addr, dest->port );       
79}
80
81static int ice_restart(struct IceCheckList *checklist)
82{
83        struct CandidatePair *remote_candidates = NULL;
84        int pos;
85
86        int count_waiting=0;
87        int count=0;
88
89        if (checklist==NULL)
90                return 0;
91        remote_candidates = checklist->cand_pairs;
92        if (remote_candidates==NULL)
93                return 0;
94
95        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
96        {
97                if (strcasecmp(remote_candidates[pos].local_candidate.cand_type, "srflx")==0)
98                {
99                        /* search for a highest priority "equivalent" pair */
100                        int pos2;
101                        for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
102                        {
103                                /* same "base" address (origin of STUN connectivity check to the remote candidate */
104                                if (strcasecmp(remote_candidates[pos].local_candidate.rel_addr, /* base address for "reflexive" address */
105                                        remote_candidates[pos2].local_candidate.conn_addr)==0) /* base address for "host" address */
106                                {
107                                        /* if same target remote candidate: -> remove the one with lowest priority */
108                                        if (strcasecmp(remote_candidates[pos].remote_candidate.conn_addr,
109                                                remote_candidates[pos2].remote_candidate.conn_addr)==0)
110                                        {   
111                                                /* useless cpair */                 
112                                                ms_message("ice.c: Removing useless pair (idx=%i)", pos);
113                                                remote_candidates[pos].connectivity_check = ICE_PRUNED;
114
115                                        }
116
117                                }
118
119                        }
120                }
121        }
122
123        /* no currently nominated pair */
124        checklist->nominated_pair_index = -1;
125
126        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
127        {
128                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
129                        continue;
130                if (remote_candidates[pos].connectivity_check == ICE_FROZEN)
131                        remote_candidates[pos].connectivity_check = ICE_WAITING;
132        }
133
134        checklist->Ta = 40;
135        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
136        {
137                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
138                        continue;
139                if (remote_candidates[pos].connectivity_check == ICE_WAITING)
140                        count_waiting++;
141                count++;
142        }
143        checklist->RTO = MAX(200, count*checklist->Ta*count_waiting);
144        return 0;
145}
146
147static int ice_sound_send_stun_request(RtpSession *session, struct IceCheckList *checklist, uint64_t ctime)
148{
149        struct CandidatePair *remote_candidates = NULL;
150
151        if (checklist==NULL)
152                return 0;
153        remote_candidates = checklist->cand_pairs;
154        if (remote_candidates==NULL)
155                return 0;
156
157        {
158                struct CandidatePair *cand_pair;
159                int media_socket = rtp_session_get_rtp_socket(session);
160                StunAddress4 stunServerAddr;
161                StunAtrString username;
162                StunAtrString password;
163                bool_t res;
164                int pos;
165
166                /* prepare ONCE tie-break value */
167                if (checklist->tiebreak_value==0) {
168                        checklist->tiebreak_value = random() * (0x7fffffffffffffffLL /0x7fff);
169                }
170
171                cand_pair=NULL;
172                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
173                {
174                        cand_pair = &remote_candidates[pos];
175                        if (cand_pair->connectivity_check == ICE_PRUNED)
176                        {
177                                cand_pair=NULL;
178                                continue;
179                        }
180                        if (cand_pair->connectivity_check == ICE_WAITING)
181                                break;
182                        if (cand_pair->connectivity_check == ICE_IN_PROGRESS)
183                                break;
184                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
185                                break;
186                        cand_pair=NULL;
187                }
188
189                if (cand_pair==NULL)
190                        return 0; /* nothing to do: every pair is FAILED, FROZEN or PRUNED */
191
192                /* start first WAITING pair */
193                cand_pair=NULL;
194                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
195                {
196                        cand_pair = &remote_candidates[pos];
197                        if (cand_pair->connectivity_check == ICE_PRUNED)
198                        {
199                                cand_pair=NULL;
200                                continue;
201                        }
202                        if (cand_pair->connectivity_check == ICE_WAITING)
203                                break;
204                        cand_pair=NULL;
205                }
206
207                if (cand_pair!=NULL)
208                {
209                        cand_pair->connectivity_check = ICE_IN_PROGRESS;
210                        cand_pair->retransmission_number=0;
211                        cand_pair->retransmission_time=ctime+checklist->RTO;
212                        /* keep same rem_controlling for retransmission */
213                        cand_pair->rem_controlling = checklist->rem_controlling;
214                }
215
216                /* try no nominate a pair if we are ready */
217                if (cand_pair==NULL && checklist->nominated_pair_index<0)
218                {
219                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
220                        {
221                                cand_pair = &remote_candidates[pos];
222                                if (cand_pair->connectivity_check == ICE_PRUNED)
223                                {
224                                        cand_pair=NULL;
225                                        continue;
226                                }
227                                if (cand_pair->connectivity_check == ICE_SUCCEEDED)
228                                {
229                                        break;
230                                }
231                                cand_pair=NULL;
232                        }
233
234                        /* ALWAYS accept "host" candidate that have succeeded */
235                        if (cand_pair!=NULL
236                                && (strcasecmp(cand_pair->remote_candidate.cand_type, "host")==0))
237                        {
238                                checklist->nominated_pair_index = pos;
239                                cand_pair->nominated_pair = 1;
240                                cand_pair->connectivity_check = ICE_IN_PROGRESS;
241                                cand_pair->retransmission_number=0;
242                                cand_pair->retransmission_time=ctime+checklist->RTO;
243                                /* keep same rem_controlling for retransmission */
244                                cand_pair->rem_controlling = checklist->rem_controlling;
245                                /* send a new STUN with USE-CANDIDATE */
246                                ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
247                                        pos,
248                                        cand_pair->local_candidate.conn_addr,
249                                        cand_pair->local_candidate.conn_port,
250                                        cand_pair->local_candidate.cand_type,
251                                        cand_pair->remote_candidate.conn_addr,
252                                        cand_pair->remote_candidate.conn_port,
253                                        cand_pair->remote_candidate.cand_type,
254                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
255                                checklist->keepalive_time=ctime+15*1000;
256                        }
257                        else if (cand_pair!=NULL)
258                        {
259                                struct CandidatePair *cand_pair2;
260                                int pos2;
261                                for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
262                                {
263                                        cand_pair2 = &remote_candidates[pos2];
264                                        if (cand_pair2->connectivity_check == ICE_PRUNED)
265                                        {
266                                                cand_pair2=NULL;
267                                                continue;
268                                        }
269                                        if (cand_pair2->connectivity_check == ICE_IN_PROGRESS
270                                                ||cand_pair2->connectivity_check == ICE_WAITING)
271                                        {
272                                                break;
273                                        }
274                                        cand_pair2=NULL;
275                                }
276
277                                if (cand_pair2!=NULL)
278                                {
279                                        /* a better candidate is still tested */
280                                        cand_pair=NULL;
281                                }
282                                else
283                                {
284                                        checklist->nominated_pair_index = pos;
285                                        cand_pair->nominated_pair = 1;
286                                        cand_pair->connectivity_check = ICE_IN_PROGRESS;
287                                        cand_pair->retransmission_number=0;
288                                        cand_pair->retransmission_time=ctime+checklist->RTO;
289                                        /* keep same rem_controlling for retransmission */
290                                        cand_pair->rem_controlling = checklist->rem_controlling;
291                                        /* send a new STUN with USE-CANDIDATE */
292                                        ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
293                                                pos,
294                                                cand_pair->local_candidate.conn_addr,
295                                                cand_pair->local_candidate.conn_port,
296                                                cand_pair->local_candidate.cand_type,
297                                                cand_pair->remote_candidate.conn_addr,
298                                                cand_pair->remote_candidate.conn_port,
299                                                cand_pair->remote_candidate.cand_type,
300                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
301                                        checklist->keepalive_time=ctime+15*1000;
302                                }
303                        }
304                }
305
306                if (cand_pair==NULL)
307                {
308                        /* no WAITING pair: retransmit after RTO */
309                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
310                        {
311                                cand_pair = &remote_candidates[pos];
312                                if (cand_pair->connectivity_check == ICE_PRUNED)
313                                {
314                                        cand_pair=NULL;
315                                        continue;
316                                }
317                                if (cand_pair->connectivity_check == ICE_IN_PROGRESS
318                                        && ctime > cand_pair->retransmission_time)
319                                {
320                                        if (cand_pair->retransmission_number>7)
321                                        {
322                                                ms_message("ice.c: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
323                                                        cand_pair->local_candidate.conn_addr,
324                                                        cand_pair->local_candidate.conn_port,
325                                                        cand_pair->remote_candidate.conn_addr,
326                                                        cand_pair->remote_candidate.conn_port);
327
328                                                cand_pair->connectivity_check = ICE_FAILED;
329                                                cand_pair=NULL;
330                                                continue;
331                                        }
332
333                                        cand_pair->retransmission_number++;
334                                        cand_pair->retransmission_time=ctime+checklist->RTO;
335                                        break;
336                                }
337                                cand_pair=NULL;
338                        }
339                }
340
341                if (cand_pair==NULL)
342                {
343                        if (checklist->nominated_pair_index<0)
344                                return 0;
345
346                        /* send STUN indication each 15 seconds: keepalive */
347                        if (ctime>checklist->keepalive_time)
348                        {
349                                checklist->keepalive_time=ctime+15*1000;
350                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
351                                {
352                                        cand_pair = &remote_candidates[pos];
353                                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
354                                        {
355                                                res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
356                                                        &stunServerAddr);
357                                                if ( res == TRUE )
358                                                {
359                                                        StunMessage req;
360                                                        char buf[STUN_MAX_MESSAGE_SIZE];
361                                                        int len = STUN_MAX_MESSAGE_SIZE;
362                                                        stunServerAddr.port = cand_pair->remote_candidate.conn_port;
363                                                        memset(&req, 0, sizeof(StunMessage));
364                                                        stunBuildReqSimple( &req, NULL, FALSE, FALSE, 1);
365                                                        req.msgHdr.msgType = (STUN_METHOD_BINDING|STUN_INDICATION);
366                                                        req.hasFingerprint = TRUE;
367                                                        len = stunEncodeMessage( &req, buf, len, NULL);
368                                                        sendMessage( media_socket, buf, len, stunServerAddr.addr, stunServerAddr.port );
369                                                }
370                                        }
371                                }
372                        }
373
374                        return 0;
375                }
376
377                username.sizeValue = 0;
378                password.sizeValue = 0;
379
380                /* username comes from "ice-ufrag" (rfrag:lfrag) */
381                /* ufrag and pwd are in first row only */
382                snprintf(username.value, sizeof(username.value), "%s:%s",
383                        checklist->rem_ice_ufrag,
384                        checklist->loc_ice_ufrag);
385                username.sizeValue = (UInt16)strlen(username.value);
386
387
388                snprintf(password.value, sizeof(password.value), "%s",
389                        checklist->rem_ice_pwd);
390                password.sizeValue = (UInt16)strlen(password.value);
391
392
393                res = stunParseServerName(cand_pair->remote_candidate.conn_addr,
394                        &stunServerAddr);
395                if ( res == TRUE )
396                {
397                        ms_message("ice.c: STUN REQ (%s) -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s",
398                                cand_pair->nominated_pair==0?"":"USE-CANDIDATE",
399                                pos,
400                                cand_pair->local_candidate.conn_addr,
401                                cand_pair->local_candidate.conn_port,
402                                cand_pair->local_candidate.cand_type,
403                                cand_pair->remote_candidate.conn_addr,
404                                cand_pair->remote_candidate.conn_port,
405                                cand_pair->remote_candidate.cand_type,
406                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
407                        stunServerAddr.port = cand_pair->remote_candidate.conn_port;
408                        ice_sendtest(checklist, cand_pair, media_socket, &stunServerAddr, &username, &password,
409                                &(cand_pair->tid));
410                }
411        }
412
413        return 0;
414}
415
416#if 0
417static int
418_ice_get_localip_for (struct sockaddr_storage *saddr, size_t saddr_len, char *loc, int size)
419{
420        int err, tmp;
421        int sock;
422        struct sockaddr_storage addr;
423        socklen_t addr_len;
424
425        strcpy (loc, "127.0.0.1");    /* always fallback to local loopback */
426
427        sock = socket (saddr->ss_family, SOCK_DGRAM, 0);
428        tmp = 1;
429        err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &tmp, sizeof (int));
430        if (err < 0)
431        {
432                ms_error("ice.c: Error in setsockopt");
433                closesocket (sock);
434                return -1;
435        }
436        err = connect (sock, (struct sockaddr*)saddr, saddr_len);
437        if (err < 0)
438        {
439                ms_error("ice.c: Error in connect");
440                closesocket (sock);
441                return -1;
442        }
443        addr_len = sizeof (addr);
444        err = getsockname (sock, (struct sockaddr *) &addr, (socklen_t*)&addr_len);
445        if (err != 0)
446        {
447                ms_error("ice.c: Error in getsockname");
448                closesocket (sock);
449                return -1;
450        }
451
452        err = getnameinfo ((struct sockaddr *) &addr, addr_len, loc, size, NULL, 0, NI_NUMERICHOST);
453        if (err != 0)
454        {
455                ms_error("ice.c: Error in getnameinfo");
456                closesocket (sock);
457                return -1;
458        }
459        closesocket (sock);
460        /* ms_message("ice.c: Outgoing interface for sending STUN answer is %s", loc); */
461        return 0;
462}
463
464#endif
465
466static void
467_ice_createErrorResponse(StunMessage *response, int cl, int number, const char* msg)
468{
469        response->msgHdr.msgType = (STUN_METHOD_BINDING | STUN_ERR_RESP);
470        response->hasErrorCode = TRUE;
471        response->errorCode.errorClass = cl;
472        response->errorCode.number = number;
473        strcpy(response->errorCode.reason, msg);
474        response->errorCode.sizeReason = strlen(msg);
475        response->hasFingerprint = TRUE;
476}
477
478static int ice_process_stun_message(RtpSession *session, struct IceCheckList *checklist, OrtpEvent *evt)
479{
480        struct CandidatePair *remote_candidates = NULL;
481        StunMessage msg;
482        bool_t res;
483        int highest_priority_success=-1;
484        OrtpEventData *evt_data = ortp_event_get_data(evt);
485        mblk_t *mp = evt_data->packet;
486        struct sockaddr_in *udp_remote;
487        char src6host[NI_MAXHOST];
488        int recvport = 0;
489        int i;
490
491        udp_remote = (struct sockaddr_in*)&evt_data->ep->addr;
492
493        memset( &msg, 0 , sizeof(msg) );
494        res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg);
495        if (!res)
496        {
497                ms_error("ice.c: Malformed STUN packet.");
498                return -1;
499        }
500
501        if (checklist==NULL)
502        {
503                ms_error("ice.c: dropping STUN packet: ice is not configured");
504                return -1;
505        }
506
507        remote_candidates = checklist->cand_pairs;
508        if (remote_candidates==NULL)
509        {
510                ms_error("ice.c: dropping STUN packet: ice is not configured");
511                return -1;
512        }
513
514        /* prepare ONCE tie-break value */
515        if (checklist->tiebreak_value==0) {
516                checklist->tiebreak_value = random() * (0x7fffffffffffffffLL/0x7fff);
517        }
518
519        memset (src6host, 0, sizeof (src6host));
520
521        {
522                struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr;
523                if (aaddr->ss_family==AF_INET)
524                        recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port);
525                else
526                        recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port);
527        }
528        i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen,
529                src6host, NI_MAXHOST,
530                NULL, 0, NI_NUMERICHOST);
531        if (i != 0)
532        {
533                ms_error("ice.c: Error with getnameinfo");
534                return -1;
535        }
536
537        if (STUN_IS_REQUEST(msg.msgHdr.msgType))
538                ms_message("ice.c: STUN_CONNECTIVITYCHECK: Request received from: %s:%i",
539                src6host, recvport);
540        else if (STUN_IS_INDICATION(msg.msgHdr.msgType))
541                ms_message("ice.c: SUN_INDICATION: Request Indication received from: %s:%i",
542                src6host, recvport);
543        else
544                ms_message("ice.c: STUN_ANSWER: Answer received from: %s:%i",
545                src6host, recvport);
546
547        {
548                int pos;
549                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
550                {
551                        struct CandidatePair *cand_pair = &remote_candidates[pos];
552
553                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
554                        {
555                                highest_priority_success=pos;
556                                break;
557                        }
558                }
559        }
560
561        if (STUN_IS_INDICATION(msg.msgHdr.msgType))
562        {
563                ms_message("ice.c: STUN INDICATION <- (?:?:? <- %s:%i:?)", src6host, recvport);
564                return 0;
565        }
566        else if (STUN_IS_REQUEST(msg.msgHdr.msgType))
567        {
568                StunMessage resp;
569                StunAtrString hmacPassword;
570                StunAddress4 remote_addr;
571                int rtp_socket;
572
573                memset( &resp, 0 , sizeof(resp));
574                remote_addr.addr = ntohl(udp_remote->sin_addr.s_addr);
575                remote_addr.port = ntohs(udp_remote->sin_port);
576
577                rtp_socket = rtp_session_get_rtp_socket(session);
578
579                resp.msgHdr.magic_cookie = ntohl(msg.msgHdr.magic_cookie);
580                for (i=0; i<12; i++ )
581                {
582                        resp.msgHdr.tr_id.octet[i] = msg.msgHdr.tr_id.octet[i];
583                }
584
585                /* check mandatory params */
586
587                if (!msg.hasUsername)
588                {
589                        char buf[STUN_MAX_MESSAGE_SIZE];
590                        int len = sizeof(buf);
591                        ms_error("ice.c: STUN REQ <- Missing USERNAME attribute in connectivity check");
592                        _ice_createErrorResponse(&resp, 4, 32, "Missing USERNAME attribute");
593                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
594                        if (len)
595                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
596                        return -1;
597                }
598                if (!msg.hasMessageIntegrity)
599                {
600                        char buf[STUN_MAX_MESSAGE_SIZE];
601                        int len = sizeof(buf);
602                        ms_error("ice.c: STUN REQ <- Missing MESSAGEINTEGRITY attribute in connectivity check");
603                        _ice_createErrorResponse(&resp, 4, 1, "Missing MESSAGEINTEGRITY attribute");
604                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
605                        if (len)
606                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
607                        return -1;
608                }
609
610                /*
611                The password associated with that transport address ID is used to verify
612                the MESSAGE-INTEGRITY attribute, if one was present in the request.
613                */
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
646                /* 7.2.1.1. Detecting and Repairing Role Conflicts */
647                /* TODO */
648                if (!msg.hasIceControlling && !msg.hasIceControlled)
649                {
650                        char buf[STUN_MAX_MESSAGE_SIZE];
651                        int len = sizeof(buf);
652                        ms_error("ice.c: STUN REQ <- Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
653                        _ice_createErrorResponse(&resp, 4, 87, "Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
654                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
655                        if (len)
656                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
657                        return -1;
658                }
659
660                if (checklist->rem_controlling==0 && msg.hasIceControlling) {
661                        /* If the agent's tie-breaker is larger than or equal
662                        to the contents of the ICE-CONTROLLING attribute
663                        -> send 487, and do not change ROLE */
664                        if (checklist->tiebreak_value >= msg.iceControlling.value) {
665                                char buf[STUN_MAX_MESSAGE_SIZE];
666                                int len = sizeof(buf);
667                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
668                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
669                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
670                                if (len)
671                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
672                                return -1;
673                        }
674                        else {
675                                int pos;
676                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
677                                {
678                                        /* controller agent */
679                                        uint64_t G = remote_candidates[pos].remote_candidate.priority;
680                                        /* controlled agent */ 
681                                        uint64_t D = remote_candidates[pos].local_candidate.priority;
682                                        remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
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                                        uint64_t G = remote_candidates[pos].local_candidate.priority;
710                                        /* controlled agent */ 
711                                        uint64_t D = remote_candidates[pos].remote_candidate.priority;
712                                        remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
713                                }
714                                checklist->rem_controlling = 0;
715                                /* reset all to initial WAITING state? */
716                                ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
717                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
718                                {
719                                        if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
720                                                continue;
721                                        remote_candidates[pos].connectivity_check = ICE_WAITING;
722                                        memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
723                                        remote_candidates[pos].retransmission_time = 0;
724                                        remote_candidates[pos].retransmission_number = 0;
725                                }
726                        }
727                        else {
728                                char buf[STUN_MAX_MESSAGE_SIZE];
729                                int len = sizeof(buf);
730                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
731                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
732                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
733                                if (len)
734                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
735                                return -1;
736                        }
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                                {
816                                        uint32_t type_preference = 110;
817                                        uint32_t interface_preference = 255;
818                                        uint32_t stun_priority=255;
819                                        new_pair.remote_candidate.priority = (type_preference << 24) | (interface_preference << 16) | (stun_priority << 8)
820                                                | (256 - new_pair.remote_candidate.component_id);
821                                }
822
823                                snprintf(new_pair.remote_candidate.cand_type, sizeof(cand_pair->remote_candidate.cand_type),
824                                        "prflx");
825                                snprintf (new_pair.remote_candidate.transport,
826                                                                sizeof (new_pair.remote_candidate.transport),
827                                                                "UDP");
828
829                                if (checklist->rem_controlling==0)
830                                {
831                                        uint64_t G = new_pair.local_candidate.priority;
832                                        /* controlled agent */ 
833                                        uint64_t D = new_pair.remote_candidate.priority;
834                                        new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
835                                }
836                                else
837                                {
838                                        uint64_t G = new_pair.remote_candidate.priority;
839                                        /* controlled agent */ 
840                                        uint64_t D = new_pair.local_candidate.priority;
841                                        new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
842                                }
843                                new_pair.connectivity_check = ICE_WAITING;
844                                /* insert new pair candidate */
845                                if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
846                                {
847                                        new_pair.nominated_pair = 1;
848                                }
849
850                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
851                                {
852                                        if (pos==9)
853                                        {
854                                                ms_message("ice.c: STUN REQ (%s) <- X (%s:%i:%s <- %s:%i:%s) no room for new remote reflexive candidate",
855                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
856                                                        new_pair.local_candidate.conn_addr,
857                                                        new_pair.local_candidate.conn_port,
858                                                        new_pair.local_candidate.cand_type,
859                                                        new_pair.remote_candidate.conn_addr,
860                                                        new_pair.remote_candidate.conn_port,
861                                                        new_pair.remote_candidate.cand_type);
862                                                break;
863                                        }
864                                        if (new_pair.pair_priority > remote_candidates[pos].pair_priority)
865                                        {
866                                                /* move upper data */
867                                                memmove(&remote_candidates[pos+1], &remote_candidates[pos], sizeof(struct CandidatePair)*(10-pos-1));
868                                                memcpy(&remote_candidates[pos], &new_pair, sizeof(struct CandidatePair));
869
870                                                if (checklist->nominated_pair_index>=pos)
871                                                        checklist->nominated_pair_index++;
872                                                ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) new learned remote reflexive candidate",
873                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
874                                                        pos,
875                                                        new_pair.local_candidate.conn_addr,
876                                                        new_pair.local_candidate.conn_port,
877                                                        new_pair.local_candidate.cand_type,
878                                                        new_pair.remote_candidate.conn_addr,
879                                                        new_pair.remote_candidate.conn_port,
880                                                        new_pair.remote_candidate.cand_type);
881                                                break;
882                                        }
883                                }
884                        }
885                }
886
887                {
888                        UInt32 cookie = 0x2112A442;
889                        resp.hasXorMappedAddress = TRUE;
890                        resp.xorMappedAddress.ipv4.port = remote_addr.port^(cookie>>16);
891                        resp.xorMappedAddress.ipv4.addr = remote_addr.addr^cookie;
892                }
893
894                resp.msgHdr.msgType = (STUN_METHOD_BINDING | STUN_SUCCESS_RESP);
895
896                resp.hasUsername = TRUE;
897                memcpy(resp.username.value, msg.username.value, msg.username.sizeValue );
898                resp.username.sizeValue = msg.username.sizeValue;
899
900                /* ? any messageintegrity in response? */
901                resp.hasMessageIntegrity = TRUE;
902
903                {
904                        const char serverName[] = "mediastreamer2 " STUN_VERSION;
905                        resp.hasSoftware = TRUE;
906                        memcpy( resp.softwareName.value, serverName, sizeof(serverName));
907                        resp.softwareName.sizeValue = sizeof(serverName);
908                }
909
910                resp.hasFingerprint = TRUE;
911
912                {
913                        char buf[STUN_MAX_MESSAGE_SIZE];
914                        int len = sizeof(buf);
915                        len = stunEncodeMessage( &resp, buf, len, &hmacPassword );
916                        if (len)
917                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
918                }
919        }
920        else if (STUN_IS_SUCCESS_RESP(msg.msgHdr.msgType))
921        {
922                /* set state to RECV-VALID or VALID */
923                StunMessage resp;
924                StunAddress4 mappedAddr;
925                memset(&resp, 0, sizeof(StunMessage));
926                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
927                        &resp );
928                if (!res)
929                {
930                        ms_error("ice.c: STUN RESP <- Bad format for STUN answer.");
931                        return -1;
932                }
933
934                if (resp.hasXorMappedAddress!=TRUE)
935                {
936                        ms_error("ice.c: STUN RESP <- Missing XOR-MAPPED-ADDRESS in STUN answer.");               
937                        return -1;
938                }
939
940                {
941                        UInt32 cookie = 0x2112A442;
942                        UInt16 cookie16 = 0x2112A442 >> 16;
943                        mappedAddr.port = resp.xorMappedAddress.ipv4.port^cookie16;
944                        mappedAddr.addr = resp.xorMappedAddress.ipv4.addr^cookie;
945                }
946
947                {
948                        struct in_addr inaddr;
949                        char mapped_addr[64];
950                        struct CandidatePair *cand_pair=NULL;
951                        int pos;
952                        inaddr.s_addr = htonl (mappedAddr.addr);
953                        snprintf(mapped_addr, sizeof(mapped_addr),
954                                "%s", inet_ntoa (inaddr));
955
956                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
957                        {
958                                cand_pair = &remote_candidates[pos];
959
960                                if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
961                                {
962                                        break;
963                                }
964                                cand_pair = NULL;
965                        }
966
967                        if (cand_pair==NULL)
968                        {
969                                ms_message("ice.c: STUN RESP (%s) <- no transaction for STUN answer?",
970                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE");
971                        }
972                        else if (strcmp(src6host, cand_pair->remote_candidate.conn_addr)!=0
973                                || recvport!=cand_pair->remote_candidate.conn_port)
974                        {
975                                /* 7.1.2.2.  Success Cases
976                                -> must be a security issue: refuse non-symmetric answer */
977                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s) refused because non-symmetric",
978                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
979                                        pos,
980                                        cand_pair->local_candidate.conn_addr,
981                                        cand_pair->local_candidate.conn_port,
982                                        cand_pair->local_candidate.cand_type,
983                                        cand_pair->remote_candidate.conn_addr,
984                                        cand_pair->remote_candidate.conn_port,
985                                        cand_pair->remote_candidate.cand_type,
986                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
987                                cand_pair->connectivity_check = ICE_FAILED;
988                        }
989                        else
990                        {
991                                /* Youhouhouhou */
992                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
993                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
994                                        pos,
995                                        cand_pair->local_candidate.conn_addr,
996                                        cand_pair->local_candidate.conn_port,
997                                        cand_pair->local_candidate.cand_type,
998                                        cand_pair->remote_candidate.conn_addr,
999                                        cand_pair->remote_candidate.conn_port,
1000                                        cand_pair->remote_candidate.cand_type,
1001                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
1002                                if (cand_pair->connectivity_check != ICE_SUCCEEDED)
1003                                {
1004                                        if (checklist->rem_controlling==1 && cand_pair->nominated_pair>0)
1005                                        {
1006                                                /* USE-CANDIDATE was in previous STUN request sent */
1007                                                ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
1008                                                        pos,
1009                                                        cand_pair->local_candidate.conn_addr,
1010                                                        cand_pair->local_candidate.conn_port,
1011                                                        cand_pair->local_candidate.cand_type,
1012                                                        cand_pair->remote_candidate.conn_addr,
1013                                                        cand_pair->remote_candidate.conn_port,
1014                                                        cand_pair->remote_candidate.cand_type,
1015                                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
1016                                                memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1017                                                session->rtp.rem_addrlen=evt_data->ep->addrlen;
1018                                        }
1019
1020                                        if (cand_pair->nominated_pair>0 && checklist->rem_controlling==0)
1021                                        {
1022                                                /* USE-CANDIDATE is in STUN request and we already succeeded on that link */
1023                                                ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
1024                                                        pos,
1025                                                        cand_pair->local_candidate.conn_addr,
1026                                                        cand_pair->local_candidate.conn_port,
1027                                                        cand_pair->local_candidate.cand_type,
1028                                                        cand_pair->remote_candidate.conn_addr,
1029                                                        cand_pair->remote_candidate.conn_port,
1030                                                        cand_pair->remote_candidate.cand_type,
1031                                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
1032                                                memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1033                                                session->rtp.rem_addrlen=evt_data->ep->addrlen;
1034                                        }
1035
1036                                        cand_pair->connectivity_check = ICE_FAILED;
1037                                        if (mappedAddr.port == cand_pair->local_candidate.conn_port
1038                                                && strcmp(mapped_addr, cand_pair->local_candidate.conn_addr)==0)
1039                                        {
1040                                                /* no peer-reflexive candidate was discovered */
1041                                                cand_pair->connectivity_check = ICE_SUCCEEDED;
1042                                        }
1043                                        else
1044                                        {
1045                                                int pos2;
1046                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1047                                                {
1048                                                        if (mappedAddr.port == remote_candidates[pos2].local_candidate.conn_port
1049                                                                && strcmp(mapped_addr, remote_candidates[pos2].local_candidate.conn_addr)==0
1050                                                                && cand_pair->remote_candidate.conn_port == remote_candidates[pos2].remote_candidate.conn_port
1051                                                                && strcmp(cand_pair->remote_candidate.conn_addr, remote_candidates[pos2].remote_candidate.conn_addr)==0)
1052                                                        {
1053                                                                if (remote_candidates[pos2].connectivity_check==ICE_PRUNED
1054                                                                        ||remote_candidates[pos2].connectivity_check==ICE_FROZEN
1055                                                                        ||remote_candidates[pos2].connectivity_check==ICE_FAILED
1056                                                                        || remote_candidates[pos2].connectivity_check==ICE_IN_PROGRESS)
1057                                                                        remote_candidates[pos2].connectivity_check = ICE_WAITING; /* trigger check */
1058                                                                /*
1059                                                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) found candidate pair matching XOR-MAPPED-ADDRESS",
1060                                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1061                                                                        pos,
1062                                                                        cand_pair->local_candidate.conn_addr,
1063                                                                        cand_pair->local_candidate.conn_port,
1064                                                                        cand_pair->local_candidate.cand_type,
1065                                                                        cand_pair->remote_candidate.conn_addr,
1066                                                                        cand_pair->remote_candidate.conn_port,
1067                                                                        cand_pair->remote_candidate.cand_type);
1068                                                                        */
1069                                                                break;
1070                                                        }
1071                                                }
1072                                                if (pos2==10 || remote_candidates[pos2].remote_candidate.conn_addr[0]=='\0')
1073                                                {
1074                                                        struct CandidatePair new_pair;
1075                                                        memset(&new_pair, 0, sizeof(struct CandidatePair));
1076
1077                                                        /* 7.1.2.2.1.  Discovering Peer Reflexive Candidates */
1078                                                        /* If IP & port were different than mappedAddr, there was A NAT
1079                                                        between me and remote destination. */
1080                                                        memcpy(&new_pair.remote_candidate, &cand_pair->remote_candidate, sizeof(new_pair.remote_candidate));
1081
1082                                                        new_pair.local_candidate.foundation = 6;
1083                                                        new_pair.local_candidate.component_id = cand_pair->local_candidate.component_id;
1084
1085                                                        /* what is my base address? */
1086                                                        new_pair.local_candidate.rel_port = cand_pair->local_candidate.conn_port;
1087                                                        snprintf(new_pair.local_candidate.rel_addr, sizeof(new_pair.local_candidate.rel_addr),
1088                                                                "%s", cand_pair->local_candidate.conn_addr);
1089
1090                                                        new_pair.local_candidate.conn_port = mappedAddr.port;
1091                                                        snprintf(new_pair.local_candidate.conn_addr, sizeof(new_pair.local_candidate.conn_addr),
1092                                                                "%s", mapped_addr);
1093
1094                                                        new_pair.remote_candidate.priority = (110 << 24) | (255 << 16) | (255 << 8)
1095                                                                | (256 - new_pair.remote_candidate.component_id);
1096
1097                                                        snprintf(new_pair.local_candidate.cand_type, sizeof(cand_pair->local_candidate.cand_type),
1098                                                                "prflx");
1099                                                        snprintf (new_pair.local_candidate.transport,
1100                                                                                        sizeof (new_pair.local_candidate.transport),
1101                                                                                        "UDP");
1102
1103                                                        if (checklist->rem_controlling==0)
1104                                                        {
1105                                                                uint64_t G = new_pair.local_candidate.priority;
1106                                                                /* controlled agent */ 
1107                                                                uint64_t D = new_pair.remote_candidate.priority;
1108                                                                new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
1109                                                        }
1110                                                        else
1111                                                        {
1112                                                                uint64_t G = new_pair.remote_candidate.priority;
1113                                                                /* controlled agent */ 
1114                                                                uint64_t D = new_pair.local_candidate.priority;
1115                                                                new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
1116                                                        }
1117                                                        new_pair.connectivity_check = ICE_WAITING;
1118                                                        /* insert new pair candidate */
1119                                                        for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1120                                                        {
1121                                                                if (pos2==9)
1122                                                                {
1123                                                                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) no room for new local peer-reflexive candidate",
1124                                                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1125                                                                                pos2,
1126                                                                                new_pair.local_candidate.conn_addr,
1127                                                                                new_pair.local_candidate.conn_port,
1128                                                                                new_pair.local_candidate.cand_type,
1129                                                                                new_pair.remote_candidate.conn_addr,
1130                                                                                new_pair.remote_candidate.conn_port,
1131                                                                                new_pair.remote_candidate.cand_type);
1132                                                                        break;
1133                                                                }
1134                                                                if (new_pair.pair_priority > remote_candidates[pos2].pair_priority)
1135                                                                {
1136                                                                        /* move upper data */
1137                                                                        memmove(&remote_candidates[pos2+1], &remote_candidates[pos2], sizeof(struct CandidatePair)*(10-pos2-1));
1138                                                                        memcpy(&remote_candidates[pos2], &new_pair, sizeof(struct CandidatePair));
1139
1140                                                                        if (checklist->nominated_pair_index>=pos2)
1141                                                                                checklist->nominated_pair_index++;
1142                                                                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) new discovered local peer-reflexive candidate",
1143                                                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1144                                                                                pos2,
1145                                                                                new_pair.local_candidate.conn_addr,
1146                                                                                new_pair.local_candidate.conn_port,
1147                                                                                new_pair.local_candidate.cand_type,
1148                                                                                new_pair.remote_candidate.conn_addr,
1149                                                                                new_pair.remote_candidate.conn_port,
1150                                                                                new_pair.remote_candidate.cand_type);
1151                                                                        break;
1152                                                                }
1153                                                        }
1154                                                }
1155                                        }
1156                                }
1157                        }
1158                }
1159        }
1160        else if (STUN_IS_ERR_RESP(msg.msgHdr.msgType))
1161        {
1162                int pos;
1163                StunMessage resp;
1164                memset(&resp, 0, sizeof(StunMessage));
1165                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
1166                        &resp );
1167                if (!res)
1168                {
1169                        ms_error("ice.c: ERROR_RESPONSE: Bad format for STUN answer.");
1170                        return -1;
1171                }
1172
1173                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1174                {
1175                        struct CandidatePair *cand_pair = &remote_candidates[pos];
1176
1177                        if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
1178                        {
1179                                cand_pair->connectivity_check = ICE_FAILED;
1180                                ms_message("ice.c: ERROR_RESPONSE: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
1181                                        cand_pair->local_candidate.conn_addr,
1182                                        cand_pair->local_candidate.conn_port,
1183                                        cand_pair->remote_candidate.conn_addr,
1184                                        cand_pair->remote_candidate.conn_port);
1185                                if (resp.hasErrorCode==TRUE && resp.errorCode.errorClass==4 && resp.errorCode.number==87)
1186                                {
1187                                        if (remote_candidates[pos].rem_controlling==1)
1188                                        {
1189                                                int pos2;
1190                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1191                                                {
1192                                                        /* controller agent */
1193                                                        uint64_t G = remote_candidates[pos2].local_candidate.priority;
1194                                                        /* controlled agent */ 
1195                                                        uint64_t D = remote_candidates[pos2].remote_candidate.priority;
1196                                                        remote_candidates[pos2].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
1197                                                }
1198                                                checklist->rem_controlling=0;
1199                                        }
1200                                        else
1201                                        {
1202                                                int pos2;
1203                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1204                                                {
1205                                                        /* controller agent */
1206                                                        uint64_t G = remote_candidates[pos2].remote_candidate.priority;
1207                                                        /* controlled agent */ 
1208                                                        uint64_t D = remote_candidates[pos2].local_candidate.priority;
1209                                                        remote_candidates[pos2].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0);
1210                                                }
1211                                                checklist->rem_controlling=1;
1212                                        }
1213                                        /* reset all to initial WAITING state? */
1214                                        ms_message("ice.c: ERROR_RESPONSE: 487 -> reset all to ICE_WAITING state");
1215                                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1216                                        {
1217                                                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
1218                                                        continue;
1219                                                remote_candidates[pos].connectivity_check = ICE_WAITING;
1220                                                memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
1221                                                remote_candidates[pos].retransmission_time = 0;
1222                                                remote_candidates[pos].retransmission_number = 0;
1223                                        }
1224                                }
1225                        }
1226                }
1227        }
1228
1229        return 0;
1230}
1231
1232
1233
1234
1235struct IceData {
1236        RtpSession *session;
1237        OrtpEvQueue *ortp_event;
1238        struct IceCheckList *check_lists;       /* table of 10 cpair */
1239        int rate;
1240};
1241
1242typedef struct IceData IceData;
1243
1244static void ice_init(MSFilter * f)
1245{
1246        IceData *d = (IceData *)ms_new(IceData, 1);
1247
1248        d->ortp_event = ortp_ev_queue_new();
1249        d->session = NULL;
1250        d->check_lists = NULL;
1251        d->rate = 8000;
1252        f->data = d;
1253}
1254
1255static void ice_postprocess(MSFilter * f)
1256{
1257        IceData *d = (IceData *) f->data;
1258        if (d->session!=NULL && d->ortp_event!=NULL)
1259          rtp_session_unregister_event_queue(d->session, d->ortp_event);
1260}
1261
1262static void ice_uninit(MSFilter * f)
1263{
1264        IceData *d = (IceData *) f->data;
1265        if (d->ortp_event!=NULL)
1266          ortp_ev_queue_destroy(d->ortp_event);
1267        ms_free(f->data);
1268}
1269
1270static int ice_set_session(MSFilter * f, void *arg)
1271{
1272        IceData *d = (IceData *) f->data;
1273        RtpSession *s = (RtpSession *) arg;
1274        PayloadType *pt = rtp_profile_get_payload(rtp_session_get_profile(s),
1275                                                                                          rtp_session_get_recv_payload_type
1276                                                                                          (s));
1277        if (pt != NULL) {
1278                if (strcasecmp("g722", pt->mime_type)==0 )
1279                        d->rate=8000;
1280                else d->rate = pt->clock_rate;
1281        } else {
1282                ms_warning("Receiving undefined payload type ?");
1283        }
1284        d->session = s;
1285
1286        return 0;
1287}
1288
1289static int ice_set_sdpcandidates(MSFilter * f, void *arg)
1290{
1291        IceData *d = (IceData *) f->data;
1292        struct IceCheckList *scs = NULL;
1293
1294        if (d == NULL)
1295                return -1;
1296
1297        scs = (struct IceCheckList *) arg;
1298        d->check_lists = scs;
1299        ice_restart(d->check_lists);
1300        return 0;
1301}
1302
1303static void ice_preprocess(MSFilter * f){
1304        IceData *d = (IceData *) f->data;
1305        if (d->session!=NULL && d->ortp_event!=NULL)
1306                rtp_session_register_event_queue(d->session, d->ortp_event);
1307}
1308
1309static void ice_process(MSFilter * f)
1310{
1311        IceData *d = (IceData *) f->data;
1312
1313        if (d->session == NULL)
1314                return;
1315
1316        /* check received STUN request */
1317        if (d->ortp_event!=NULL)
1318        {
1319                OrtpEvent *evt = ortp_ev_queue_get(d->ortp_event);
1320
1321                while (evt != NULL) {
1322                        if (ortp_event_get_type(evt) ==
1323                                ORTP_EVENT_STUN_PACKET_RECEIVED) {
1324                                ice_process_stun_message(d->session, d->check_lists, evt);
1325                        }
1326                        if (ortp_event_get_type(evt) ==
1327                                ORTP_EVENT_TELEPHONE_EVENT) {
1328                        }
1329
1330                        ortp_event_destroy(evt);
1331                        evt = ortp_ev_queue_get(d->ortp_event);
1332                }
1333        }
1334
1335#if !defined(_WIN32_WCE)
1336        ice_sound_send_stun_request(d->session, d->check_lists, f->ticker->time);
1337#else
1338        ice_sound_send_stun_request(d->session, d->check_lists, f->ticker->time));
1339#endif
1340}
1341
1342static MSFilterMethod ice_methods[] = {
1343        {MS_ICE_SET_SESSION, ice_set_session},
1344        {MS_ICE_SET_CANDIDATEPAIRS, ice_set_sdpcandidates},
1345        {0, NULL}
1346};
1347
1348#ifdef _MSC_VER
1349
1350MSFilterDesc ms_ice_desc = {
1351        MS_ICE_ID,
1352        "MSIce",
1353        N_("ICE filter"),
1354        MS_FILTER_OTHER,
1355        NULL,
1356        0,
1357        0,
1358        ice_init,
1359        ice_preprocess,
1360        ice_process,
1361        ice_postprocess,
1362        ice_uninit,
1363        ice_methods
1364};
1365
1366#else
1367
1368MSFilterDesc ms_ice_desc = {
1369        .id = MS_ICE_ID,
1370        .name = "MSIce",
1371        .text = N_("ICE filter"),
1372        .category = MS_FILTER_OTHER,
1373        .ninputs = 0,
1374        .noutputs = 0,
1375        .init = ice_init,
1376        .preprocess = ice_preprocess,
1377        .process = ice_process,
1378        .postprocess=ice_postprocess,
1379        .uninit = ice_uninit,
1380        .methods = ice_methods
1381};
1382
1383#endif
1384
1385MS_FILTER_DESC_EXPORT(ms_ice_desc)
Note: See TracBrowser for help on using the repository browser.