2 * This file is part of JSTUN.
4 * Copyright (c) 2005 Thomas King <king@t-king.de> - All rights
7 * This software is licensed under either the GNU Public License (GPL),
8 * or the Apache 2.0 license. Copies of both license agreements are
9 * included in this distribution.
12 package de.javawi.jstun.test.demo.ice;
14 import java.net.InetAddress;
15 import java.net.NetworkInterface;
16 import java.util.Collections;
17 import java.util.Enumeration;
18 import java.util.HashSet;
19 import java.util.Iterator;
20 import java.util.List;
21 import java.util.Vector;
23 import de.javawi.jstun.test.DiscoveryInfo;
24 import de.javawi.jstun.test.DiscoveryTest;
25 import de.javawi.jstun.test.demo.ice.Candidate.CandidateType;
26 import de.javawi.jstun.util.Address;
28 public class ICENegociator {
29 // type preference must be an integere from 0 (=lowest) to 126 (=highest) (inclusive)
30 private final static int LOCAL_PREFERENCE = 0;
31 private final static int SERVER_REFLEXIVE_PREFERENCE = 42;
32 private final static int PEER_REFLEXIVE_PREFERENCE = 84;
33 private final static int RELAYED_PREFERENCE = 126;
36 private short componentId;
39 HashSet<Candidate> candidates;
41 public ICENegociator(short componentId) {
42 this.componentId = componentId;
43 candidates = new HashSet<Candidate>();
47 * This method gathers candidate addresses as described in draft-ietf-mmusic-ice-12.txt Chapter 2.1
48 * Unfortunately, only the candidates of the direct attached network interfaces and server reflexive
49 * addreses are gathered. So far, no support for relayed candidates is available (because I am not
50 * aware of any STUN relay server).
52 public void gatherCandidateAddresses() {
53 candidates = new HashSet<Candidate>();
55 Enumeration<NetworkInterface> ifaces = NetworkInterface.getNetworkInterfaces();
56 while (ifaces.hasMoreElements()) {
57 NetworkInterface iface = ifaces.nextElement();
58 Enumeration<InetAddress> iaddresses = iface.getInetAddresses();
59 while (iaddresses.hasMoreElements()) {
60 InetAddress iaddress = iaddresses.nextElement();
61 if (!iaddress.isLoopbackAddress() && !iaddress.isLinkLocalAddress()) {
63 Candidate local = new Candidate(new Address(iaddress.getAddress()), componentId);
64 candidates.add(local);
65 // add server reflexive address
66 DiscoveryTest test = new DiscoveryTest(iaddress, "iphone-stun.freenet.de", 3478);
67 DiscoveryInfo di = test.test();
68 if (di.getPublicIP() != null) {
69 Candidate cand = new Candidate(new Address(di.getPublicIP().getAddress()), CandidateType.ServerReflexive, componentId, local);
70 cand.setComponentId(componentId);
76 } catch (Exception e) {
81 public void prioritizeCandidates() {
82 // count number of candidate types
84 int numberServerReflexive = 0;
85 int numberPeerReflexive = 0;
86 int numberRelayed = 0;
87 // count number of candidates of a particular type
88 Iterator<Candidate> iterCandidates = candidates.iterator();
89 while (iterCandidates.hasNext()) {
90 Candidate cand = iterCandidates.next();
91 CandidateType type = cand.getCandidateType();
92 if (type == CandidateType.Local) numberLocal++;
93 else if (type == CandidateType.ServerReflexive) numberServerReflexive++;
94 else if (type == CandidateType.PeerReflexive) numberPeerReflexive++;
95 else if (type == CandidateType.Relayed) numberRelayed++;
98 iterCandidates = candidates.iterator();
99 while (iterCandidates.hasNext()) {
102 int componentValue = 0;
103 Candidate cand = iterCandidates.next();
104 CandidateType type = cand.getCandidateType();
105 if (type == CandidateType.Local) {
106 typeValue = LOCAL_PREFERENCE;
107 localValue = numberLocal--;
109 else if (type == CandidateType.ServerReflexive) {
110 typeValue = SERVER_REFLEXIVE_PREFERENCE;
111 localValue = numberServerReflexive--;
113 else if (type == CandidateType.PeerReflexive) {
114 typeValue = PEER_REFLEXIVE_PREFERENCE;
115 localValue = numberPeerReflexive--;
117 else if (type == CandidateType.Relayed) {
118 typeValue = RELAYED_PREFERENCE;
119 localValue = numberRelayed--;
121 componentValue = cand.getComponentId();
122 int priority = ((2 ^ 24) * typeValue) + ((2 ^ 8) * localValue) + componentValue;
123 cand.setPriority(priority);
127 public List<Candidate> getSortedCandidates() {
128 Vector<Candidate> sortedCandidates = new Vector<Candidate>(candidates);
129 Collections.sort(sortedCandidates);
130 return sortedCandidates;
133 public static void main(String args[]) {
134 ICENegociator cc = new ICENegociator((short) 1);
136 cc.gatherCandidateAddresses();
137 // priorize candidates
138 cc.prioritizeCandidates();
139 // get SortedCandidates
140 List<Candidate> sortedCandidates = cc.getSortedCandidates();
142 // sent sorted candidate addresses to peer over SDP
143 // received sorted candidate addresses of peer over SDP