⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 natpmpdeviceimpl.java

📁 这是一个基于java编写的torrent的P2P源码
💻 JAVA
📖 第 1 页 / 共 2 页
字号:
/*
 * Created on 12-Jun-2006
 * Created by Marc Colosimo
 * Copyright (C) 2004, 2005, 2006 Aelitis, All Rights Reserved.
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 * 
 * AELITIS, SAS au capital de 46,603.30 euros
 * 8 Allee Lenotre, La Grille Royale, 78600 Le Mesnil le Roi, France.
 *
 * Connection class for NAT-PMP (Port Mapping Protocol) Devices
 * 
 * @see <http://files.dns-sd.org/draft-cheshire-nat-pmp.txt>
 * Tested with <https://www.grc.com/x/portprobe=6881>
 * 
 * This code is ugly, but it works.
 *
 * Some assumptions: 
 *  - The NAT device will be at xxx.xxx.xxx.1
 * 
 * This needs to be threaded. 
 *  - It could take upto 2 minutes to timeout during any request
 *  - We need to listen for address changes (using link-local multicast?)!
 *  - We need to request the mapping again before it expires
 *
 * Some hints and to dos:
 *  - The draft spec says that the device could set max lease life time  
 *    to be less than requested. this should be checked.
 *  - Need to make something to renew port mappings - recommend that 
 *    the client SHOULD begin trying to renew the mapping halfway to *
 *    expiry time, like DHCP
 *  - Need to listen for public address changes
 *
 * Version 0.1b
 */

package com.aelitis.net.natpmp.impl;

import java.net.*;

import com.aelitis.azureus.core.util.NetUtils;
import com.aelitis.net.natpmp.NATPMPDeviceAdapter;
import com.aelitis.net.natpmp.NatPMPDevice;

/**
 *
 * Main class
 *
 * */
public class NatPMPDeviceImpl implements NatPMPDevice
{

    static final int NATMAP_VER = 0;
    static final int NATMAP_PORT = 5351;
    static final int NATMAP_RESPONSE_MASK = 128;
    static final int NATMAP_INIT_RETRY = 250;     // ms
    static final int NATMAP_MAX_RETRY = 2250;     // gives us three tries
    
    // lease life in seconds
    // 24 hours
    static final int NATMAP_DEFAULT_LEASE = 60*60*24;  
         
    // link-local multicast address - for address changes
    // not implemented
    static final String NATMAP_LLM = "224.0.0.1";    
   
    // Opcodes used for ..
    static final byte NATOp_AddrRequest = 0; // Ask for a NAT-PMP device
    static final byte NATOp_MapUDP = 1;      // Map a UDP Port
    static final byte NATOp_MapTCP = 2;      // Map a TCP Port
    
    /* Length of Requests in bytes */
    static final int NATAddrRequest = 2;
    static final int NATPortMapRequestLen  = 4 * 3;  // 4 bytes by 3
       
    /* Length of Replies in Bytes */
    static final int NATAddrReplyLen       = 4 * 3;  
    static final int NATPortMapReplyLen    = 4 * 4; 
    
    /* Current Result Codes */
    static final int NATResultSuccess = 0;
    static final int NATResultUnsupportedVer = 1;
    /** 
     * Not Authorized/Refused
     * (e.g. box supports mapping, but user has turned feature off)
     **/
    static final int NATResultNotAuth = 2; 
    /**
     * Network Failure
     * (e.g. NAT box itself has not obtained a DHCP lease)
     **/
    static final int NATResultNetFailure = 3;
    static final int NATResultNoResc = 4; // Out of resources
    static final int NATResultUnsupportedOp = 5;  // Unsupported opcode
    
    /* Instance specific globals */
    String		current_router_address	= "?";
    InetAddress hostInet;        // Our address
    InetAddress natPriInet;      // NAT's private (interal) address      
    InetAddress natPubInet;      // NAT's public address
    NetworkInterface networkInterface;	// natPriInet network interface
    InetAddress llmInet;
    
    boolean nat_pmp_found = false;
    int nat_epoch = 0;           // This gets updated each request
    
    private NATPMPDeviceAdapter	adapter;
    
    /**
     * Singleton creation
     **/
    private static NatPMPDeviceImpl NatPMPDeviceSingletonRef;
    
    public static synchronized NatPMPDeviceImpl
                    getSingletonObject(NATPMPDeviceAdapter adapter) throws Exception {
        if (NatPMPDeviceSingletonRef == null)
            NatPMPDeviceSingletonRef = new NatPMPDeviceImpl(adapter);
        return NatPMPDeviceSingletonRef;
    }
    
    private 
    NatPMPDeviceImpl(
    	NATPMPDeviceAdapter _adapter) 
    	
    	throws Exception 
    {
    	adapter		= _adapter;
        hostInet 	= NetUtils.getLocalHost();
        
        checkRouterAddress();
    }
    
    protected void
    checkRouterAddress()
    
    	throws Exception
    {
    	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 );
    }
    
    
    /**
     * Send a request and wait for reply 
     * This class should be threaded!!!
     *
     * This sends to the default NATPMP_PORT.
     *
     * @param dstInet destination address (should be the private NAT address)
     * @param dstPkt packet to send
     * @param recBuf byte buffer big enough to hold received
     **/
    public DatagramPacket sendNATMsg(InetAddress dstInet, DatagramPacket dstPkt, byte[] recBuf) throws Exception {
        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;
    }

    /**
     * Try to connect with a NAT-PMP device.
     * This could take sometime.
     *
     * @return true if it found one
     **/     
    public boolean connect() throws Exception {

   		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)   
	         **/
	         

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -