123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- /*
- * To change this template, choose Tools | Templates
- * and open the template in the editor.
- */
-
- package com.md87.nat;
-
- import de.javawi.jstun.attribute.MappedAddress;
- import de.javawi.jstun.attribute.MessageAttribute;
- import de.javawi.jstun.attribute.MessageAttributeException;
- import de.javawi.jstun.attribute.MessageAttributeParsingException;
- import de.javawi.jstun.header.MessageHeader;
- import de.javawi.jstun.header.MessageHeaderParsingException;
- import de.javawi.jstun.test.DiscoveryInfo;
- import de.javawi.jstun.test.DiscoveryTest;
- import de.javawi.jstun.util.UtilityException;
-
- import java.io.IOException;
- import java.net.DatagramPacket;
- import java.net.DatagramSocket;
- import java.net.InetAddress;
- import java.net.InetSocketAddress;
- import java.net.NetworkInterface;
- import java.net.SocketException;
- import java.util.Enumeration;
- import java.util.HashMap;
- import java.util.Map;
- import java.util.concurrent.Semaphore;
-
- /**
- *
- * @author chris
- */
- public class NatTraverser {
-
- protected final CommsAgent agent;
-
- protected InetAddress address;
- protected DiscoveryInfo result;
-
- protected NatType theirType;
- protected NatType ourType;
-
- public NatTraverser(final CommsAgent agent) {
- this.agent = agent;
- }
-
- public void setInetAddress(final InetAddress address) {
- this.address = address;
- this.result = getDiscoveryInfo(address);
- addressUpdated();
- }
-
- public void findBestInetAddress() {
- final Semaphore threadSem = new Semaphore(0);
-
- NatType bestType = null;
- Map.Entry<InetAddress, DiscoveryInfo> best = null;
-
- for (final Map.Entry<InetAddress, DiscoveryInfo> info : getDiscoveryInfos().entrySet()) {
- if (info.getValue() == null) {
- return;
- }
-
- final NatType thisType = getTypeFromDI(info.getValue());
- if (thisType != null &&
- (bestType == null || thisType.ordinal() < bestType.ordinal())) {
- bestType = thisType;
- best = info;
- }
- }
-
- if (best != null) {
- this.address = best.getKey();
- this.result = best.getValue();
- addressUpdated();
- }
- }
-
- protected void addressUpdated() {
- try {
- ourType = getTypeFromDI(result);
-
- System.out.println("Using local IP: " + result.getLocalIP().getHostAddress()
- + " (remote: " + result.getPublicIP().getHostAddress() + "; iface: "
- + NetworkInterface.getByInetAddress(result.getLocalIP()).getName()
- + "; type: " + ourType + ")");
-
- agent.sendNATType(ourType);
-
- theirType = agent.readNATType();
- } catch (SocketException ex) {
- // Meh
- }
- }
-
- public DatagramSocket traverse() throws UnsupportedOperationException,
- SocketException, UtilityException, IOException,
- MessageHeaderParsingException, MessageAttributeParsingException, InterruptedException {
- if (!getTypeFromDI(result).canTraverseWith(theirType)) {
- throw new UnsupportedOperationException("Cannot traverse "
- + "between a " + ourType + " network and a "
- + theirType + " network.");
- }
-
- final DatagramSocket sock
- = new DatagramSocket(new InetSocketAddress(address, 0));
- sock.connect(InetAddress.getByName("stun.dmdirc.com"), 3478);
-
- MessageHeader sendMH = new MessageHeader(MessageHeader.MessageHeaderType.BindingRequest);
- sendMH.generateTransactionID();
-
- byte[] data = sendMH.getBytes();
- DatagramPacket send = new DatagramPacket(data, data.length);
- sock.send(send);
-
- MessageHeader receiveMH = new MessageHeader();
- while (!(receiveMH.equalTransactionID(sendMH))) {
- DatagramPacket receive = new DatagramPacket(new byte[200], 200);
- sock.receive(receive);
- receiveMH = MessageHeader.parseHeader(receive.getData());
- receiveMH.parseAttributes(receive.getData());
- }
-
- final MappedAddress ma = (MappedAddress) receiveMH.getMessageAttribute(MessageAttribute.MessageAttributeType.MappedAddress);
-
- System.out.println("I'm listening on " + address.getHostAddress() + ":"
- + sock.getLocalPort() + ". STUN server says I'm sending packets from "
- + ma.getAddress().getInetAddress().getHostAddress() + ":"
- + ma.getPort());
-
- agent.sendAddress(ma.getAddress().getInetAddress());
- agent.sendPort(ma.getPort());
-
- final InetAddress raddr = agent.readAddress();
- final int rport = agent.readPort();
-
- sock.disconnect();
- sock.connect(raddr, rport);
-
- boolean cont;
-
- do {
- cont = false;
- DatagramPacket p = new DatagramPacket("NatTraverser!".getBytes(), 13);
-
- try {
- sock.send(p);
-
- p = new DatagramPacket(new byte[13], 13);
-
- sock.receive(p);
- } catch (IOException ex) {
- ex.printStackTrace();
-
- cont = true;
- Thread.sleep(500);
- }
- } while (cont);
-
- return sock;
- }
-
- public static NatType getTypeFromDI(final DiscoveryInfo info) {
- if (info.isFullCone()) {
- return NatType.FULL_CONE;
- } else if (info.isOpenAccess()) {
- return NatType.OPEN;
- } else if (info.isPortRestrictedCone()) {
- return NatType.PORT_RESTRICTED_CONE;
- } else if (info.isRestrictedCone()) {
- return NatType.RESTRICTED_CONE;
- } else if (info.isSymmetric()) {
- return NatType.SYMMETRIC;
- } else {
- return null;
- }
- }
-
- protected Map<InetAddress, DiscoveryInfo> getDiscoveryInfos() {
- final Map<InetAddress, DiscoveryInfo> res
- = new HashMap<InetAddress, DiscoveryInfo>();
-
- try {
- final Enumeration<NetworkInterface> en = NetworkInterface.getNetworkInterfaces();
- while (en.hasMoreElements()) {
- final Enumeration<InetAddress> inen = en.nextElement().getInetAddresses();
-
- while (inen.hasMoreElements()) {
- final InetAddress ia = inen.nextElement();
- res.put(ia, getDiscoveryInfo(ia));
- }
- }
- } catch (SocketException ex) {
- // Meh
- }
-
- return res;
- }
-
- protected DiscoveryInfo getDiscoveryInfo(final InetAddress iaddress) {
- try {
- return new DiscoveryTest(iaddress, "stun.dmdirc.com", 3478).test();
- } catch (IOException ex) {
- // Meh
- } catch (UtilityException ex) {
- // Meh
- } catch (MessageAttributeException ex) {
- // Meh
- } catch (MessageHeaderParsingException ex) {
- // Meh
- }
-
- return null;
- }
-
- }
|