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

📄 stunprovider.java

📁 stun的java实现
💻 JAVA
字号:

/*
 * Stun4j, the OpenSource Java Solution for NAT and Firewall Traversal.
 *
 * Distributable under LGPL license.
 * See terms of license at gnu.org.
 */
package net.java.stun4j.stack;

import java.util.*;
import java.util.logging.*;
import net.java.stun4j.*;
import net.java.stun4j.message.*;

/**
 * The StunProvider class is an implementation of a Stun Transaction Layer. STUN
 * transactions are extremely simple and are only used to correlate requests and
 * responses. In the Stun4J implementation it is the transaction layer that
 * ensures reliable delivery.
 *
 * <p>Organisation: <p> Louis Pasteur University, Strasbourg, France</p>
 * <p>Network Research Team (http://www-r2.u-strasbg.fr)</p></p>
 * @author Emil Ivov
 * @version 0.1
 */

public class StunProvider
    implements MessageEventHandler
{
    private static final Logger logger =
        Logger.getLogger(StunProvider.class.getName());

    /**
     * Stores active client transactions mapped against TransactionID-s.
     */
    private Hashtable clientTransactions = new Hashtable();

    /**
     * Currently open server transactions. The vector contains transaction ids
     * for transactions corresponding to all non-answered received requests.
     */
    private Hashtable serverTransactions = new Hashtable();

    /**
     * The stack that created us.
     */
    private StunStack stunStack                  = null;

    /**
     * A dispatcher for incoming requests event;
     */
    private EventDispatcher  eventDispatcher    = new EventDispatcher();



    //------------------ public interface
    /**
     * Creates the provider.
     * @param stunStack The currently active stack instance.
     */
    StunProvider(StunStack stunStack)
    {
        this.stunStack = stunStack;
    }

    /**
     * Sends the specified request through the specified access point, and
     * registers the specified ResponseCollector for later notification.
     * @param  request     the request to send
     * @param  sendTo      the destination address of the request.
     * @param  sendThrough the access point to use when sending the request
     * @param  collector   the instance to notify when a response arrives or the
     *                     the transaction timeouts
     * @throws StunException
     * ILLEGAL_STATE if the stun stack is not started. <br/>
     * ILLEGAL_ARGUMENT if the apDescriptor references an access point that had
     * not been installed <br/>
     * NETWORK_ERROR if an error occurs while sending message bytes through the
     * network socket. <br/>

     */
    public void sendRequest( Request                  request,
                             StunAddress              sendTo,
                             NetAccessPointDescriptor sendThrough,
                             ResponseCollector        collector )
        throws StunException
    {
        stunStack.checkStarted();

        StunClientTransaction clientTransaction =
                                        new StunClientTransaction(this,
                                                                  request,
                                                                  sendTo,
                                                                  sendThrough,
                                                                  collector);

        clientTransactions.put(clientTransaction.getTransactionID(),
                               clientTransaction);
        clientTransaction.sendRequest();
    }

    /**
     * Sends the specified response message through the specified access point.
     *
     * @param transactionID the id of the transaction to use when sending the
     *    response. Actually we are getting kind of redundant here as we already
     *    have the id in the response object, but I am bringing out as an extra
     *    parameter as the user might otherwise forget to explicitly set it.
     * @param response      the message to send.
     * @param sendThrough   the access point to use when sending the message.
     * @param sendTo        the destination of the message.
     * @throws StunException TRANSACTION_DOES_NOT_EXIST if the response message
     * has an invalid transaction id. <br/>
     * ILLEGAL_STATE if the stun stack is not started. <br/>
     * ILLEGAL_ARGUMENT if the apDescriptor references an access point that had
     * not been installed <br/>
     * NETWORK_ERROR if an error occurs while sending message bytes through the
     * network socket. <br/>
     */
    public void sendResponse(byte[]                   transactionID,
                             Response                 response,
                             NetAccessPointDescriptor sendThrough,
                             StunAddress                  sendTo)
        throws StunException
    {
        stunStack.checkStarted();

        TransactionID tid = TransactionID.createTransactionID(transactionID);
        StunServerTransaction sTran =
            (StunServerTransaction)serverTransactions.get(tid);

        if(sTran == null || sTran.isReransmitting()){
            throw new StunException(StunException.TRANSACTION_DOES_NOT_EXIST,
                                    "The transaction specified in the response "
                                    + "object does not exist or has already "
                                    + "transmitted a response.");
        }
        else{
            sTran.sendResponse(response, sendThrough, sendTo);
        }



    }

    /**
     * Sets the listener that should be notified when a new Request is received.
     * @param requestListener the listener interested in incoming requests.
     */
    public  void addRequestListener(RequestListener requestListener)
    {
        this.eventDispatcher.addRequestListener( requestListener );
    }

    /**
     * Removes the specified listener from the local listener list. (If any
     * instances of this listener have been registered for a particular
     * access point, they will not be removed).
     * @param listener the RequestListener listener to unregister
     */
    public void removeRequestListener(RequestListener listener)
    {
        this.eventDispatcher.removeRequestListener(listener);
    }

    /**
     * Add a RequestListener for requests coming from a specific NetAccessPoint.
     * The listener will be invoked only when a request event is received on
     * that specific property.
     *
     * @param apDescriptor  The descriptor of the NetAccessPoint to listen on.
     * @param listener  The ConfigurationChangeListener to be added
     */

    public synchronized void addRequestListener(
        NetAccessPointDescriptor apDescriptor,
        RequestListener listener)
    {
        eventDispatcher.addRequestListener(apDescriptor, listener);
    }



//------------- stack internals ------------------------------------------------
    /**
     * Returns the currently active instance of NetAccessManager. Used by client
     * transactions when sending messages.
     * @return the currently active instance of NetAccessManager.
     */
    NetAccessManager getNetAccessManager()
    {
        return stunStack.getNetAccessManager();
    }

    /**
     * Removes a client transaction from this providers client transactions list.
     * Method is used by StunClientTransaction-s themselves when a timeout occurs.
     * @param tran the transaction to remove.
     */
    synchronized void removeClientTransaction(StunClientTransaction tran)
    {
        clientTransactions.remove(tran.getTransactionID());
    }

    /**
     * Removes a server transaction from this provider's server transactions
     * list.
     * Method is used by StunServerTransaction-s themselves when they expire.
     * @param tran the transaction to remove.
     */
    synchronized void removeServerTransaction(StunServerTransaction tran)
    {
        serverTransactions.remove(tran.getTransactionID());
    }

    /**
     * Called to notify this provider for an incoming message.
     * @param event the event object that contains the new message.
     */
    public void handleMessageEvent(StunMessageEvent event)
    {
        Message msg = event.getMessage();

        if(logger.isLoggable(Level.FINEST))
            logger.finest("Received a message on NetAP"
                        + event.getSourceAccessPoint()
                        + " of type:"
                        + msg.getMessageType());

        //request
        if(msg instanceof Request)
        {
            TransactionID serverTid = TransactionID.
                                    createTransactionID(msg.getTransactionID());

            StunServerTransaction sTran  =
                (StunServerTransaction)serverTransactions.get(serverTid);
            if( sTran != null){
                //requests from this transaction have already been seen
                //retransmit the response if there was any
                try
                {
                    sTran.retransmitResponse();
                    logger.finest("Response retransmitted");
                }
                catch (StunException ex)
                {
                    //we couldn't really do anything here .. apart from logging
                    logger.log(Level.WARNING,
                               "Failed to retransmit a stun response", ex);
                }

                String propagate = System.getProperty(
                    "net.java.stun4j.PROPAGATE_RECEIVED_RETRANSMISSIONS");
                if(propagate == null || !propagate.trim().equalsIgnoreCase("true"))
                    return;
            }
            else{

                sTran =
                    new StunServerTransaction(this, serverTid);

                serverTransactions.put(serverTid, sTran);
                sTran.start();
            }
            eventDispatcher.fireMessageEvent(event);
        }
        //response
        else if(msg instanceof Response)
        {
            TransactionID tid = TransactionID.
                                    createTransactionID(msg.getTransactionID());

            StunClientTransaction tran =
                (StunClientTransaction)clientTransactions.remove(tid);

            if(tran != null)
            {
                tran.handleResponse(event);
            }
            else
            {
                //do nothing - just drop the phantom response.
                logger.fine("Dropped response - no matching client tran found.");
                logger.fine("response tid was - " + tid.toString());
                logger.fine("all tids in stock were" + clientTransactions.toString());
            }
        }

    }

    /**
     * Cancels all running transactions and prepares for garbage collection
     */
    void shutDown()
    {
        eventDispatcher.removeAllListeners();

        Enumeration tids = clientTransactions.keys();
        while (tids.hasMoreElements()) {
            TransactionID item = (TransactionID)tids.nextElement();
            StunClientTransaction tran =
                        (StunClientTransaction)clientTransactions.remove(item);
            if(tran != null)
                tran.cancel();

        }

        tids = serverTransactions.keys();
        while (tids.hasMoreElements()) {
            TransactionID item = (TransactionID)tids.nextElement();
            StunServerTransaction tran =
                        (StunServerTransaction)clientTransactions.remove(item);
            if(tran != null)
                tran.expire();

        }
    }

}

⌨️ 快捷键说明

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