Methods Summary |
---|
public int | addPortMapping(boolean tcp, int publicPort, int privatePort)Asks for a public port to be mapped to a private port from this host.
NAP-PMP allows the device to assign another public port if the
requested one is taken. So, you should check the returned port.
// check for actual connection!
return portMappingProtocol( tcp, publicPort, privatePort,
NATMAP_DEFAULT_LEASE );
|
public java.lang.String | byteArrayString(byte[] buf)
StringBuffer sb = new StringBuffer();
for(int i = 0; i < buf.length; i++) {
sb.append(buf[i]).append(" ");
}
return sb.toString();
|
protected void | checkRouterAddress()
String natAddr = adapter.getRouterAddress().trim();
if ( natAddr.length() == 0 ){
natAddr = convertHost2RouterAddress(hostInet);
}
if ( natAddr.equals( current_router_address )){
return;
}
current_router_address = natAddr;
log("Using Router IP: " + natAddr);
natPriInet = InetAddress.getByName(natAddr);
networkInterface = NetworkInterface.getByInetAddress( natPriInet );
|
public boolean | connect()Try to connect with a NAT-PMP device.
This could take sometime.
checkRouterAddress();
try{
// Send NAT request to find out if it is PMP happy
byte reqBuf[] = {NATMAP_VER, NATOp_AddrRequest};
DatagramPacket dstPkt = new DatagramPacket(reqBuf, reqBuf.length);
byte recBuf[] = new byte[NATAddrReplyLen];
/* DatagramPacket recPkt = */ sendNATMsg(natPriInet, dstPkt, recBuf);
//int recVer = unsigned8ByteArrayToInt( recBuf, 0 );
//int recOp = unsigned8ByteArrayToInt( recBuf, 1 );
int recErr = unsigned16ByteArrayToInt( recBuf, 2 );
int recEpoch = unsigned32ByteArrayToInt( recBuf, 4 );
String recPubAddr = unsigned8ByteArrayToInt( recBuf, 8 ) + "." +
unsigned8ByteArrayToInt( recBuf, 9 ) + "." +
unsigned8ByteArrayToInt( recBuf, 10 ) + "." +
unsigned8ByteArrayToInt( recBuf, 11 );
/* set the global NAT public address */
natPubInet = InetAddress.getByName(recPubAddr);
/* set the global NAT Epoch time (in seconds) */
nat_epoch = recEpoch;
if (recErr != 0)
throw( new Exception("NAT-PMP connection error: " + recErr) );
log("Err: " +recErr);
log("Uptime: " + recEpoch);
log("Public Address: " + recPubAddr);
/**
* TO DO:
* Set up listner for announcements from the device for
* address changes (public address changes)
**/
nat_pmp_found = true;
return true;
}catch( PortUnreachableException e ){
return( false );
}
|
private java.lang.String | convertHost2RouterAddress(java.net.InetAddress inet)
byte rawIP[] = inet.getAddress();
// assume router is at xxx.xxx.xxx.1
rawIP[3] = 1;
// is there no printf in java?
String newIP = (rawIP[0]&0xff) +"."+(rawIP[1]&0xff)+"."+(rawIP[2]&0xff)+"."+(rawIP[3]&0xff);
return newIP;
|
public void | deletePortMapping(boolean tcp, int publicPort, int privatePort)Delete a mapped public port
/**
* if the request was successful, a zero lifetime will
* delete the mapping and return a public port of 0
**/
// check for actual connection
/*int result = */ portMappingProtocol(tcp, publicPort, privatePort, 0);
|
public int | getEpoch()
return( nat_epoch );
|
public java.lang.String | getExternalIPAddress()
return( natPubInet.getHostAddress());
|
public java.net.InetAddress | getLocalAddress()
return( hostInet );
|
public java.net.NetworkInterface | getNetworkInterface()
return( networkInterface );
|
public static synchronized com.aelitis.net.natpmp.impl.NatPMPDeviceImpl | getSingletonObject(com.aelitis.net.natpmp.NATPMPDeviceAdapter adapter)
if (NatPMPDeviceSingletonRef == null)
NatPMPDeviceSingletonRef = new NatPMPDeviceImpl(adapter);
return NatPMPDeviceSingletonRef;
|
public java.lang.String | intArrayString(int[] buf)
StringBuffer sb = new StringBuffer();
for(int i = 0; i < buf.length; i++) {
sb.append(buf[i]).append(" ");
}
return sb.toString();
|
public byte[] | intToByteArray(int v)Convert a 32-bit int into a 4 byte array
byte b[] = new byte[4];
int i, shift;
for(i = 0, shift = 24; i < 4; i++, shift -= 8)
b[i] = (byte)(0xFF & (v >> shift));
return b;
|
protected void | log(java.lang.String str)
adapter.log( str );
|
public int | portMappingProtocol(boolean tcp, int publicPort, int privatePort, int lifetime)General port mapping protocol
byte NATOp = (tcp?NATOp_MapTCP:NATOp_MapUDP);
// Should check for errors - only using lower 2 bytes
byte pubPort[] = intToByteArray(publicPort);
byte priPort[] = intToByteArray(privatePort);
byte portLifeTime[] = intToByteArray(lifetime);
// Generate Port Map request packet
byte dstBuf[] = new byte[NATPortMapRequestLen];
dstBuf[0] = NATMAP_VER; // Ver
dstBuf[1] = NATOp; // OP
dstBuf[2] = 0; // Reserved - 2 bytes
dstBuf[3] = 0;
dstBuf[4] = priPort[2]; // Private Port - 2 bytes
dstBuf[5] = priPort[3];
dstBuf[6] = pubPort[2]; // Requested Public Port - 2 bytes
dstBuf[7] = pubPort[3];
for (int i = 0; i < 4; i++) {
dstBuf[8 + i] = portLifeTime[i];
}
DatagramPacket dstPkt = new DatagramPacket(dstBuf, dstBuf.length);
byte recBuf[] = new byte[NATPortMapReplyLen];
/* DatagramPacket recPkt = */ sendNATMsg(natPriInet, dstPkt, recBuf);
// Unpack this and check codes
//int recVers = unsigned8ByteArrayToInt( recBuf, 0 );
int recOP = unsigned8ByteArrayToInt( recBuf, 1 );
int recCode = unsigned16ByteArrayToInt( recBuf, 2 );
int recEpoch = unsigned32ByteArrayToInt( recBuf, 4);
//int recPriPort = unsigned16ByteArrayToInt( recBuf, 8 );
int recPubPort = unsigned16ByteArrayToInt( recBuf, 10 );
int recLifetime = unsigned32ByteArrayToInt( recBuf, 12);
/**
* Should save the epoch. This can be used to determine the
* time the mapping will be deleted.
**/
log("Seconds since Start of Epoch: " + recEpoch);
log("Returned Mapped Port Lifetime: " + recLifetime);
if ( recCode != 0 )
throw( new Exception( "An error occured while getting a port mapping: " + recCode ) );
if ( recOP != ( NATOp + 128) )
throw( new Exception( "Received the incorrect port type: " + recOP) );
if ( lifetime != recLifetime )
log("Received different port life time!");
return recPubPort;
|
public java.net.DatagramPacket | sendNATMsg(java.net.InetAddress dstInet, java.net.DatagramPacket dstPkt, byte[] recBuf)Send a request and wait for reply
This class should be threaded!!!
This sends to the default NATPMP_PORT.
int retryInterval = NATMAP_INIT_RETRY;
boolean recRep = false;
DatagramSocket skt = new DatagramSocket();
skt.connect( dstInet, NATMAP_PORT );
skt.setSoTimeout( NATMAP_INIT_RETRY );
skt.send(dstPkt); // how do we know we hit something?
DatagramPacket recPkt = new DatagramPacket(recBuf, recBuf.length);
// We have several tries at this (like 3)
while ( !recRep && (retryInterval < NATMAP_MAX_RETRY) ) {
try {
skt.receive(recPkt);
recRep = true;
} catch (SocketTimeoutException ste) {
//log("Timed Out!");
//log( ste.getMessage() );
// sleep before trying again
// this.sleep(retryInterval);
Thread.sleep(retryInterval); // not sleeping?!?
// increase retry interval
retryInterval += (retryInterval * 2);
}
}
if ( !recRep ){
throw( new PortUnreachableException());
}
// check recRep for true!!!
return recPkt;
|
public byte[] | shortToByteArray(short v)Convert a 16-bit short into a 2 byte array
byte b[] = new byte[2];
b[0] = (byte) ( 0xFF & (v >> 8) );
b[1] = (byte) ( 0xFF & (v >> 0) );
return b;
|
public static int | unsigned16ByteArrayToInt(byte[] b, int offset)Convert the byte array containing 16-bits to an int starting from
the given offset.
int value = 0;
for (int i = 0; i < 2; i++) {
int shift = (2 - 1 - i) * 8;
value += ( (int) b[i + offset] & 0xFF) << shift;
}
return value;
|
public static int | unsigned32ByteArrayToInt(byte[] b, int offset)Convert the byte array containing 32-bit to an int starting from
the given offset.
int value = 0;
for (int i = 0; i < 4; i++) {
int shift = (4 - 1 - i) * 8;
value += ( (int) b[i + offset] & 0xFF) << shift;
}
return value;
|
public static int | unsigned8ByteArrayToInt(byte[] b, int offset)Convert the byte array containing 8-bits to an int starting from
the given offset.
return (int) b[offset] & 0xFF;
|
public short | unsignedByteArrayToShort(byte[] buf)
if (buf.length == 2) {
int i;
i = ( ( ( (int) buf[0] & 0xFF) << 8) | ( (int) buf[1] & 0xFF) );
return (short) i;
}
return -1;
|