mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-27 00:32:07 +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:
parent
dee9b8a297
commit
fb89cb289e
2 changed files with 234 additions and 31 deletions
|
@ -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);
|
||||||
|
|
||||||
|
}
|
|
@ -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);
|
||||||
|
@ -473,8 +502,8 @@ public abstract class TransportCandidate {
|
||||||
* @param type type as defined in ICE-12
|
* @param type type as defined in ICE-12
|
||||||
*/
|
*/
|
||||||
public Ice(String ip, int generation, int network,
|
public Ice(String ip, int generation, int network,
|
||||||
String password, int port, String username,
|
String password, int port, String username,
|
||||||
int preference, String type) {
|
int preference, String type) {
|
||||||
super(ip, port, generation);
|
super(ip, port, generation);
|
||||||
|
|
||||||
proto = Protocol.UDP;
|
proto = Protocol.UDP;
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue