Package xnap.plugin.nap.net

Source Code of xnap.plugin.nap.net.NapListener

/*
*  Java Napster version x.yz (for current version number as well as for
*  additional information see version.txt)
*
*  Previous versions of this program were written by Florian Student
*  and Michael Ransburg available at www.weblicity.de/jnapster and
*  http://www.tux.org/~daneel/content/projects/10.shtml respectively.
*
*
*  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
*
*/
package xnap.plugin.nap.net;

import xnap.plugin.nap.net.msg.MessageHandler;
import xnap.plugin.nap.net.msg.client.ChangeDataPortMessage;
import xnap.util.*;
import xnap.io.*;

import java.io.*;
import java.net.*;
import java.util.*;
import org.apache.log4j.Logger;

// FIX: a DOS attack is easily possible by connecting to the listener
// and not sending data
public class NapListener  {

    //--- Constant(s) ---

  /**
   *
   */
  public static int SOCKET_TIMEOUT = 30 * 1000;

    //--- Data field(s) ---

    protected static Logger logger = Logger.getLogger(ListenerThread.class);

    private LinkedList sockets = new LinkedList();
    private Object lock = new Object();
    private PortRange range = null;
    private ListenerThread runner = null;
   
    //--- Constructor(s) ---
   
    public NapListener(PortRange range)
    {
  setPortRange(range);
    }

    public NapListener()
    {
    }
   
    //--- Method(s) ---
   
    protected void addSocket(IncomingSocket s)
    {
  synchronized (lock) {
      sockets.add(s);
      lock.notifyAll();
  }
    }

    public int getPort()
    {
  return (runner != null) ? runner.getPort() : 0;
    }

    public void die()
    {
  if (runner != null) {
      runner.die();
      runner = null;
  }
    }

    private void start(int port)
    {
  if (range != null) {
      ServerSocket socket = null;

      if (port != 0) {
    try {
        // try to open the socket on port first
        socket = new ServerSocket(port);
    }
    catch (IOException e) {
    }
      }

      if (socket == null) {
    // bind to next free port
    for (PortRange.IntIterator i = range.random(); i.hasNext();) {
        try {
      socket = new ServerSocket(i.next());
      break;
        }
        catch (IOException e) {
        }
    }
      }

      if (socket != null) {
    runner = new ListenerThread(socket);
    runner.start();
      }
      else {
    logger.debug("could not start listener on "
           + range.toString());
      }
  }
    }

    private void restart(int port)
    {
  int oldPort = getPort();

  die();
  start(port);

  if (oldPort != getPort()) {
      // notify servers of changed port
      MessageHandler.send(new ChangeDataPortMessage(getPort()));
  }

    }

    private void restart()
    {
  restart(0);
    }
   
    /**
     * Sets a new port range and restarts socket thread if needed.
     */
    public void setPortRange(PortRange newValue)
    {
  PortRange oldValue = range;
  range = newValue;
 
  if (newValue != null && newValue.contains(getPort())) {
      // no need to restart the listener
      return;
  }

  restart();
    }

    public IncomingSocket waitForSocket(IncomingSocket is, long timeout)
    {
  long startTime = System.currentTimeMillis();
  while (true) {
      synchronized(lock) {
    for (Iterator i = sockets.iterator(); i.hasNext();) {
        IncomingSocket s = (IncomingSocket)i.next();
        if (s.equals(is)) {
      i.remove();
      return s;
        }
    }

    long timeLeft
        = timeout - (System.currentTimeMillis() - startTime);
    if (timeLeft <= 0) {
        return null;
    }

    try {
        lock.wait(timeLeft);
    }
    catch (InterruptedException e) {
        // someone wants to abort
        return null;
    }
      }
  }
    }
    //--- Inner Class(es) ---

    private class ListenerThread extends Thread {
 
  private ServerSocket listenerSocket = null;
  private boolean die = false;
 
  public ListenerThread(ServerSocket listenerSocket)
  {
      super("OpenNapListener :" + listenerSocket.getLocalPort());
     
      this.listenerSocket = listenerSocket;
  }

  public void die()
  {
      die = true;
  }

  public int getPort()
  {
      return listenerSocket.getLocalPort();
  }

  private void handleSocket(Socket s)
  {
      InputStream in = null;
      OutputStream out = null;
     
      try {
    in = new BufferedInputStream(s.getInputStream());
    out = s.getOutputStream();
   
    out.write('1');
    out.flush();
   
    byte data[] = new byte[2048];
    in.mark(8);
    int i = in.read(data, 0, 8);
   
    if (i > 0) {
        String response = new String(data, 0, i);
       
        logger.debug("received: " + response);
        in.reset();
       
        if (response.startsWith("GETLIST")) {
      in.skip(7);
      DirectBrowseUpload u = new DirectBrowseUpload(s);
      u.start();
        }
        else if (response.startsWith("GET")) {
      in.skip(3);
      addSocket(new UploadSocket(s, in));
        }
        else if (response.startsWith("SENDLIST")) {
      // add to queue for reverse direct browse threads
      in.skip(8);
      addSocket(new BrowseSocket(s, in));
        }
        else if (response.startsWith("SEND")) {
      in.skip(4);
      // add to queue for reverse download threads
      addSocket(new DownloadSocket(s, in));
        }
        else {
      throw new IOException("invalid request: " + response);
        }

    }
    else {
        throw new IOException("empty request");
    }
      }
      catch (IOException e) {
    logger.warn("invalid listener request", e);
   
    try {
        if (s != null) {
      s.close();
        }
        if (in != null) {
      in.close();
        }
        if (out != null) {
      out.close();
        }
    }
    catch (IOException ioe) {
    }
      }
  }
 

  public void run()
  {
      boolean restart = false;
      logger.debug("started listener on port " + getPort());
     
      try {
    listenerSocket.setSoTimeout(10 * 1000);
      }
      catch(SocketException e) {
    restart = true;
    die = true;
      }
     
      while(!die) {
    Socket socket = null;
    try {
        socket = listenerSocket.accept();
        // only wait a few seconds for a request, otherwise
        // the listener can be blocked forever
        socket.setSoTimeout(SOCKET_TIMEOUT);
    }
    catch(InterruptedIOException e) {
        continue;   
    }
    catch(IOException e) {
        restart = true;
        break;
    }
   
    if (socket != null) {
        handleSocket(socket);
    }
      }
 
      try {
    listenerSocket.close();
      }
      catch(IOException e) {
      }

      logger.debug("stopped listener on port " + getPort());
     
      if (restart) {
    // the thread has died unexpectively, restart it
    logger.debug("listener died unexpectively, restarting");
    restart(getPort());
      }
  }
 
    }

}
TOP

Related Classes of xnap.plugin.nap.net.NapListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.