void t_media_stun_trans::retransmit(void) { // Retransmit the STUN request StunAtrString stun_pass; stun_pass.sizeValue = 0; char m[STUN_MAX_MESSAGE_SIZE]; int msg_size = stunEncodeMessage(*request, m, STUN_MAX_MESSAGE_SIZE, stun_pass, false); try { sock->sendto(destinations.front().ipaddr, destinations.front().port, m, msg_size); } catch (int err) { string msg("Failed to send STUN request for media.\n"); msg += get_error_str(err); log_file->write_report(msg, "::t_media_stun_trans::retransmit", LOG_NORMAL, LOG_CRITICAL); StunMessage *resp; resp = stunBuildError(*request, 500, "Could not send request"); evq_trans_layer->push_stun_response(resp, tuid, id); MEMMAN_DELETE(resp); delete resp; return; } num_transmissions++; }
static void ice_sendtest( Socket myFd, StunAddress4 *dest, const StunAtrString *username, const StunAtrString *password, int testNum, bool verbose , UInt128 *tid) { bool changePort=false; bool changeIP=false; bool discard=false; StunMessage req; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; switch (testNum) { case 1: case 10: case 11: break; case 2: /* changePort=true; */ changeIP=true; break; case 3: changePort=true; break; case 4: changeIP=true; break; case 5: discard=true; break; default: printf("Test %i is unkown\n", testNum); return ; /* error */ } memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, username, changePort , changeIP , testNum ); len = stunEncodeMessage( &req, buf, len, password,verbose ); memcpy(tid , &(req.msgHdr.id), sizeof(req.msgHdr.id)); sendMessage( myFd, buf, len, dest->addr, dest->port, verbose ); }
static void ice_sendtest( struct IceCheckList *checklist, struct CandidatePair *remote_candidate, Socket myFd, StunAddress4 *dest, const StunAtrString *username, const StunAtrString *password, UInt96 *tid) { StunMessage req; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, username, FALSE, FALSE, 1); req.hasMessageIntegrity=TRUE; /* 7.1.1.1 The attribute MUST be set equal to the priority that would be assigned, based on the algorithm in Section 4.1.2, to a peer reflexive candidate, should one be learned as a consequence of this check */ req.hasPriority = TRUE; req.priority.priority = (110 << 24) | (255 << 16) | (255 << 8) | (256 - remote_candidate->remote_candidate.component_id); /* TODO: put this parameter only for the candidate selected */ if (remote_candidate->nominated_pair==1) req.hasUseCandidate = TRUE; if (remote_candidate->rem_controlling==1) { req.hasIceControlled = TRUE; req.iceControlled.value = checklist->tiebreak_value; } else { req.hasIceControlling = TRUE; req.iceControlling.value = checklist->tiebreak_value; } /* TODO: not yet implemented? */ req.hasFingerprint = TRUE; len = stunEncodeMessage( &req, buf, len, password ); memcpy(tid , &(req.msgHdr.tr_id), sizeof(req.msgHdr.tr_id)); sendMessage( myFd, buf, len, dest->addr, dest->port ); }
/* Send dummy STUN packet to open NAT ports ASAP. */ static void send_stun_packet(RtpSession *s) { StunMessage msg; mblk_t *mp; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; memset(&msg, 0, sizeof(StunMessage)); stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1); len = stunEncodeMessage(&msg, buf, len, NULL); if (len > 0) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; rtp_session_sendm_with_ts(s, mp, 0); } }
static void send_stun(t_event *event) { t_event_stun_request *e; e = (t_event_stun_request *)event; assert(e->dst_addr != 0); assert(e->dst_port != 0); log_file->write_header("::send_stun", LOG_STUN); log_file->write_raw("Send to: "); log_file->write_raw(h_ip2str(e->dst_addr)); log_file->write_raw(":"); log_file->write_raw(e->dst_port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(*e->get_msg())); log_file->write_footer(); StunAtrString stun_pass; stun_pass.sizeValue = 0; char m[STUN_MAX_MESSAGE_SIZE]; int msg_size = stunEncodeMessage(*e->get_msg(), m, STUN_MAX_MESSAGE_SIZE, stun_pass, false); bool msg_sent = false; int transmit_count = 0; while (!msg_sent && transmit_count++ <= MAX_TRANSMIT_RETRIES) { try { sip_socket->sendto(e->dst_addr, e->dst_port, m, msg_size); num_non_icmp_errors = 0; msg_sent = true; } catch (int err) { if (!handle_socket_err(err, e->dst_addr, e->dst_port)) { // Discard packet. msg_sent = true; } else { if (transmit_count <= MAX_TRANSMIT_RETRIES) { // Sleep 100 ms struct timespec sleeptimer; sleeptimer.tv_sec = 0; sleeptimer.tv_nsec = 100000000; nanosleep(&sleeptimer, NULL); } } } } }
static int test_stun_encode( char*buffer, size_t len, bool_t expect_fail ) { StunAtrString username; StunAtrString password; StunMessage req; memset(&req, 0, sizeof(StunMessage)); memset(&username,0,sizeof(username)); memset(&password,0,sizeof(password)); stunBuildReqSimple( &req, &username, TRUE , TRUE , 11); len = stunEncodeMessage( &req, buffer, (unsigned int)len, &password); if (len<=0){ if( expect_fail ) ms_message("Fail to encode stun message (EXPECTED).\n"); else ms_error("Fail to encode stun message.\n"); return -1; } return (int)len; }
/* sends a request to a stun server */ int send_stun_request(const int udpSocket,struct sockaddr_in *stunServ) { assert( sizeof(UInt8 ) == 1 ); assert( sizeof(UInt16) == 2 ); assert( sizeof(UInt32) == 4 ); bool verbose = STUN_VERBOSE; //set the verbose mode verbose = true; StunMessage req; memset(&req, 0, sizeof(StunMessage)); StunAtrString username; StunAtrString password; username.sizeValue = 0; password.sizeValue = 0; /* build a stun request message */ /* creates a stun message struct with the given atributes */ stunBuildReqSimple( &req, username, false , false , 0x0c ); /* buffer for the stun request */ char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; /* encode the stun message */ len = stunEncodeMessage( req, buf, len, password, verbose); struct iovec iov; iov.iov_len = len; iov.iov_base = buf; debug("Sending STUN with sendPacketFinal %d, %d!!!!!\n",len, udpSocket); sendPacketFinal(udpSocket,&iov,1,stunServ); return 0; }
/* Send dummy STUN packet to open NAT ports ASAP. */ static void send_stun_packet(RtpSession *s) { StunMessage msg; mblk_t *mp; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; if (ms_is_multicast_addr((const struct sockaddr *)&s->rtcp.gs.loc_addr)) { ms_debug("Stun packet not sent for session [%p] because of multicast",s); return; } memset(&msg, 0, sizeof(StunMessage)); stunBuildReqSimple(&msg, NULL, FALSE, FALSE, 1); len = stunEncodeMessage(&msg, buf, len, NULL); if (len > 0) { mp = allocb(len, BPRI_MED); memcpy(mp->b_wptr, buf, len); mp->b_wptr += len; ms_message("Stun packet sent for session [%p]",s); rtp_session_sendm_with_ts(s, mp, 0); } }
static int sendStunRequest(int sock, const struct sockaddr *server, socklen_t addrlen, int id, bool_t changeAddr){ char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; StunAtrString username; StunAtrString password; StunMessage req; int err; memset(&req, 0, sizeof(StunMessage)); memset(&username,0,sizeof(username)); memset(&password,0,sizeof(password)); stunBuildReqSimple( &req, &username, changeAddr , changeAddr , id); len = stunEncodeMessage( &req, buf, len, &password); if (len<=0){ ms_error("Fail to encode stun message."); return -1; } err=sendto(sock,buf,len,0,server,addrlen); if (err<0){ ms_error("sendto failed: %s",strerror(errno)); return -1; } return 0; }
static int ice_process_stun_message(RtpSession *session, struct IceCheckList *checklist, OrtpEvent *evt) { struct CandidatePair *remote_candidates = NULL; StunMessage msg; bool_t res; int highest_priority_success=-1; OrtpEventData *evt_data = ortp_event_get_data(evt); mblk_t *mp = evt_data->packet; struct sockaddr_in *udp_remote; char src6host[NI_MAXHOST]; int recvport = 0; int i; udp_remote = (struct sockaddr_in*)&evt_data->ep->addr; memset( &msg, 0 , sizeof(msg) ); res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg); if (!res) { ms_error("ice.c: Malformed STUN packet."); return -1; } if (checklist==NULL) { ms_error("ice.c: dropping STUN packet: ice is not configured"); return -1; } remote_candidates = checklist->cand_pairs; if (remote_candidates==NULL) { ms_error("ice.c: dropping STUN packet: ice is not configured"); return -1; } /* prepare ONCE tie-break value */ if (checklist->tiebreak_value==0) { checklist->tiebreak_value = random() * (0x7fffffffffffffffLL/0x7fff); } memset (src6host, 0, sizeof (src6host)); { struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr; if (aaddr->ss_family==AF_INET) recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port); else recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port); } i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen, src6host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (i != 0) { ms_error("ice.c: Error with getnameinfo"); return -1; } if (STUN_IS_REQUEST(msg.msgHdr.msgType)) ms_message("ice.c: STUN_CONNECTIVITYCHECK: Request received from: %s:%i", src6host, recvport); else if (STUN_IS_INDICATION(msg.msgHdr.msgType)) ms_message("ice.c: SUN_INDICATION: Request Indication received from: %s:%i", src6host, recvport); else ms_message("ice.c: STUN_ANSWER: Answer received from: %s:%i", src6host, recvport); { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { struct CandidatePair *cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_SUCCEEDED) { highest_priority_success=pos; break; } } } if (STUN_IS_INDICATION(msg.msgHdr.msgType)) { ms_message("ice.c: STUN INDICATION <- (?:?:? <- %s:%i:?)", src6host, recvport); return 0; } else if (STUN_IS_REQUEST(msg.msgHdr.msgType)) { StunMessage resp; StunAtrString hmacPassword; StunAddress4 remote_addr; int rtp_socket; memset( &resp, 0 , sizeof(resp)); remote_addr.addr = ntohl(udp_remote->sin_addr.s_addr); remote_addr.port = ntohs(udp_remote->sin_port); rtp_socket = rtp_session_get_rtp_socket(session); resp.msgHdr.magic_cookie = ntohl(msg.msgHdr.magic_cookie); for (i=0; i<12; i++ ) { resp.msgHdr.tr_id.octet[i] = msg.msgHdr.tr_id.octet[i]; } /* check mandatory params */ if (!msg.hasUsername) { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- Missing USERNAME attribute in connectivity check"); _ice_createErrorResponse(&resp, 4, 32, "Missing USERNAME attribute"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } if (!msg.hasMessageIntegrity) { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- Missing MESSAGEINTEGRITY attribute in connectivity check"); _ice_createErrorResponse(&resp, 4, 1, "Missing MESSAGEINTEGRITY attribute"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } /* The password associated with that transport address ID is used to verify the MESSAGE-INTEGRITY attribute, if one was present in the request. */ { char hmac[20]; /* remove length of fingerprint if present */ if (msg.hasFingerprint==TRUE) { char *lenpos = (char *)mp->b_rptr + sizeof(uint16_t); uint16_t newlen = htons(msg.msgHdr.msgLength-8); /* remove fingerprint size */ memcpy(lenpos, &newlen, sizeof(uint16_t)); stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24-8, checklist->loc_ice_pwd); } else stunCalculateIntegrity_shortterm(hmac, (char*)mp->b_rptr, mp->b_wptr-mp->b_rptr-24, checklist->loc_ice_pwd); if (memcmp(msg.messageIntegrity.hash, hmac, 20)!=0) { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- Wrong MESSAGEINTEGRITY attribute in connectivity check"); _ice_createErrorResponse(&resp, 4, 1, "Wrong MESSAGEINTEGRITY attribute"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } if (msg.hasFingerprint==TRUE) { char *lenpos = (char *)mp->b_rptr + sizeof(uint16_t); uint16_t newlen = htons(msg.msgHdr.msgLength); /* add back fingerprint size */ memcpy(lenpos, &newlen, sizeof(uint16_t)); } } /* 7.2.1.1. Detecting and Repairing Role Conflicts */ /* TODO */ if (!msg.hasIceControlling && !msg.hasIceControlled) { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute"); _ice_createErrorResponse(&resp, 4, 87, "Missing either ICE-CONTROLLING or ICE-CONTROLLED attribute"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } if (checklist->rem_controlling==0 && msg.hasIceControlling) { /* If the agent's tie-breaker is larger than or equal to the contents of the ICE-CONTROLLING attribute -> send 487, and do not change ROLE */ if (checklist->tiebreak_value >= msg.iceControlling.value) { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- 487 Role Conflict"); _ice_createErrorResponse(&resp, 4, 87, "Role Conflict"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } else { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { /* controller agent */ uint64_t G = remote_candidates[pos].remote_candidate.priority; /* controlled agent */ uint64_t D = remote_candidates[pos].local_candidate.priority; remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0); } checklist->rem_controlling = 1; /* reset all to initial WAITING state? */ ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state"); for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { if (remote_candidates[pos].connectivity_check == ICE_PRUNED) continue; remote_candidates[pos].connectivity_check = ICE_WAITING; memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid)); remote_candidates[pos].retransmission_time = 0; remote_candidates[pos].retransmission_number = 0; } } } if (checklist->rem_controlling==1 && msg.hasIceControlled) { /* If the agent's tie-breaker is larger than or equal to the contents of the ICE-CONTROLLED attribute -> change ROLE */ if (checklist->tiebreak_value >= msg.iceControlled.value) { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { /* controller agent */ uint64_t G = remote_candidates[pos].local_candidate.priority; /* controlled agent */ uint64_t D = remote_candidates[pos].remote_candidate.priority; remote_candidates[pos].pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0); } checklist->rem_controlling = 0; /* reset all to initial WAITING state? */ ms_message("ice.c: STUN REQ <- tiebreaker -> reset all to ICE_WAITING state"); for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { if (remote_candidates[pos].connectivity_check == ICE_PRUNED) continue; remote_candidates[pos].connectivity_check = ICE_WAITING; memset(&remote_candidates[pos].tid , 0, sizeof(remote_candidates[pos].tid)); remote_candidates[pos].retransmission_time = 0; remote_candidates[pos].retransmission_number = 0; } } else { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); ms_error("ice.c: STUN REQ <- 487 Role Conflict"); _ice_createErrorResponse(&resp, 4, 87, "Role Conflict"); len = stunEncodeMessage(&resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); return -1; } } { struct CandidatePair *cand_pair; int pos; cand_pair=NULL; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; /* connectivity check is coming from a known remote candidate? we should also check the port... */ if (strcmp(cand_pair->remote_candidate.conn_addr, src6host)==0 && cand_pair->remote_candidate.conn_port==recvport) { ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) from known peer", msg.hasUseCandidate==0?"":"USE-CANDIDATE", pos, cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->local_candidate.cand_type, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port, cand_pair->remote_candidate.cand_type); if (cand_pair->connectivity_check==ICE_FROZEN || cand_pair->connectivity_check==ICE_IN_PROGRESS || cand_pair->connectivity_check==ICE_FAILED) { cand_pair->connectivity_check = ICE_WAITING; if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0) cand_pair->nominated_pair = 1; } else if (cand_pair->connectivity_check==ICE_SUCCEEDED) { if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0) { cand_pair->nominated_pair = 1; /* USE-CANDIDATE is in STUN request and we already succeeded on that link */ ms_message("ice.c: ICE CONCLUDED == %i (%s:%i:%s <- %s:%i:%s nominated=%s)", pos, cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->local_candidate.cand_type, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port, cand_pair->remote_candidate.cand_type, cand_pair->nominated_pair==0?"FALSE":"TRUE"); memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen); session->rtp.rem_addrlen=evt_data->ep->addrlen; } } break; } cand_pair=NULL; } if (cand_pair==NULL) { struct CandidatePair new_pair; memset(&new_pair, 0, sizeof(struct CandidatePair)); ms_message("ice.c: STUN REQ <- connectivity check received from an unknow candidate (%s:%i)", src6host, recvport); /* TODO: add the peer-reflexive candidate */ memcpy(&new_pair.local_candidate, &remote_candidates[0].local_candidate, sizeof(new_pair.local_candidate)); new_pair.remote_candidate.foundation = 6; new_pair.remote_candidate.component_id = remote_candidates[0].remote_candidate.component_id; /* -> no known base address for peer */ new_pair.remote_candidate.conn_port = recvport; snprintf(new_pair.remote_candidate.conn_addr, sizeof(new_pair.remote_candidate.conn_addr), "%s", src6host); /* take it from PRIORITY STUN attr */ new_pair.remote_candidate.priority = msg.priority.priority; if (new_pair.remote_candidate.priority==0) { uint32_t type_preference = 110; uint32_t interface_preference = 255; uint32_t stun_priority=255; new_pair.remote_candidate.priority = (type_preference << 24) | (interface_preference << 16) | (stun_priority << 8) | (256 - new_pair.remote_candidate.component_id); } snprintf(new_pair.remote_candidate.cand_type, sizeof(cand_pair->remote_candidate.cand_type), "prflx"); snprintf (new_pair.remote_candidate.transport, sizeof (new_pair.remote_candidate.transport), "UDP"); if (checklist->rem_controlling==0) { uint64_t G = new_pair.local_candidate.priority; /* controlled agent */ uint64_t D = new_pair.remote_candidate.priority; new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0); } else { uint64_t G = new_pair.remote_candidate.priority; /* controlled agent */ uint64_t D = new_pair.local_candidate.priority; new_pair.pair_priority = (MIN(G, D))<<32 | (MAX(G, D))<<1 | (G>D?1:0); } new_pair.connectivity_check = ICE_WAITING; /* insert new pair candidate */ if (msg.hasUseCandidate==TRUE && checklist->rem_controlling==0) { new_pair.nominated_pair = 1; } for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { if (pos==9) { ms_message("ice.c: STUN REQ (%s) <- X (%s:%i:%s <- %s:%i:%s) no room for new remote reflexive candidate", msg.hasUseCandidate==0?"":"USE-CANDIDATE", new_pair.local_candidate.conn_addr, new_pair.local_candidate.conn_port, new_pair.local_candidate.cand_type, new_pair.remote_candidate.conn_addr, new_pair.remote_candidate.conn_port, new_pair.remote_candidate.cand_type); break; } if (new_pair.pair_priority > remote_candidates[pos].pair_priority) { /* move upper data */ memmove(&remote_candidates[pos+1], &remote_candidates[pos], sizeof(struct CandidatePair)*(10-pos-1)); memcpy(&remote_candidates[pos], &new_pair, sizeof(struct CandidatePair)); if (checklist->nominated_pair_index>=pos) checklist->nominated_pair_index++; ms_message("ice.c: STUN REQ (%s) <- %i (%s:%i:%s <- %s:%i:%s) new learned remote reflexive candidate", msg.hasUseCandidate==0?"":"USE-CANDIDATE", pos, new_pair.local_candidate.conn_addr, new_pair.local_candidate.conn_port, new_pair.local_candidate.cand_type, new_pair.remote_candidate.conn_addr, new_pair.remote_candidate.conn_port, new_pair.remote_candidate.cand_type); break; } } } } { uint32_t cookie = 0x2112A442; resp.hasXorMappedAddress = TRUE; resp.xorMappedAddress.ipv4.port = remote_addr.port^(cookie>>16); resp.xorMappedAddress.ipv4.addr = remote_addr.addr^cookie; } resp.msgHdr.msgType = (STUN_METHOD_BINDING | STUN_SUCCESS_RESP); resp.hasUsername = TRUE; memcpy(resp.username.value, msg.username.value, msg.username.sizeValue ); resp.username.sizeValue = msg.username.sizeValue; /* ? any messageintegrity in response? */ resp.hasMessageIntegrity = TRUE; { const char serverName[] = "mediastreamer2 " STUN_VERSION; resp.hasSoftware = TRUE; memcpy( resp.softwareName.value, serverName, sizeof(serverName)); resp.softwareName.sizeValue = sizeof(serverName); } resp.hasFingerprint = TRUE; { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); len = stunEncodeMessage( &resp, buf, len, &hmacPassword ); if (len) sendMessage( rtp_socket, buf, len, remote_addr.addr, remote_addr.port); } }
static int ice_sound_send_stun_request(RtpSession *session, struct IceCheckList *checklist, uint64_t ctime) { struct CandidatePair *remote_candidates = NULL; if (checklist==NULL) return 0; remote_candidates = checklist->cand_pairs; if (remote_candidates==NULL) return 0; { struct CandidatePair *cand_pair; int media_socket = rtp_session_get_rtp_socket(session); StunAddress4 stunServerAddr; StunAtrString username; StunAtrString password; bool_t res; int pos; /* prepare ONCE tie-break value */ if (checklist->tiebreak_value==0) { checklist->tiebreak_value = random() * (0x7fffffffffffffffLL /0x7fff); } cand_pair=NULL; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_PRUNED) { cand_pair=NULL; continue; } if (cand_pair->connectivity_check == ICE_WAITING) break; if (cand_pair->connectivity_check == ICE_IN_PROGRESS) break; if (cand_pair->connectivity_check == ICE_SUCCEEDED) break; cand_pair=NULL; } if (cand_pair==NULL) return 0; /* nothing to do: every pair is FAILED, FROZEN or PRUNED */ /* start first WAITING pair */ cand_pair=NULL; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_PRUNED) { cand_pair=NULL; continue; } if (cand_pair->connectivity_check == ICE_WAITING) break; cand_pair=NULL; } if (cand_pair!=NULL) { cand_pair->connectivity_check = ICE_IN_PROGRESS; cand_pair->retransmission_number=0; cand_pair->retransmission_time=ctime+checklist->RTO; /* keep same rem_controlling for retransmission */ cand_pair->rem_controlling = checklist->rem_controlling; } /* try no nominate a pair if we are ready */ if (cand_pair==NULL && checklist->nominated_pair_index<0) { for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_PRUNED) { cand_pair=NULL; continue; } if (cand_pair->connectivity_check == ICE_SUCCEEDED) { break; } cand_pair=NULL; } /* ALWAYS accept "host" candidate that have succeeded */ if (cand_pair!=NULL && (strcasecmp(cand_pair->remote_candidate.cand_type, "host")==0)) { checklist->nominated_pair_index = pos; cand_pair->nominated_pair = 1; cand_pair->connectivity_check = ICE_IN_PROGRESS; cand_pair->retransmission_number=0; cand_pair->retransmission_time=ctime+checklist->RTO; /* keep same rem_controlling for retransmission */ cand_pair->rem_controlling = checklist->rem_controlling; /* send a new STUN with USE-CANDIDATE */ ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s", pos, cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->local_candidate.cand_type, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port, cand_pair->remote_candidate.cand_type, cand_pair->nominated_pair==0?"FALSE":"TRUE"); checklist->keepalive_time=ctime+15*1000; } else if (cand_pair!=NULL) { struct CandidatePair *cand_pair2=NULL; int pos2; for (pos2=0;pos2<pos && remote_candidates[pos2].remote_candidate.conn_addr[0]!='\0';pos2++) { cand_pair2 = &remote_candidates[pos2]; if (cand_pair2->connectivity_check == ICE_PRUNED) { cand_pair2=NULL; continue; } if (cand_pair2->connectivity_check == ICE_IN_PROGRESS ||cand_pair2->connectivity_check == ICE_WAITING) { break; } cand_pair2=NULL; } if (cand_pair2!=NULL) { /* a better candidate is still tested */ cand_pair=NULL; } else { checklist->nominated_pair_index = pos; cand_pair->nominated_pair = 1; cand_pair->connectivity_check = ICE_IN_PROGRESS; cand_pair->retransmission_number=0; cand_pair->retransmission_time=ctime+checklist->RTO; /* keep same rem_controlling for retransmission */ cand_pair->rem_controlling = checklist->rem_controlling; /* send a new STUN with USE-CANDIDATE */ ms_message("ice.c: nominating pair -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s", pos, cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->local_candidate.cand_type, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port, cand_pair->remote_candidate.cand_type, cand_pair->nominated_pair==0?"FALSE":"TRUE"); checklist->keepalive_time=ctime+15*1000; } } } if (cand_pair==NULL) { /* no WAITING pair: retransmit after RTO */ for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_PRUNED) { cand_pair=NULL; continue; } if (cand_pair->connectivity_check == ICE_IN_PROGRESS && ctime > cand_pair->retransmission_time) { if (cand_pair->retransmission_number>7) { ms_message("ice.c: ICE_FAILED for candidate pair! %s:%i -> %s:%i", cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port); cand_pair->connectivity_check = ICE_FAILED; cand_pair=NULL; continue; } cand_pair->retransmission_number++; cand_pair->retransmission_time=ctime+checklist->RTO; break; } cand_pair=NULL; } } if (cand_pair==NULL) { if (checklist->nominated_pair_index<0) return 0; /* send STUN indication each 15 seconds: keepalive */ if (ctime>checklist->keepalive_time) { checklist->keepalive_time=ctime+15*1000; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.conn_addr[0]!='\0';pos++) { cand_pair = &remote_candidates[pos]; if (cand_pair->connectivity_check == ICE_SUCCEEDED) { res = stunParseServerName(cand_pair->remote_candidate.conn_addr, &stunServerAddr); if ( res == TRUE ) { StunMessage req; char buf[STUN_MAX_MESSAGE_SIZE]; int len = STUN_MAX_MESSAGE_SIZE; stunServerAddr.port = cand_pair->remote_candidate.conn_port; memset(&req, 0, sizeof(StunMessage)); stunBuildReqSimple( &req, NULL, FALSE, FALSE, 1); req.msgHdr.msgType = (STUN_METHOD_BINDING|STUN_INDICATION); req.hasFingerprint = TRUE; len = stunEncodeMessage( &req, buf, len, NULL); sendMessage( media_socket, buf, len, stunServerAddr.addr, stunServerAddr.port ); } } } } return 0; } username.sizeValue = 0; password.sizeValue = 0; /* username comes from "ice-ufrag" (rfrag:lfrag) */ /* ufrag and pwd are in first row only */ snprintf(username.value, sizeof(username.value), "%s:%s", checklist->rem_ice_ufrag, checklist->loc_ice_ufrag); username.sizeValue = (uint16_t)strlen(username.value); snprintf(password.value, sizeof(password.value), "%s", checklist->rem_ice_pwd); password.sizeValue = (uint16_t)strlen(password.value); res = stunParseServerName(cand_pair->remote_candidate.conn_addr, &stunServerAddr); if ( res == TRUE ) { ms_message("ice.c: STUN REQ (%s) -> %i (%s:%i:%s -> %s:%i:%s) nominated=%s", cand_pair->nominated_pair==0?"":"USE-CANDIDATE", pos, cand_pair->local_candidate.conn_addr, cand_pair->local_candidate.conn_port, cand_pair->local_candidate.cand_type, cand_pair->remote_candidate.conn_addr, cand_pair->remote_candidate.conn_port, cand_pair->remote_candidate.cand_type, cand_pair->nominated_pair==0?"FALSE":"TRUE"); stunServerAddr.port = cand_pair->remote_candidate.conn_port; ice_sendtest(checklist, cand_pair, media_socket, &stunServerAddr, &username, &password, &(cand_pair->tid)); } } return 0; }
t_media_stun_trans::t_media_stun_trans(t_user *user, StunMessage *r, unsigned short _tuid, const list<t_ip_port> &dst, unsigned short src_port) : t_stun_transaction(user, r, _tuid, dst) { thr_listen = NULL; try { sock = new t_socket_udp(src_port); MEMMAN_NEW(sock); sock->connect(destinations.front().ipaddr, destinations.front().port); } catch (int err) { string msg("Failed to create a UDP socket (STUN) on port "); msg += int2str(src_port); msg += "\n"; msg += get_error_str(err); log_file->write_report(msg, "t_media_stun_trans::t_media_stun_trans", LOG_NORMAL, LOG_CRITICAL); delete sock; sock = NULL; StunMessage *resp; resp = stunBuildError(*request, 500, "Could not create socket"); evq_trans_layer->push_stun_response(resp, tuid, id); MEMMAN_DELETE(resp); delete resp; return; } // Send STUN request StunAtrString stun_pass; stun_pass.sizeValue = 0; char m[STUN_MAX_MESSAGE_SIZE]; int msg_size = stunEncodeMessage(*r, m, STUN_MAX_MESSAGE_SIZE, stun_pass, false); try { sock->send(m, msg_size); } catch (int err) { string msg("Failed to send STUN request for media.\n"); msg += get_error_str(err); log_file->write_report(msg, "::t_media_stun_trans::t_media_stun_trans", LOG_NORMAL, LOG_CRITICAL); StunMessage *resp; resp = stunBuildError(*request, 500, "Failed to send request"); evq_trans_layer->push_stun_response(resp, tuid, id); MEMMAN_DELETE(resp); delete resp; return; } num_transmissions++; try { thr_listen = new t_thread(stun_listen_main, sock); MEMMAN_NEW(thr_listen); } catch (int) { log_file->write_report("Failed to create STUN listener thread.", "::t_media_stun_trans::t_media_stun_trans", LOG_NORMAL, LOG_CRITICAL); delete thr_listen; thr_listen = NULL; StunMessage *resp; resp = stunBuildError(*request, 500, "Failed to create STUN listen thread"); evq_trans_layer->push_stun_response(resp, tuid, id); MEMMAN_DELETE(resp); delete resp; return; } start_timer_req_timeout(); state = TS_PROCEEDING; }
bool get_stun_binding(t_user *user_config, unsigned short src_port, unsigned long &mapped_ip, unsigned short &mapped_port, int &err_code, string &err_reason) { list<t_ip_port> destinations = user_config->get_stun_server().get_h_ip_srv("udp"); if (destinations.empty()) { // Cannot resolve STUN server address. log_file->write_header("::get_stun_binding", LOG_NORMAL, LOG_CRITICAL); log_file->write_raw("Failed to resolve: "); log_file->write_raw(user_config->get_stun_server().encode()); log_file->write_endl(); log_file->write_raw("Return internal STUN bind error: 404 Not Found"); log_file->write_endl(); log_file->write_footer(); err_code = 404; err_reason = "Not Found"; return false; } int num_transmissions = 0; int wait_intval = DUR_STUN_START_INTVAL; t_socket_udp sock(src_port); sock.connect(destinations.front().ipaddr, destinations.front().port); // Build STUN request char buf[STUN_MAX_MESSAGE_SIZE + 1]; StunMessage req_bind; StunAtrString stun_null_str; stun_null_str.sizeValue = 0; stunBuildReqSimple(&req_bind, stun_null_str, false, false); char req_msg[STUN_MAX_MESSAGE_SIZE]; int req_msg_size = stunEncodeMessage(req_bind, req_msg, STUN_MAX_MESSAGE_SIZE, stun_null_str, false); // Send STUN request and retransmit till a response is received. while (num_transmissions < STUN_MAX_TRANSMISSIONS) { bool ret; try { sock.send(req_msg, req_msg_size); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Send failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } log_file->write_header("::get_stun_binding", LOG_STUN); log_file->write_raw("Send to: "); log_file->write_raw(h_ip2str(destinations.front().ipaddr)); log_file->write_raw(":"); log_file->write_raw(destinations.front().port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(req_bind)); log_file->write_footer(); try { ret = sock.select_read(wait_intval); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Select failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } if (!ret) { // Time out num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } // A message has been received int resp_msg_size; try { resp_msg_size = sock.recv(buf, STUN_MAX_MESSAGE_SIZE + 1); } catch (int err) { // Socket error (probably ICMP error) // Failover to next destination log_file->write_report("Recv failed. Failover to next destination.", "::get_stun_binding"); destinations.pop_front(); if (destinations.empty()) { log_file->write_report("No next destination for failover.", "::get_stun_binding"); break; } num_transmissions = 0; wait_intval = DUR_STUN_START_INTVAL; sock.connect(destinations.front().ipaddr, destinations.front().port); continue; } StunMessage resp_bind; if (!stunParseMessage(buf, resp_msg_size, resp_bind, false)) { log_file->write_report( "Received faulty STUN message", "::get_stun_binding", LOG_STUN); num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } log_file->write_header("::get_stun_binding", LOG_STUN); log_file->write_raw("Received from: "); log_file->write_raw(h_ip2str(destinations.front().ipaddr)); log_file->write_raw(":"); log_file->write_raw(destinations.front().port); log_file->write_endl(); log_file->write_raw(stunMsg2Str(resp_bind)); log_file->write_footer(); // Check if id in msgHdr matches if (!stunEqualId(resp_bind, req_bind)) { num_transmissions++; if (wait_intval < DUR_STUN_MAX_INTVAL) { wait_intval *= 2; } continue; } if (resp_bind.msgHdr.msgType == BindResponseMsg && resp_bind.hasMappedAddress) { // Bind response received mapped_ip = resp_bind.mappedAddress.ipv4.addr; mapped_port = resp_bind.mappedAddress.ipv4.port; return true; } if (resp_bind.msgHdr.msgType == BindErrorResponseMsg && resp_bind.hasErrorCode) { // Bind error received err_code = resp_bind.errorCode.errorClass * 100 + resp_bind.errorCode.number; char s[STUN_MAX_STRING + 1]; strncpy(s, resp_bind.errorCode.reason, STUN_MAX_STRING); s[STUN_MAX_STRING] = 0; err_reason = s; return false; } // A wrong response has been received. log_file->write_report( "Invalid STUN response received", "::get_stun_binding", LOG_NORMAL); err_code = 500; err_reason = "Server Error"; return false; } // Request timed out log_file->write_report("STUN request timeout", "::get_stun_binding", LOG_NORMAL); err_code = 408; err_reason = "Request Timeout"; return false; }
int ice_process_stun_message(RtpSession *session, struct CandidatePair *remote_candidates, OrtpEvent *evt) { bool switch_to_address = -1; StunMessage msg; bool res; int already_worked_once=-1; OrtpEventData *evt_data = ortp_event_get_data(evt); mblk_t *mp = evt_data->packet; struct sockaddr_in *udp_remote; char src6host[NI_MAXHOST]; int recvport = 0; int i; udp_remote = (struct sockaddr_in*)&evt_data->ep->addr; memset( &msg, 0 , sizeof(msg) ); res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &msg, 0); if (!res) { ms_error("ice.c: Malformed STUN packet."); return -1; } memset (src6host, 0, sizeof (src6host)); { struct sockaddr_storage *aaddr = (struct sockaddr_storage *)&evt_data->ep->addr; if (aaddr->ss_family==AF_INET) recvport = ntohs (((struct sockaddr_in *) udp_remote)->sin_port); else recvport = ntohs (((struct sockaddr_in6 *) &evt_data->ep->addr)->sin6_port); } i = getnameinfo ((struct sockaddr*)&evt_data->ep->addr, evt_data->ep->addrlen, src6host, NI_MAXHOST, NULL, 0, NI_NUMERICHOST); if (i != 0) { ms_error("ice.c: Error with getnameinfo"); } else { if (msg.msgHdr.msgType == BindRequestMsg) ms_message("ice.c: Request received from: %s:%i", src6host, recvport); else ms_message("ice.c: Answer received from: %s:%i", src6host, recvport); } if (remote_candidates!=NULL) { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) { struct CandidatePair *cand_pair = &remote_candidates[pos]; #ifdef RESTRICTIVE_ICE if (cand_pair->connectivity_check == VALID ||cand_pair->connectivity_check == RECV_VALID) { already_worked_once=pos; break; } #else if (cand_pair->connectivity_check == VALID ||cand_pair->connectivity_check == RECV_VALID ||cand_pair->connectivity_check == SEND_VALID) { already_worked_once=pos; break; } #endif } } if (msg.msgHdr.msgType == BindRequestMsg) { StunMessage resp; StunAddress4 dest; StunAtrString hmacPassword; StunAddress4 from; StunAddress4 secondary; StunAddress4 myAddr; StunAddress4 myAltAddr; bool changePort = false; bool changeIp = false; struct sockaddr_storage name; socklen_t namelen; char localip[128]; int rtp_socket; memset(&name, '\0', sizeof(struct sockaddr_storage)); memset(localip, '\0', sizeof(localip)); _ice_get_localip_for ((struct sockaddr_storage*)&evt_data->ep->addr, evt_data->ep->addrlen, localip, 128); from.addr = ntohl(udp_remote->sin_addr.s_addr); from.port = ntohs(udp_remote->sin_port); secondary.addr = 0; secondary.port = 0; namelen = sizeof(struct sockaddr_storage); rtp_socket = rtp_session_get_rtp_socket(session); i = getsockname(rtp_socket, (struct sockaddr*)&name, &namelen); if (i!=0) { ms_error("ice.c: getsockname failed."); return -1; } myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port); i = stunParseHostName(localip, &myAddr.addr, &myAddr.port, myAddr.port); if (!i) { ms_error("ice.c: stunParseHostName failed."); return -1; } myAddr.port = ntohs (((struct sockaddr_in*)&name)->sin_port); /* changed-address set to local address/port */ myAltAddr = myAddr; dest.addr = 0; dest.port = 0; res = stunServerProcessMsg((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &from, &secondary, &myAddr, &myAltAddr, &resp, &dest, &hmacPassword, &changePort, &changeIp, false ); if (!res) { ms_error("ice.c: Failed to process STUN request."); return -1; } if (changePort == true || changeIp == true) { ms_error("ice.c: STUN request with changePort or changeIP refused."); return -1; } res=true; if ( dest.addr == 0 ) res=false; if ( dest.port == 0 ) res=false; if (!res) { ms_error("ice.c: Missing destination value for response."); return -1; } if (msg.hasUsername!=true || msg.username.sizeValue<=0) { /* reply 430 */ ms_error("ice.c: Missing or bad username value."); return -1; } /* USERNAME is considered valid if its topmost portion (the part up to, but not including the second colon) corresponds to a transport address ID known to the agent. */ if (remote_candidates!=NULL) { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) { char username[256]; struct CandidatePair *cand_pair = &remote_candidates[pos]; size_t len = strlen(cand_pair->remote_candidate.candidate_id); if (cand_pair->connectivity_check == VALID) { break; } memset(username, '\0', sizeof(username)); snprintf(username, sizeof(username), "%s:%i:%s:%i", cand_pair->remote_candidate.candidate_id, 1, cand_pair->local_candidate.candidate_id, 1); if (len+3<msg.username.sizeValue && strncmp(msg.username.value, cand_pair->remote_candidate.candidate_id, len)==0) { char tmp[10]; int k; snprintf(tmp, 10, "%s", msg.username.value + len +1); for (k=0;k<10;k++) { if (tmp[k]=='\0') break; if (tmp[k]==':') { tmp[k]='\0'; break; } } k = atoi(tmp); /* TODO support for 2 stream RTP+RTCP */ if (k>0 && k<10 && k==1) { /* candidate-id found! */ #if 0 ms_message("ice.c: Find candidate id (index=%i) for incoming STUN request.", pos); #endif if (strncmp(msg.username.value, username, strlen(username))==0) { #ifdef RESTRICTIVE_ICE ms_message("ice.c: Valid STUN request received (to=%s:%i from=%s:%i).", cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, src6host, recvport); /* We can't be sure the remote end will receive our answer: connection could be only one way... */ if (cand_pair->connectivity_check != VALID) { switch_to_address = pos; } #else switch_to_address = pos; #endif if (cand_pair->connectivity_check == RECV_VALID || cand_pair->connectivity_check == VALID) { if (cand_pair->connectivity_check != VALID) { switch_to_address = pos; ms_message("ice.c: candidate id (index=%i) moved in VALID state (stunbindingrequest received).", pos); cand_pair->connectivity_check = VALID; } } else cand_pair->connectivity_check = SEND_VALID; /* we have a VALID one */ } } } } } /* The password associated with that transport address ID is used to verify the MESSAGE-INTEGRITY attribute, if one was present in the request. */ { char buf[STUN_MAX_MESSAGE_SIZE]; int len = sizeof(buf); len = stunEncodeMessage( &resp, buf, len, &hmacPassword,false ); if (len) sendMessage( rtp_socket, buf, len, dest.addr, dest.port, false ); } } else { /* set state to RECV-VALID or VALID */ StunMessage resp; StunAddress4 mappedAddr; memset(&resp, 0, sizeof(StunMessage)); res = stunParseMessage((char*)mp->b_rptr, mp->b_wptr-mp->b_rptr, &resp, false ); if (!res) { ms_error("ice.c: Bad format for STUN answer."); return -1; } mappedAddr = resp.mappedAddress.ipv4; if (remote_candidates!=NULL) { int pos; for (pos=0;pos<10 && remote_candidates[pos].remote_candidate.ipaddr[0]!='\0';pos++) { struct CandidatePair *cand_pair = &remote_candidates[pos]; if (memcmp(&(cand_pair->tid), &(resp.msgHdr.id), sizeof(resp.msgHdr.id))==0) { /* Youhouhouhou */ if (cand_pair->connectivity_check != VALID) { switch_to_address = pos; } #if 0 ms_message("ice.c: Valid STUN answer received (to=%s:%i from=%s:%i)", cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, src6host, recvport); #endif if (cand_pair->connectivity_check == SEND_VALID || cand_pair->connectivity_check == VALID) { if (cand_pair->connectivity_check != VALID) { ms_message("ice.c: Switch to VALID mode for (to=%s:%i from=%s:%i)", cand_pair->remote_candidate.ipaddr, cand_pair->remote_candidate.port, src6host, recvport); cand_pair->connectivity_check = VALID; } } else cand_pair->connectivity_check = RECV_VALID; } } } } if (remote_candidates==NULL) { ms_warning("ice.c: STUN connectivity check is disabled but we received a STUN message (%s:%i)\n", src6host, recvport); return 0; } if (switch_to_address == -1) return 0; { /* skip symmetric RTP if any previous connection is working */ if (switch_to_address<already_worked_once || already_worked_once==-1) { /* rtp_in_direct_mode = 1; */ /* current destination address: snprintf(rtp_remote_addr, 256, "%s:%i", src6host, recvport); */ ms_warning("ice.c: Modifying remote socket: symmetric RTP (%s:%i)\n", src6host, recvport); memcpy(&session->rtp.rem_addr, &evt_data->ep->addr, evt_data->ep->addrlen); session->rtp.rem_addrlen=evt_data->ep->addrlen; } } return 0; }