1
0
Fork 0
mirror of https://codeberg.org/Mercury-IM/Smack synced 2024-11-23 06:42:05 +01:00

UDP Echo added

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@7028 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Thiago Camargo 2007-02-07 02:35:27 +00:00 committed by thiago
parent dee9b8a297
commit fb89cb289e
2 changed files with 234 additions and 31 deletions

View file

@ -0,0 +1,21 @@
package org.jivesoftware.smackx.jingle.nat;
import java.net.DatagramPacket;
/**
* Listener for datagram packets received.
*
* @author Thiago Camargo
*/
public interface DatagramListener {
/**
* Called when a datagram is received. If the method returns false, the
* packet MUST NOT be resent from the received Channel.
*
* @param datagramPacket the datagram packet received.
* @return ?
*/
public boolean datagramReceived(DatagramPacket datagramPacket);
}

View file

@ -54,13 +54,16 @@ package org.jivesoftware.smackx.jingle.nat;
import org.jivesoftware.smack.XMPPConnection; import org.jivesoftware.smack.XMPPConnection;
import java.net.InetAddress; import java.io.IOException;
import java.net.*;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Random;
import java.util.Arrays;
/** /**
* Transport candidate. * Transport candidate.
* * <p/>
* A candidate represents the possible transport for data interchange between * A candidate represents the possible transport for data interchange between
* the two endpoints. * the two endpoints.
* *
@ -87,9 +90,29 @@ public abstract class TransportCandidate {
private TransportCandidate symmetric; private TransportCandidate symmetric;
private CandidateEcho candidateEcho = null;
private Thread echoThread = null;
// Listeners for events // Listeners for events
private final List<TransportResolverListener.Checker> listeners = new ArrayList(); private final List<TransportResolverListener.Checker> listeners = new ArrayList();
public void addCandidateEcho() throws SocketException, UnknownHostException {
candidateEcho = new CandidateEcho(this);
echoThread = new Thread(candidateEcho);
echoThread.start();
}
public void removeCandidateEcho() {
candidateEcho.cancel();
candidateEcho = null;
echoThread = null;
}
public CandidateEcho getCandidateEcho() {
return candidateEcho;
}
public String getIp() { public String getIp() {
return ip; return ip;
} }
@ -231,11 +254,14 @@ public abstract class TransportCandidate {
public boolean isNull() { public boolean isNull() {
if (ip == null) { if (ip == null) {
return true; return true;
} else if (ip.length() == 0) { }
else if (ip.length() == 0) {
return true; return true;
} else if (port < 0) { }
else if (port < 0) {
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -318,14 +344,16 @@ public abstract class TransportCandidate {
if (other.getIp() != null) { if (other.getIp() != null) {
return false; return false;
} }
} else if (!getIp().equals(other.getIp())) { }
else if (!getIp().equals(other.getIp())) {
return false; return false;
} }
if (getName() == null) { if (getName() == null) {
if (other.getName() != null) { if (other.getName() != null) {
return false; return false;
} }
} else if (!getName().equals(other.getName())) { }
else if (!getName().equals(other.getName())) {
return false; return false;
} }
if (getPort() != other.getPort()) { if (getPort() != other.getPort()) {
@ -356,7 +384,8 @@ public abstract class TransportCandidate {
try { try {
candAddress = InetAddress.getByName(getIp()); candAddress = InetAddress.getByName(getIp());
isUsable = true;//candAddress.isReachable(CHECK_TIMEOUT); isUsable = true;//candAddress.isReachable(CHECK_TIMEOUT);
} catch (Exception e) { }
catch (Exception e) {
isUsable = false; isUsable = false;
} }
triggerCandidateChecked(isUsable); triggerCandidateChecked(isUsable);
@ -598,6 +627,7 @@ public abstract class TransportCandidate {
/** /**
* Get the Candidate Type * Get the Candidate Type
*
* @return candidate Type * @return candidate Type
*/ */
public String getType() { public String getType() {
@ -606,6 +636,7 @@ public abstract class TransportCandidate {
/** /**
* Set the Candidate Type * Set the Candidate Type
*
* @param type candidate type. * @param type candidate type.
*/ */
public void setType(String type) { public void setType(String type) {
@ -633,14 +664,16 @@ public abstract class TransportCandidate {
if (other.getChannel() != null) { if (other.getChannel() != null) {
return false; return false;
} }
} else if (!getChannel().equals(other.getChannel())) { }
else if (!getChannel().equals(other.getChannel())) {
return false; return false;
} }
if (getId() == null) { if (getId() == null) {
if (other.getId() != null) { if (other.getId() != null) {
return false; return false;
} }
} else if (!getId().equals(other.getId())) { }
else if (!getId().equals(other.getId())) {
return false; return false;
} }
if (getNetwork() != other.getNetwork()) { if (getNetwork() != other.getNetwork()) {
@ -650,7 +683,8 @@ public abstract class TransportCandidate {
if (other.getPassword() != null) { if (other.getPassword() != null) {
return false; return false;
} }
} else if (!getPassword().equals(other.password)) { }
else if (!getPassword().equals(other.password)) {
return false; return false;
} }
if (getPreference() != other.getPreference()) { if (getPreference() != other.getPreference()) {
@ -660,14 +694,16 @@ public abstract class TransportCandidate {
if (other.getProto() != null) { if (other.getProto() != null) {
return false; return false;
} }
} else if (!getProto().equals(other.getProto())) { }
else if (!getProto().equals(other.getProto())) {
return false; return false;
} }
if (getUsername() == null) { if (getUsername() == null) {
if (other.getUsername() != null) { if (other.getUsername() != null) {
return false; return false;
} }
} else if (!getUsername().equals(other.getUsername())) { }
else if (!getUsername().equals(other.getUsername())) {
return false; return false;
} }
return true; return true;
@ -676,9 +712,11 @@ public abstract class TransportCandidate {
public boolean isNull() { public boolean isNull() {
if (super.isNull()) { if (super.isNull()) {
return true; return true;
} else if (getProto().isNull()) { }
else if (getProto().isNull()) {
return true; return true;
} else if (getChannel().isNull()) { }
else if (getChannel().isNull()) {
return true; return true;
} }
return false; return false;
@ -697,7 +735,8 @@ public abstract class TransportCandidate {
TransportCandidate.Ice tc = (TransportCandidate.Ice) arg; TransportCandidate.Ice tc = (TransportCandidate.Ice) arg;
if (getPreference() < tc.getPreference()) { if (getPreference() < tc.getPreference()) {
return -1; return -1;
} else if (getPreference() > tc.getPreference()) { }
else if (getPreference() > tc.getPreference()) {
return 1; return 1;
} }
} }
@ -740,15 +779,20 @@ public abstract class TransportCandidate {
value = value.toLowerCase(); value = value.toLowerCase();
if (value.equals("udp")) { if (value.equals("udp")) {
return UDP; return UDP;
} else if (value.equals("tcp")) { }
else if (value.equals("tcp")) {
return TCP; return TCP;
} else if (value.equals("tcp-act")) { }
else if (value.equals("tcp-act")) {
return TCPACT; return TCPACT;
} else if (value.equals("tcp-pass")) { }
else if (value.equals("tcp-pass")) {
return TCPPASS; return TCPPASS;
} else if (value.equals("ssltcp")) { }
else if (value.equals("ssltcp")) {
return SSLTCP; return SSLTCP;
} else { }
else {
return UDP; return UDP;
} }
} }
@ -773,7 +817,8 @@ public abstract class TransportCandidate {
if (other.value != null) { if (other.value != null) {
return false; return false;
} }
} else if (!value.equals(other.value)) { }
else if (!value.equals(other.value)) {
return false; return false;
} }
return true; return true;
@ -787,9 +832,11 @@ public abstract class TransportCandidate {
public boolean isNull() { public boolean isNull() {
if (value == null) { if (value == null) {
return true; return true;
} else if (value.length() == 0) { }
else if (value.length() == 0) {
return true; return true;
} else { }
else {
return false; return false;
} }
} }
@ -824,9 +871,11 @@ public abstract class TransportCandidate {
value = value.toLowerCase(); value = value.toLowerCase();
if (value.equals("myrtpvoice")) { if (value.equals("myrtpvoice")) {
return MYRTPVOICE; return MYRTPVOICE;
} else if (value.equals("tcp")) { }
else if (value.equals("tcp")) {
return MYRTCPVOICE; return MYRTCPVOICE;
} else { }
else {
return MYRTPVOICE; return MYRTPVOICE;
} }
} }
@ -851,7 +900,8 @@ public abstract class TransportCandidate {
if (other.value != null) { if (other.value != null) {
return false; return false;
} }
} else if (!value.equals(other.value)) { }
else if (!value.equals(other.value)) {
return false; return false;
} }
return true; return true;
@ -865,11 +915,143 @@ public abstract class TransportCandidate {
public boolean isNull() { public boolean isNull() {
if (value == null) { if (value == null) {
return true; return true;
} else if (value.length() == 0) { }
else if (value.length() == 0) {
return true; return true;
} else { }
else {
return false; return false;
} }
} }
} }
public class CandidateEcho implements Runnable {
DatagramSocket socket = null;
byte password[] = null;
List<DatagramListener> listeners = new ArrayList<DatagramListener>();
boolean enabled = true;
public CandidateEcho(TransportCandidate candidate) throws UnknownHostException, SocketException {
this.socket = new DatagramSocket(candidate.getPort(), InetAddress.getByName(candidate.getLocalIp()));
Random r = new Random();
password = longToByteArray((Math.abs(r.nextLong())));
}
public void run() {
try {
while (true) {
DatagramPacket packet = new DatagramPacket(new byte[8], 8);
socket.receive(packet);
for (DatagramListener listener : listeners) {
listener.datagramReceived(packet);
}
packet.setAddress(packet.getAddress());
packet.setPort(packet.getPort());
if (!Arrays.equals(packet.getData(), password))
for (int i = 0; i < 3; i++)
socket.send(packet);
}
}
catch (UnknownHostException uhe) {
if (enabled) {
}
}
catch (SocketException se) {
if (enabled) {
}
}
catch (IOException ioe) {
if (enabled) {
}
}
}
public void cancel() {
this.enabled = false;
socket.close();
}
public boolean test(final InetAddress address, final int port) {
return test(address,port,2000);
}
public boolean test(final InetAddress address, final int port, int timeout) {
final TestResults testResults = new TestResults();
DatagramListener listener = new DatagramListener() {
public boolean datagramReceived(DatagramPacket datagramPacket) {
if (datagramPacket.getAddress().equals(address) && datagramPacket.getPort() == port) {
if (Arrays.equals(datagramPacket.getData(), password)) {
testResults.setResult(true);
return true;
}
}
testResults.setResult(false);
return false;
}
};
this.addListener(listener);
DatagramPacket packet = new DatagramPacket(password, password.length);
packet.setAddress(address);
packet.setPort(port);
try {
for (int i = 0; i < 3; i++)
socket.send(packet);
}
catch (IOException e) {
e.printStackTrace();
}
try {
Thread.sleep(timeout);
}
catch (InterruptedException e) {
e.printStackTrace();
}
return testResults.isReachable();
}
public void addListener(DatagramListener listener) {
listeners.add(listener);
}
public void removeListener(DatagramListener listener) {
listeners.remove(listener);
}
public class TestResults {
private boolean result;
public boolean isReachable() {
return result;
}
public void setResult(boolean result) {
this.result = result;
}
}
}
public static byte[] longToByteArray(long valor) {
byte[] result = new byte[8];
for (int i = 0; i < result.length; i++) {
result[7 - i] = (byte) (valor & 0xFF);
valor = valor >> 8;
}
return result;
}
} }