source: mediastreamer2/linphone/mediastreamer2/src/ice.c @ 311:a3c7985aa266

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

create an ICE filter with no input/no output

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

File size: 43.9 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
32#include <math.h>
33
34static void 
35ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, 
36              const StunAtrString *username, const StunAtrString *password, 
37              UInt96 *tid)
38{       
39   StunMessage req;
40   char buf[STUN_MAX_MESSAGE_SIZE];
41   int len = STUN_MAX_MESSAGE_SIZE;
42   
43   memset(&req, 0, sizeof(StunMessage));
44
45   stunBuildReqSimple( &req, username, FALSE, FALSE, 1);
46   req.hasMessageIntegrity=TRUE;
47
48   /* 7.1.1.1
49   The attribute MUST be set equal to the priority that would be
50   assigned, based on the algorithm in Section 4.1.2, to a peer
51   reflexive candidate, should one be learned as a consequence of this
52   check */
53   req.hasPriority = TRUE;
54   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));
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() * (0x7fffffffffffffff/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
416static int
417_ice_get_localip_for (struct sockaddr_storage *saddr, size_t saddr_len, char *loc, int size)
418{
419        int err, tmp;
420        int sock;
421        struct sockaddr_storage addr;
422        socklen_t addr_len;
423
424        strcpy (loc, "127.0.0.1");    /* always fallback to local loopback */
425
426        sock = socket (saddr->ss_family, SOCK_DGRAM, 0);
427        tmp = 1;
428        err = setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, (const char *) &tmp, sizeof (int));
429        if (err < 0)
430        {
431                ms_error("ice.c: Error in setsockopt");
432                closesocket (sock);
433                return -1;
434        }
435        err = connect (sock, (struct sockaddr*)saddr, saddr_len);
436        if (err < 0)
437        {
438                ms_error("ice.c: Error in connect");
439                closesocket (sock);
440                return -1;
441        }
442        addr_len = sizeof (addr);
443        err = getsockname (sock, (struct sockaddr *) &addr, (socklen_t*)&addr_len);
444        if (err != 0)
445        {
446                ms_error("ice.c: Error in getsockname");
447                closesocket (sock);
448                return -1;
449        }
450
451        err = getnameinfo ((struct sockaddr *) &addr, addr_len, loc, size, NULL, 0, NI_NUMERICHOST);
452        if (err != 0)
453        {
454                ms_error("ice.c: Error in getnameinfo");
455                closesocket (sock);
456                return -1;
457        }
458        closesocket (sock);
459        /* ms_message("ice.c: Outgoing interface for sending STUN answer is %s", loc); */
460        return 0;
461}
462
463static void
464_ice_createErrorResponse(StunMessage *response, int cl, int number, const char* msg)
465{
466        response->msgHdr.msgType = (STUN_METHOD_BINDING | STUN_ERR_RESP);
467        response->hasErrorCode = TRUE;
468        response->errorCode.errorClass = cl;
469        response->errorCode.number = number;
470        strcpy(response->errorCode.reason, msg);
471        response->errorCode.sizeReason = strlen(msg);
472        response->hasFingerprint = TRUE;
473}
474
475static int ice_process_stun_message(RtpSession *session, struct IceCheckList *checklist, OrtpEvent *evt)
476{
477        struct CandidatePair *remote_candidates = NULL;
478        StunMessage msg;
479        bool_t res;
480        int highest_priority_success=-1;
481        OrtpEventData *evt_data = ortp_event_get_data(evt);
482        mblk_t *mp = evt_data->packet;
483        struct sockaddr_in *udp_remote;
484        char src6host[NI_MAXHOST];
485        int recvport = 0;
486        int i;
487
488        udp_remote = (struct sockaddr_in*)&evt_data->ep->addr;
489
490        memset( &msg, 0 , sizeof(msg) );
491        res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg);
492        if (!res)
493        {
494                ms_error("ice.c: Malformed STUN packet.");
495                return -1;
496        }
497
498        if (checklist==NULL)
499        {
500                ms_error("ice.c: dropping STUN packet: ice is not configured");
501                return -1;
502        }
503
504        remote_candidates = checklist->cand_pairs;
505        if (remote_candidates==NULL)
506        {
507                ms_error("ice.c: dropping STUN packet: ice is not configured");
508                return -1;
509        }
510
511        /* prepare ONCE tie-break value */
512        if (checklist->tiebreak_value==0) {
513                checklist->tiebreak_value = random() * (0x7fffffffffffffff/0x7fff);
514        }
515
516        memset (src6host, 0, sizeof (src6host));
517
518        {
519                struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr;
520                if (aaddr->ss_family==AF_INET)
521                        recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port);
522                else
523                        recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port);
524        }
525        i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen,
526                src6host, NI_MAXHOST,
527                NULL, 0, NI_NUMERICHOST);
528        if (i != 0)
529        {
530                ms_error("ice.c: Error with getnameinfo");
531                return -1;
532        }
533
534        if (STUN_IS_REQUEST(msg.msgHdr.msgType))
535                ms_message("ice.c: STUN_CONNECTIVITYCHECK: Request received from: %s:%i",
536                src6host, recvport);
537        else if (STUN_IS_INDICATION(msg.msgHdr.msgType))
538                ms_message("ice.c: SUN_INDICATION: Request Indication received from: %s:%i",
539                src6host, recvport);
540        else
541                ms_message("ice.c: STUN_ANSWER: Answer received from: %s:%i",
542                src6host, recvport);
543
544        {
545                int pos;
546                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
547                {
548                        struct CandidatePair *cand_pair = &remote_candidates[pos];
549
550                        if (cand_pair->connectivity_check == ICE_SUCCEEDED)
551                        {
552                                highest_priority_success=pos;
553                                break;
554                        }
555                }
556        }
557
558        if (STUN_IS_INDICATION(msg.msgHdr.msgType))
559        {
560                ms_message("ice.c: STUN INDICATION <- (?:?:? <- %s:%i:?)", src6host, recvport);
561                return 0;
562        }
563        else if (STUN_IS_REQUEST(msg.msgHdr.msgType))
564        {
565                StunMessage resp;
566                StunAtrString hmacPassword;
567                StunAddress4 remote_addr;
568                int rtp_socket;
569
570                memset( &resp, 0 , sizeof(resp));
571                remote_addr.addr = ntohl(udp_remote->sin_addr.s_addr);
572                remote_addr.port = ntohs(udp_remote->sin_port);
573
574                rtp_socket = rtp_session_get_rtp_socket(session);
575
576                resp.msgHdr.magic_cookie = ntohl(msg.msgHdr.magic_cookie);
577                for (i=0; i<12; i++ )
578                {
579                        resp.msgHdr.tr_id.octet[i] = msg.msgHdr.tr_id.octet[i];
580                }
581
582                /* check mandatory params */
583
584                if (!msg.hasUsername)
585                {
586                        char buf[STUN_MAX_MESSAGE_SIZE];
587                        int len = sizeof(buf);
588                        ms_error("ice.c: STUN REQ <- Missing USERNAME attribute in connectivity check");
589                        _ice_createErrorResponse(&resp, 4, 32, "Missing USERNAME attribute");
590                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
591                        if (len)
592                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
593                        return -1;
594                }
595                if (!msg.hasMessageIntegrity)
596                {
597                        char buf[STUN_MAX_MESSAGE_SIZE];
598                        int len = sizeof(buf);
599                        ms_error("ice.c: STUN REQ <- Missing MESSAGEINTEGRITY attribute in connectivity check");
600                        _ice_createErrorResponse(&resp, 4, 1, "Missing MESSAGEINTEGRITY attribute");
601                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
602                        if (len)
603                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
604                        return -1;
605                }
606
607                /*
608                The password associated with that transport address ID is used to verify
609                the MESSAGE-INTEGRITY attribute, if one was present in the request.
610                */
611                char hmac[20];
612                /* remove length of fingerprint if present */
613                if (msg.hasFingerprint==TRUE)
614                {
615                        char *lenpos = (char *)mp->b_rptr + sizeof(UInt16);
616                        UInt16 newlen = htons(msg.msgHdr.msgLength-8); /* remove fingerprint size */
617                        memcpy(lenpos, &newlen, sizeof(UInt16));
618                        stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24-8, checklist->loc_ice_pwd);
619                }
620                else
621                        stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24, checklist->loc_ice_pwd);
622                if (memcmp(msg.messageIntegrity.hash, hmac, 20)!=0)
623                {
624                        char buf[STUN_MAX_MESSAGE_SIZE];
625                        int len = sizeof(buf);
626                        ms_error("ice.c: STUN REQ <- Wrong MESSAGEINTEGRITY attribute in connectivity check");
627                        _ice_createErrorResponse(&resp, 4, 1, "Wrong MESSAGEINTEGRITY attribute");
628                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
629                        if (len)
630                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
631                        return -1;
632                }
633                if (msg.hasFingerprint==TRUE)
634                {
635                        char *lenpos = (char *)mp->b_rptr + sizeof(UInt16);
636                        UInt16 newlen = htons(msg.msgHdr.msgLength); /* add back fingerprint size */
637                        memcpy(lenpos, &newlen, sizeof(UInt16));
638                }
639
640
641                /* 7.2.1.1. Detecting and Repairing Role Conflicts */
642                /* TODO */
643                if (!msg.hasIceControlling && !msg.hasIceControlled)
644                {
645                        char buf[STUN_MAX_MESSAGE_SIZE];
646                        int len = sizeof(buf);
647                        ms_error("ice.c: STUN REQ <- Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
648                        _ice_createErrorResponse(&resp, 4, 87, "Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute");
649                        len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
650                        if (len)
651                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
652                        return -1;
653                }
654
655                if (checklist->rem_controlling==0 && msg.hasIceControlling) {
656                        /* If the agent's tie-breaker is larger than or equal
657                        to the contents of the ICE-CONTROLLING attribute
658                        -> send 487, and do not change ROLE */
659                        if (checklist->tiebreak_value >= msg.iceControlling.value) {
660                                char buf[STUN_MAX_MESSAGE_SIZE];
661                                int len = sizeof(buf);
662                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
663                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
664                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
665                                if (len)
666                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
667                                return -1;
668                        }
669                        else {
670                                int pos;
671                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
672                                {
673                                        /* controller agent */
674                                        int G = remote_candidates[pos].remote_candidate.priority;
675                                        /* controlled agent */ 
676                                        int D = remote_candidates[pos].local_candidate.priority;
677                                        remote_candidates[pos].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
678
679                                }
680                                checklist->rem_controlling = 1;
681                                /* reset all to initial WAITING state? */
682                                ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
683                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
684                                {
685                                        if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
686                                                continue;
687                                        remote_candidates[pos].connectivity_check = ICE_WAITING;
688                                        memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
689                                        remote_candidates[pos].retransmission_time = 0;
690                                        remote_candidates[pos].retransmission_number = 0;
691                                }
692                        }
693                }
694
695                if (checklist->rem_controlling==1 && msg.hasIceControlled) {
696
697                        /* If the agent's tie-breaker is larger than or equal
698                        to the contents of the ICE-CONTROLLED attribute
699                        -> change ROLE */
700                        if (checklist->tiebreak_value >= msg.iceControlled.value) {
701                                int pos;
702                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
703                                {
704                                        /* controller agent */
705                                        int G = remote_candidates[pos].local_candidate.priority;
706                                        /* controlled agent */ 
707                                        int D = remote_candidates[pos].remote_candidate.priority;
708                                        remote_candidates[pos].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
709
710                                }
711                                checklist->rem_controlling = 0;
712                                /* reset all to initial WAITING state? */
713                                ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state");
714                                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
715                                {
716                                        if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
717                                                continue;
718                                        remote_candidates[pos].connectivity_check = ICE_WAITING;
719                                        memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
720                                        remote_candidates[pos].retransmission_time = 0;
721                                        remote_candidates[pos].retransmission_number = 0;
722                                }
723                        }
724                        else {
725                                char buf[STUN_MAX_MESSAGE_SIZE];
726                                int len = sizeof(buf);
727                                ms_error("ice.c: STUN REQ <- 487 Role Conflict");
728                                _ice_createErrorResponse(&resp, 4, 87, "Role Conflict");
729                                len = stunEncodeMessage(&resp, buf, len, &hmacPassword );
730                                if (len)
731                                        sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
732                                return -1;
733                        }
734                }
735
736                struct CandidatePair *cand_pair;
737                int pos;
738                cand_pair=NULL;
739                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
740                {
741                        cand_pair = &remote_candidates[pos]; 
742                        /* connectivity check is coming from a known remote candidate?
743                        we should also check the port...
744                        */
745                        if (strcmp(cand_pair->remote_candidate.conn_addr, src6host)==0
746                                && cand_pair->remote_candidate.conn_port==recvport)
747                        {
748                                ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) from known peer",
749                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
750                                        pos,
751                                        cand_pair->local_candidate.conn_addr,
752                                        cand_pair->local_candidate.conn_port,
753                                        cand_pair->local_candidate.cand_type,
754                                        cand_pair->remote_candidate.conn_addr,
755                                        cand_pair->remote_candidate.conn_port,
756                                        cand_pair->remote_candidate.cand_type);
757                                if (cand_pair->connectivity_check==ICE_FROZEN
758                                        || cand_pair->connectivity_check==ICE_IN_PROGRESS
759                                        || cand_pair->connectivity_check==ICE_FAILED)
760                                {
761                                        cand_pair->connectivity_check = ICE_WAITING;
762                                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
763                                                cand_pair->nominated_pair = 1;
764                                }
765                                else if (cand_pair->connectivity_check==ICE_SUCCEEDED)
766                                {
767                                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
768                                        {
769                                                cand_pair->nominated_pair = 1;
770
771                                                /* USE-CANDIDATE is in STUN request and we already succeeded on that link */
772                                                ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
773                                                        pos,
774                                                        cand_pair->local_candidate.conn_addr,
775                                                        cand_pair->local_candidate.conn_port,
776                                                        cand_pair->local_candidate.cand_type,
777                                                        cand_pair->remote_candidate.conn_addr,
778                                                        cand_pair->remote_candidate.conn_port,
779                                                        cand_pair->remote_candidate.cand_type,
780                                                        cand_pair->nominated_pair==0?"FALSE":"TRUE");
781                                                memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
782                                                session->rtp.rem_addrlen=evt_data->ep->addrlen;
783                                        }
784                                }
785                                break;
786                        }
787                        cand_pair=NULL;
788                }
789                if (cand_pair==NULL)
790                {
791                        struct CandidatePair new_pair;
792                        memset(&new_pair, 0, sizeof(struct CandidatePair));
793
794                        ms_message("ice.c: STUN REQ <- connectivity check received from an unknow candidate (%s:%i)", src6host, recvport);
795                        /* TODO: add the peer-reflexive candidate */
796
797                        memcpy(&new_pair.local_candidate, &remote_candidates[0].local_candidate, sizeof(new_pair.local_candidate));
798
799                        new_pair.remote_candidate.foundation = 6;
800                        new_pair.remote_candidate.component_id = remote_candidates[0].remote_candidate.component_id;
801
802                        /* -> no known base address for peer */
803
804                        new_pair.remote_candidate.conn_port = recvport;
805                        snprintf(new_pair.remote_candidate.conn_addr, sizeof(new_pair.remote_candidate.conn_addr),
806                                "%s", src6host);
807
808                        /* take it from PRIORITY STUN attr */
809                        new_pair.remote_candidate.priority = msg.priority.priority;
810                        if (new_pair.remote_candidate.priority==0)
811                                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));
812
813                        snprintf(new_pair.remote_candidate.cand_type, sizeof(cand_pair->remote_candidate.cand_type),
814                                "prflx");
815                        snprintf (new_pair.remote_candidate.transport,
816                                                        sizeof (new_pair.remote_candidate.transport),
817                                                        "UDP");
818
819                        if (checklist->rem_controlling==0)
820                        {
821                                int G = new_pair.local_candidate.priority;
822                                /* controlled agent */ 
823                                int D = new_pair.remote_candidate.priority;
824                                new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
825                        }
826                        else
827                        {
828                                int G = new_pair.remote_candidate.priority;
829                                /* controlled agent */ 
830                                int D = new_pair.local_candidate.priority;
831                                new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
832                        }
833                        new_pair.connectivity_check = ICE_WAITING;
834                        /* insert new pair candidate */
835                        if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0)
836                        {
837                                new_pair.nominated_pair = 1;
838                        }
839
840                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
841                        {
842                                if (pos==9)
843                                {
844                                        ms_message("ice.c: STUN REQ (%s) <- X (%s:%i:%s <- %s:%i:%s) no room for new remote reflexive candidate",
845                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
846                                                new_pair.local_candidate.conn_addr,
847                                                new_pair.local_candidate.conn_port,
848                                                new_pair.local_candidate.cand_type,
849                                                new_pair.remote_candidate.conn_addr,
850                                                new_pair.remote_candidate.conn_port,
851                                                new_pair.remote_candidate.cand_type);
852                                        break;
853                                }
854                                if (new_pair.pair_priority > remote_candidates[pos].pair_priority)
855                                {
856                                        /* move upper data */
857                                        memmove(&remote_candidates[pos+1], &remote_candidates[pos], sizeof(struct CandidatePair)*(10-pos-1));
858                                        memcpy(&remote_candidates[pos], &new_pair, sizeof(struct CandidatePair));
859
860                                        if (checklist->nominated_pair_index>=pos)
861                                                checklist->nominated_pair_index++;
862                                        ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) new learned remote reflexive candidate",
863                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
864                                                pos,
865                                                new_pair.local_candidate.conn_addr,
866                                                new_pair.local_candidate.conn_port,
867                                                new_pair.local_candidate.cand_type,
868                                                new_pair.remote_candidate.conn_addr,
869                                                new_pair.remote_candidate.conn_port,
870                                                new_pair.remote_candidate.cand_type);
871                                        break;
872                                }
873                        }
874                }
875
876                UInt32 cookie = 0x2112A442;
877                resp.hasXorMappedAddress = TRUE;
878                resp.xorMappedAddress.ipv4.port = remote_addr.port^(cookie>>16);
879                resp.xorMappedAddress.ipv4.addr = remote_addr.addr^cookie;
880
881
882                resp.msgHdr.msgType = (STUN_METHOD_BINDING | STUN_SUCCESS_RESP);
883
884                resp.hasUsername = TRUE;
885                memcpy(resp.username.value, msg.username.value, msg.username.sizeValue );
886                resp.username.sizeValue = msg.username.sizeValue;
887
888                /* ? any messageintegrity in response? */
889                resp.hasMessageIntegrity = TRUE;
890
891                const char serverName[] = "mediastreamer2 " STUN_VERSION;
892                resp.hasSoftware = TRUE;
893                memcpy( resp.softwareName.value, serverName, sizeof(serverName));
894                resp.softwareName.sizeValue = sizeof(serverName);
895
896                resp.hasFingerprint = TRUE;
897
898                {
899                        char buf[STUN_MAX_MESSAGE_SIZE];
900                        int len = sizeof(buf);
901                        len = stunEncodeMessage( &resp, buf, len, &hmacPassword );
902                        if (len)
903                                sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port);
904                }
905        }
906        else if (STUN_IS_SUCCESS_RESP(msg.msgHdr.msgType))
907        {
908                /* set state to RECV-VALID or VALID */
909                StunMessage resp;
910                StunAddress4 mappedAddr;
911                memset(&resp, 0, sizeof(StunMessage));
912                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
913                        &resp );
914                if (!res)
915                {
916                        ms_error("ice.c: STUN RESP <- Bad format for STUN answer.");
917                        return -1;
918                }
919
920                if (resp.hasXorMappedAddress!=TRUE)
921                {
922                        ms_error("ice.c: STUN RESP <- Missing XOR-MAPPED-ADDRESS in STUN answer.");               
923                        return -1;
924                }
925
926                UInt32 cookie = 0x2112A442;
927                UInt16 cookie16 = 0x2112A442 >> 16;
928                mappedAddr.port = resp.xorMappedAddress.ipv4.port^cookie16;
929                mappedAddr.addr = resp.xorMappedAddress.ipv4.addr^cookie;
930
931                struct in_addr inaddr;
932                char mapped_addr[64];
933                inaddr.s_addr = htonl (mappedAddr.addr);
934                snprintf(mapped_addr, sizeof(mapped_addr),
935                        "%s", inet_ntoa (inaddr));
936
937                struct CandidatePair *cand_pair;
938                int pos;
939                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
940                {
941                        cand_pair = &remote_candidates[pos];
942
943                        if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
944                        {
945                                break;
946                        }
947                        cand_pair = NULL;
948                }
949
950                if (cand_pair==NULL)
951                {
952                        ms_message("ice.c: STUN RESP (%s) <- no transaction for STUN answer?",
953                                msg.hasUseCandidate==0?"":"USE-CANDIDATE");
954                }
955                else if (strcmp(src6host, cand_pair->remote_candidate.conn_addr)!=0
956                        || recvport!=cand_pair->remote_candidate.conn_port)
957                {
958                        /* 7.1.2.2.  Success Cases
959                        -> must be a security issue: refuse non-symmetric answer */
960                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s) refused because non-symmetric",
961                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
962                                pos,
963                                cand_pair->local_candidate.conn_addr,
964                                cand_pair->local_candidate.conn_port,
965                                cand_pair->local_candidate.cand_type,
966                                cand_pair->remote_candidate.conn_addr,
967                                cand_pair->remote_candidate.conn_port,
968                                cand_pair->remote_candidate.cand_type,
969                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
970                        cand_pair->connectivity_check = ICE_FAILED;
971                }
972                else
973                {
974                        /* Youhouhouhou */
975                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
976                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
977                                pos,
978                                cand_pair->local_candidate.conn_addr,
979                                cand_pair->local_candidate.conn_port,
980                                cand_pair->local_candidate.cand_type,
981                                cand_pair->remote_candidate.conn_addr,
982                                cand_pair->remote_candidate.conn_port,
983                                cand_pair->remote_candidate.cand_type,
984                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
985                        if (cand_pair->connectivity_check != ICE_SUCCEEDED)
986                        {
987                                if (checklist->rem_controlling==1 && cand_pair->nominated_pair>0)
988                                {
989                                        /* USE-CANDIDATE was in previous STUN request sent */
990                                        ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
991                                                pos,
992                                                cand_pair->local_candidate.conn_addr,
993                                                cand_pair->local_candidate.conn_port,
994                                                cand_pair->local_candidate.cand_type,
995                                                cand_pair->remote_candidate.conn_addr,
996                                                cand_pair->remote_candidate.conn_port,
997                                                cand_pair->remote_candidate.cand_type,
998                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
999                                        memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1000                                        session->rtp.rem_addrlen=evt_data->ep->addrlen;
1001                                }
1002
1003                                if (cand_pair->nominated_pair>0 && checklist->rem_controlling==0)
1004                                {
1005                                        /* USE-CANDIDATE is in STUN request and we already succeeded on that link */
1006                                        ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)",
1007                                                pos,
1008                                                cand_pair->local_candidate.conn_addr,
1009                                                cand_pair->local_candidate.conn_port,
1010                                                cand_pair->local_candidate.cand_type,
1011                                                cand_pair->remote_candidate.conn_addr,
1012                                                cand_pair->remote_candidate.conn_port,
1013                                                cand_pair->remote_candidate.cand_type,
1014                                                cand_pair->nominated_pair==0?"FALSE":"TRUE");
1015                                        memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen);
1016                                        session->rtp.rem_addrlen=evt_data->ep->addrlen;
1017                                }
1018
1019                                cand_pair->connectivity_check = ICE_FAILED;
1020                                if (mappedAddr.port == cand_pair->local_candidate.conn_port
1021                                        && strcmp(mapped_addr, cand_pair->local_candidate.conn_addr)==0)
1022                                {
1023                                        /* no peer-reflexive candidate was discovered */
1024                                        cand_pair->connectivity_check = ICE_SUCCEEDED;
1025                                }
1026                                else
1027                                {
1028                                        int pos2;
1029                                        for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1030                                        {
1031                                                if (mappedAddr.port == remote_candidates[pos2].local_candidate.conn_port
1032                                                        && strcmp(mapped_addr, remote_candidates[pos2].local_candidate.conn_addr)==0
1033                                                        && cand_pair->remote_candidate.conn_port == remote_candidates[pos2].remote_candidate.conn_port
1034                                                        && strcmp(cand_pair->remote_candidate.conn_addr, remote_candidates[pos2].remote_candidate.conn_addr)==0)
1035                                                {
1036                                                        if (remote_candidates[pos2].connectivity_check==ICE_PRUNED
1037                                                                ||remote_candidates[pos2].connectivity_check==ICE_FROZEN
1038                                                                ||remote_candidates[pos2].connectivity_check==ICE_FAILED
1039                                                                || remote_candidates[pos2].connectivity_check==ICE_IN_PROGRESS)
1040                                                                remote_candidates[pos2].connectivity_check = ICE_WAITING; /* trigger check */
1041                                                        /*
1042                                                        ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) found candidate pair matching XOR-MAPPED-ADDRESS",
1043                                                                msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1044                                                                pos,
1045                                                                cand_pair->local_candidate.conn_addr,
1046                                                                cand_pair->local_candidate.conn_port,
1047                                                                cand_pair->local_candidate.cand_type,
1048                                                                cand_pair->remote_candidate.conn_addr,
1049                                                                cand_pair->remote_candidate.conn_port,
1050                                                                cand_pair->remote_candidate.cand_type);
1051                                                                */
1052                                                        break;
1053                                                }
1054                                        }
1055                                        if (pos2==10 || remote_candidates[pos2].remote_candidate.conn_addr[0]=='\0')
1056                                        {
1057                                                struct CandidatePair new_pair;
1058                                                memset(&new_pair, 0, sizeof(struct CandidatePair));
1059
1060                                                /* 7.1.2.2.1.  Discovering Peer Reflexive Candidates */
1061                                                /* If IP & port were different than mappedAddr, there was A NAT
1062                                                between me and remote destination. */
1063                                                memcpy(&new_pair.remote_candidate, &cand_pair->remote_candidate, sizeof(new_pair.remote_candidate));
1064
1065                                                new_pair.local_candidate.foundation = 6;
1066                                                new_pair.local_candidate.component_id = cand_pair->local_candidate.component_id;
1067
1068                                                /* what is my base address? */
1069                                                new_pair.local_candidate.rel_port = cand_pair->local_candidate.conn_port;
1070                                                snprintf(new_pair.local_candidate.rel_addr, sizeof(new_pair.local_candidate.rel_addr),
1071                                                        "%s", cand_pair->local_candidate.conn_addr);
1072
1073                                                new_pair.local_candidate.conn_port = mappedAddr.port;
1074                                                snprintf(new_pair.local_candidate.conn_addr, sizeof(new_pair.local_candidate.conn_addr),
1075                                                        "%s", mapped_addr);
1076
1077                                                /* take it from PRIORITY STUN attr */
1078                                                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));
1079
1080                                                snprintf(new_pair.local_candidate.cand_type, sizeof(cand_pair->local_candidate.cand_type),
1081                                                        "prflx");
1082                                                snprintf (new_pair.local_candidate.transport,
1083                                                                                sizeof (new_pair.local_candidate.transport),
1084                                                                                "UDP");
1085
1086                                                if (checklist->rem_controlling==0)
1087                                                {
1088                                                        int G = new_pair.local_candidate.priority;
1089                                                        /* controlled agent */ 
1090                                                        int D = new_pair.remote_candidate.priority;
1091                                                        new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1092                                                }
1093                                                else
1094                                                {
1095                                                        int G = new_pair.remote_candidate.priority;
1096                                                        /* controlled agent */ 
1097                                                        int D = new_pair.local_candidate.priority;
1098                                                        new_pair.pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1099                                                }
1100                                                new_pair.connectivity_check = ICE_WAITING;
1101                                                /* insert new pair candidate */
1102                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1103                                                {
1104                                                        if (pos2==9)
1105                                                        {
1106                                                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) no room for new local peer-reflexive candidate",
1107                                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1108                                                                        pos2,
1109                                                                        new_pair.local_candidate.conn_addr,
1110                                                                        new_pair.local_candidate.conn_port,
1111                                                                        new_pair.local_candidate.cand_type,
1112                                                                        new_pair.remote_candidate.conn_addr,
1113                                                                        new_pair.remote_candidate.conn_port,
1114                                                                        new_pair.remote_candidate.cand_type);
1115                                                                break;
1116                                                        }
1117                                                        if (new_pair.pair_priority > remote_candidates[pos2].pair_priority)
1118                                                        {
1119                                                                /* move upper data */
1120                                                                memmove(&remote_candidates[pos2+1], &remote_candidates[pos2], sizeof(struct CandidatePair)*(10-pos2-1));
1121                                                                memcpy(&remote_candidates[pos2], &new_pair, sizeof(struct CandidatePair));
1122
1123                                                                if (checklist->nominated_pair_index>=pos2)
1124                                                                        checklist->nominated_pair_index++;
1125                                                                ms_message("ice.c: STUN RESP (%s) <- %i (%s:%i:%s <- %s:%i:%s) new discovered local peer-reflexive candidate",
1126                                                                        msg.hasUseCandidate==0?"":"USE-CANDIDATE",
1127                                                                        pos2,
1128                                                                        new_pair.local_candidate.conn_addr,
1129                                                                        new_pair.local_candidate.conn_port,
1130                                                                        new_pair.local_candidate.cand_type,
1131                                                                        new_pair.remote_candidate.conn_addr,
1132                                                                        new_pair.remote_candidate.conn_port,
1133                                                                        new_pair.remote_candidate.cand_type);
1134                                                                break;
1135                                                        }
1136                                                }
1137                                        }
1138                                }
1139                        }
1140                }
1141        }
1142        else if (STUN_IS_ERR_RESP(msg.msgHdr.msgType))
1143        {
1144                StunMessage resp;
1145                memset(&resp, 0, sizeof(StunMessage));
1146                res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr,
1147                        &resp );
1148                if (!res)
1149                {
1150                        ms_error("ice.c: ERROR_RESPONSE: Bad format for STUN answer.");
1151                        return -1;
1152                }
1153
1154                int pos;
1155                for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1156                {
1157                        struct CandidatePair *cand_pair = &remote_candidates[pos];
1158
1159                        if (memcmp(&(cand_pair->tid), &(resp.msgHdr.tr_id), sizeof(resp.msgHdr.tr_id))==0)
1160                        {
1161                                cand_pair->connectivity_check = ICE_FAILED;
1162                                ms_message("ice.c: ERROR_RESPONSE: ICE_FAILED for candidate pair! %s:%i -> %s:%i",
1163                                        cand_pair->local_candidate.conn_addr,
1164                                        cand_pair->local_candidate.conn_port,
1165                                        cand_pair->remote_candidate.conn_addr,
1166                                        cand_pair->remote_candidate.conn_port);
1167                                if (resp.hasErrorCode==TRUE && resp.errorCode.errorClass==4 && resp.errorCode.number==87)
1168                                {
1169                                        if (remote_candidates[pos].rem_controlling==1)
1170                                        {
1171                                                int pos2;
1172                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1173                                                {
1174                                                        /* controller agent */
1175                                                        int G = remote_candidates[pos2].local_candidate.priority;
1176                                                        /* controlled agent */ 
1177                                                        int D = remote_candidates[pos2].remote_candidate.priority;
1178                                                        remote_candidates[pos2].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1179                                                }
1180                                                checklist->rem_controlling=0;
1181                                        }
1182                                        else
1183                                        {
1184                                                int pos2;
1185                                                for (pos2=0;pos2<10 && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++)
1186                                                {
1187                                                        /* controller agent */
1188                                                        int G = remote_candidates[pos2].remote_candidate.priority;
1189                                                        /* controlled agent */ 
1190                                                        int D = remote_candidates[pos2].local_candidate.priority;
1191                                                        remote_candidates[pos2].pair_priority = (UInt64)pow((double)2,(double)32)*MIN(G,D) + 2*MAX(G,D) + (G>D?1:0);
1192                                                }
1193                                                checklist->rem_controlling=1;
1194                                        }
1195                                        /* reset all to initial WAITING state? */
1196                                        ms_message("ice.c: ERROR_RESPONSE: 487 -> reset all to ICE_WAITING state");
1197                                        for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++)
1198                                        {
1199                                                if (remote_candidates[pos].connectivity_check == ICE_PRUNED)
1200                                                        continue;
1201                                                remote_candidates[pos].connectivity_check = ICE_WAITING;
1202                                                memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid));
1203                                                remote_candidates[pos].retransmission_time = 0;
1204                                                remote_candidates[pos].retransmission_number = 0;
1205                                        }
1206                                }
1207                        }
1208                }
1209        }
1210
1211        return 0;
1212}
1213
1214
1215
1216
1217struct IceData {
1218        RtpSession *session;
1219        OrtpEvQueue *ortp_event;
1220        struct IceCheckList *check_lists;       /* table of 10 cpair */
1221        int rate;
1222};
1223
1224typedef struct IceData IceData;
1225
1226static void ice_init(MSFilter * f)
1227{
1228        IceData *d = (IceData *)ms_new(IceData, 1);
1229
1230        d->ortp_event = ortp_ev_queue_new();
1231        d->session = NULL;
1232        d->check_lists = NULL;
1233        d->rate = 8000;
1234        f->data = d;
1235}
1236
1237static void ice_postprocess(MSFilter * f)
1238{
1239        IceData *d = (IceData *) f->data;
1240        if (d->session!=NULL && d->ortp_event!=NULL)
1241          rtp_session_unregister_event_queue(d->session, d->ortp_event);
1242}
1243
1244static void ice_uninit(MSFilter * f)
1245{
1246        IceData *d = (IceData *) f->data;
1247        if (d->ortp_event!=NULL)
1248          ortp_ev_queue_destroy(d->ortp_event);
1249        ms_free(f->data);
1250}
1251
1252static int ice_set_session(MSFilter * f, void *arg)
1253{
1254        IceData *d = (IceData *) f->data;
1255        RtpSession *s = (RtpSession *) arg;
1256        PayloadType *pt = rtp_profile_get_payload(rtp_session_get_profile(s),
1257                                                                                          rtp_session_get_recv_payload_type
1258                                                                                          (s));
1259        if (pt != NULL) {
1260                if (strcasecmp("g722", pt->mime_type)==0 )
1261                        d->rate=8000;
1262                else d->rate = pt->clock_rate;
1263        } else {
1264                ms_warning("Receiving undefined payload type ?");
1265        }
1266        d->session = s;
1267
1268        return 0;
1269}
1270
1271static int ice_set_sdpcandidates(MSFilter * f, void *arg)
1272{
1273        IceData *d = (IceData *) f->data;
1274        struct IceCheckList *scs = NULL;
1275
1276        if (d == NULL)
1277                return -1;
1278
1279        scs = (struct IceCheckList *) arg;
1280        d->check_lists = scs;
1281        ice_restart(d->check_lists);
1282        return 0;
1283}
1284
1285static void ice_preprocess(MSFilter * f){
1286        IceData *d = (IceData *) f->data;
1287        if (d->session!=NULL && d->ortp_event!=NULL)
1288                rtp_session_register_event_queue(d->session, d->ortp_event);
1289}
1290
1291static void ice_process(MSFilter * f)
1292{
1293        IceData *d = (IceData *) f->data;
1294
1295        if (d->session == NULL)
1296                return;
1297
1298        /* check received STUN request */
1299        if (d->ortp_event!=NULL)
1300        {
1301                OrtpEvent *evt = ortp_ev_queue_get(d->ortp_event);
1302
1303                while (evt != NULL) {
1304                        if (ortp_event_get_type(evt) ==
1305                                ORTP_EVENT_STUN_PACKET_RECEIVED) {
1306                                ice_process_stun_message(d->session, d->check_lists, evt);
1307                        }
1308                        if (ortp_event_get_type(evt) ==
1309                                ORTP_EVENT_TELEPHONE_EVENT) {
1310                        }
1311
1312                        ortp_event_destroy(evt);
1313                        evt = ortp_ev_queue_get(d->ortp_event);
1314                }
1315        }
1316
1317#if !defined(_WIN32_WCE)
1318        ice_sound_send_stun_request(d->session, d->check_lists, f->ticker->time);
1319#else
1320        ice_sound_send_stun_request(d->session, d->check_lists, f->ticker->time));
1321#endif
1322}
1323
1324static MSFilterMethod ice_methods[] = {
1325        {MS_ICE_SET_SESSION, ice_set_session},
1326        {MS_ICE_SET_CANDIDATEPAIRS, ice_set_sdpcandidates},
1327        {0, NULL}
1328};
1329
1330#ifdef _MSC_VER
1331
1332MSFilterDesc ms_ice_desc = {
1333        MS_ICE_ID,
1334        "MSIce",
1335        N_("ICE filter"),
1336        MS_FILTER_OTHER,
1337        NULL,
1338        0,
1339        0,
1340        ice_init,
1341        ice_preprocess,
1342        ice_process,
1343        ice_postprocess,
1344        ice_uninit,
1345        ice_methods
1346};
1347
1348#else
1349
1350MSFilterDesc ms_ice_desc = {
1351        .id = MS_ICE_ID,
1352        .name = "MSIce",
1353        .text = N_("ICE filter"),
1354        .category = MS_FILTER_OTHER,
1355        .ninputs = 0,
1356        .noutputs = 0,
1357        .init = ice_init,
1358        .preprocess = ice_preprocess,
1359        .process = ice_process,
1360        .postprocess=ice_postprocess,
1361        .uninit = ice_uninit,
1362        .methods = ice_methods
1363};
1364
1365#endif
1366
1367MS_FILTER_DESC_EXPORT(ms_ice_desc)
Note: See TracBrowser for help on using the repository browser.