Android Open Source - azilink Select Thread






From Project

Back to project page azilink.

License

The source code is released under:

GNU General Public License

If you think the Android project azilink listed in this page is inappropriate, such as containing malicious code/tools or violating the copyright, please email info at java2s dot com, thanks.

Java Source Code

/* AziLink: USB tethering for Android
 * Copyright (C) 2009 by James Perry/*from w w w . j  av  a 2 s  .  c  om*/
 *
 * 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) version 3 of the License.
 *
 * 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, see <http://www.gnu.org/licenses/>.
 */

package org.lfx.azilink.net;

import java.io.IOException;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.spi.SelectorProvider;
import java.util.Iterator;
import java.util.Set;
import android.os.SystemClock;
import android.util.Log;

/**
 * This is the main worker thread for the NAT engine.  It blocks in a standard select() loop
 * over all network connections, and also dispatches timer events.
 * 
 * @author Jim Perry
 *
 */
public class SelectThread implements Runnable {
  /** The Java NIO selector */
  Selector mSelector;
  /** Used to tell the select thread that it's time to terminate. */
  boolean mDie;
  /** Worker thread */
  Thread mThread = new Thread( this );
  /** Pointer to the actual NAT engine; used for callbacks. */
  VpnNatEngine mEngine;
  
  /**
   * Construct the select thread.  Does not start the thread.
   * @param engine pointer to the NAT engine
   */
  SelectThread( VpnNatEngine engine ) {
    mEngine = engine;
  }
  
  /**
   * Start the worker thread.
   * @throws IOException
   */
  void start() throws IOException {
    mSelector = SelectorProvider.provider().openSelector();
    mDie = false;
    mThread.start();
  }
  
  /**
   * Stop the worker thread, and wait for it to terminate.
   * @throws InterruptedException
   */
  void stop() throws InterruptedException {
    mDie = true;
    mSelector.wakeup();          
    mThread.join();
    try {
      mSelector.close();
    } catch (IOException e) {
    }
    mSelector = null;
  }  
  
  /**
   * Main select loop.
   */
  public void run() {
    try {
      // Attach the debugger to the new thread and automatically breakpoint:
      //   android.os.Debug.waitForDebugger();
      
      // Setup the listener socket (VPN)
      ServerSocketChannel fdCmd = ServerSocketChannel.open();
      fdCmd.socket().setReuseAddress( true );      
      fdCmd.configureBlocking( false );
      fdCmd.socket().bind( new InetSocketAddress( InetAddress.getByAddress( new byte[] { 127,0,0,1 } ), 41927 ) );
      fdCmd.register( mSelector, SelectionKey.OP_ACCEPT, new SocketHandler( fdCmd ) {
        /**
         * Notify the VPN engine that a new VPN connection has been made.
         */
        public void onAccept( SelectionKey k ) {
          mEngine.acceptServerLink( (ServerSocketChannel) k.channel() );
        }
      });
            
      // Main select loop
      for( ;; ) {
        // Ask the timer class when the next timeout is due to be dispatched.
        long nextTimeout = mEngine.mTimers.nextTimer();
        
        if( nextTimeout >= 0 ) {
          // There's a pending timeout, so select() over that interval
          if(VpnNatEngine.sLog) Log.v("AziLink", "SelectThread timeout: " + (nextTimeout - SystemClock.elapsedRealtime()));
          mSelector.select( Math.max(nextTimeout - SystemClock.elapsedRealtime(), 1) );
        } else {
          // No pending timeouts, so just select() until something exciting happens.
          if(VpnNatEngine.sLog) Log.v("AziLink", "SelectThread no timeout" );
          mSelector.select();
        }
        
        // Main thread is asking is to terminate.
        if( mDie ) {
          break;
        }
        
        // If a timeout has occured, then issue callbacks to the relevent classes.
        if( SystemClock.elapsedRealtime() >= nextTimeout ) {
          mEngine.mTimers.runTimers();          
        }
        
        // Lock to prevent the UI from screwing with the selector table (does it still actually do this?)
        synchronized(this) {
          // Iterate over all connections that have some sort of activity
          Set<SelectionKey> rdy = mSelector.selectedKeys();
          Iterator<SelectionKey> i = rdy.iterator();
          while( i.hasNext() ) {
            SelectionKey k = i.next();
            i.remove();
            if( !k.isValid() ) continue;    // Key could be cancelled
            SocketHandler h = (SocketHandler) k.attachment();
            int op = k.readyOps();
            try {
              // Figure out what happens and dispatch it to the thread.  Don't change
              // the order unless you know what you're doing!
              if( (op & SelectionKey.OP_WRITE) != 0 ) h.onWrite( k );
              if( (op & SelectionKey.OP_READ) != 0 ) h.onRead( k );              
              if( (op & SelectionKey.OP_ACCEPT) != 0 ) h.onAccept( k );
              if( (op & SelectionKey.OP_CONNECT) != 0 ) h.onConnect( k );            
            } catch( IOException e ) {
              try {
                k.channel().close();
              } catch( IOException e2 ) {                
              }
            }
          }
        }
      }
    } catch (IOException e) {
      if(VpnNatEngine.sLog) Log.v("AziLink", "Terminating due to exception" );
      mEngine.selectError( e.toString() );
    }
    // Thread is terminating.  Close all connections!
    Set<SelectionKey> allKeys = mSelector.keys();
    Iterator<SelectionKey> i = allKeys.iterator();
    while( i.hasNext() ) {
      SelectionKey k = i.next();
      try {
        k.channel().close();
      } catch (IOException e ) {}
    }
  }
}




Java Source Code List

org.lfx.azilink.AboutActivity.java
org.lfx.azilink.BootActivity.java
org.lfx.azilink.ForwardService.java
org.lfx.azilink.LinkStatistics.java
org.lfx.azilink.MainActivity.java
org.lfx.azilink.Reflection.java
org.lfx.azilink.net.IcmpKey.java
org.lfx.azilink.net.IcmpPacket.java
org.lfx.azilink.net.SelectThread.java
org.lfx.azilink.net.SocketHandler.java
org.lfx.azilink.net.TcpDriverCallback.java
org.lfx.azilink.net.TcpDriverImpl.java
org.lfx.azilink.net.TcpDriverPacketSink.java
org.lfx.azilink.net.TcpDriver.java
org.lfx.azilink.net.TcpEngine.java
org.lfx.azilink.net.TcpKey.java
org.lfx.azilink.net.TcpPacket.java
org.lfx.azilink.net.TcpToNio.java
org.lfx.azilink.net.TimerCallback.java
org.lfx.azilink.net.TimerQueue.java
org.lfx.azilink.net.TmAccept.java
org.lfx.azilink.net.TransferStatistics.java
org.lfx.azilink.net.UdpDriver.java
org.lfx.azilink.net.UdpEngine.java
org.lfx.azilink.net.UdpKey.java
org.lfx.azilink.net.UdpPacket.java
org.lfx.azilink.net.VpnLink.java
org.lfx.azilink.net.VpnNatEngineNotify.java
org.lfx.azilink.net.VpnNatEngine.java