Package org.jmule.core.networkmanager

Source Code of org.jmule.core.networkmanager.JMPeerConnection$SenderThread

/*
*  JMule - Java file sharing client
*  Copyright (C) 2007-2009 JMule team ( jmule@jmule.org / http://jmule.org )
*
*  Any parts of this program derived from other projects, or contributed
*  by third-party developers are copyrighted by their respective authors.
*
*  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., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
*
*/
package org.jmule.core.networkmanager;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousCloseException;
import java.nio.channels.SocketChannel;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;

import org.jmule.core.JMException;
import org.jmule.core.JMThread;
import org.jmule.core.configmanager.ConfigurationManager;
import org.jmule.core.edonkey.E2DKConstants;
import org.jmule.core.edonkey.packet.Packet;
import org.jmule.core.utils.Convert;
import org.jmule.core.utils.JMuleZLib;
import org.jmule.core.utils.Misc;

/**
* Created on Aug 16, 2009
* @author binary256
* @author javajox
* @version $Revision: 1.14 $
* Last changed by $Author: binary255 $ on $Date: 2010/01/12 14:42:36 $
*/
public final class JMPeerConnection extends JMConnection {

  private JMuleSocketChannel jm_socket_channel;
 
  private JMThread connecting_thread;
  private JMThread receiver_thread;
 
  private volatile SenderThread sender_thread;
  private volatile Queue<Packet> send_queue = new ConcurrentLinkedQueue<Packet>();
 
  volatile int usePort = 0;
 
  private InetSocketAddress remote_inet_socket_address;
   
  private InternalNetworkManager _network_manager = (InternalNetworkManager) NetworkManagerSingleton.getInstance();
 
  private ConnectionStatus connection_status = ConnectionStatus.DISCONNECTED; 
 
  private long uploadedFileBytes = 0;
 
  JMPeerConnection(InetSocketAddress remoteInetSocketAddress) {
    remote_inet_socket_address = remoteInetSocketAddress;
  }
 
  JMPeerConnection(JMuleSocketChannel peerConnection) throws NetworkManagerException {
    jm_socket_channel = peerConnection;
    remote_inet_socket_address = (InetSocketAddress) jm_socket_channel.getSocket().getRemoteSocketAddress();
    _network_manager.addPeer(this);
    connection_status = ConnectionStatus.CONNECTED;
    send_queue.clear();
    createSenderThread();
    sender_thread.start();
   
    createReceiverThread();
    receiver_thread.start();
  }
 
  JMPeerConnection(String ipAddress, int port) {
    remote_inet_socket_address = new InetSocketAddress(ipAddress, port);
  }
 
  void connect() {
    connecting_thread = new JMThread() {
      public void JMStop() {
      }
      public void run() {
        try {
          connection_status = ConnectionStatus.CONNECTING;
          jm_socket_channel = new JMuleSocketChannel(SocketChannel
              .open());
          jm_socket_channel.connect(remote_inet_socket_address,
              ConfigurationManager.PEER_CONNECTING_TIMEOUT);

          connection_status = ConnectionStatus.CONNECTED;
          send_queue.clear();
          createSenderThread();
          sender_thread.start();
         
          createReceiverThread();
          receiver_thread.start();
         
          _network_manager.peerConnected(remote_inet_socket_address.getAddress().getHostAddress(),remote_inet_socket_address.getPort());

        } catch (IOException cause) {
          cause.printStackTrace();
          connection_status = ConnectionStatus.DISCONNECTED;
          int port = remote_inet_socket_address.getPort();
          if (usePort!=0)
            port = usePort;
          _network_manager.peerConnectingFailed(remote_inet_socket_address.getAddress().getHostAddress(),port, cause);
        }
      }

    };

    connecting_thread.start();
  }
 
  private void createReceiverThread() {
    receiver_thread = new JMThread() {
     
      private boolean stop_thread = false;

      public void JMStop() {
        stop_thread = true;
      }

      public void run() {
        while (!stop_thread) {
          try {
            PacketReader.readPeerPacket(jm_socket_channel,usePort);
          } catch (Throwable cause) {
            if (cause instanceof JMEndOfStreamException)
              notifyDisconnect(); else
            if (cause instanceof AsynchronousCloseException)
              return ;
            else {
              JMException exception = new JMException("Exception in connection " + remote_inet_socket_address+"\n"+Misc.getStackTrace(cause));
              exception.printStackTrace();
            }
          }
        }
      }
    };
  }
 
  private void createSenderThread() {
    sender_thread = new SenderThread();
  }

  void disconnect() throws NetworkManagerException {
    if (connection_status == ConnectionStatus.CONNECTED) {
      try {
        jm_socket_channel.close();
        connection_status = ConnectionStatus.DISCONNECTED;
      } catch (IOException cause) {
        throw new NetworkManagerException(cause);
      }
      receiver_thread.JMStop();
      sender_thread.JMStop();
      send_queue.clear();
    }
   
    if (connection_status == ConnectionStatus.CONNECTING) {
      try {
        jm_socket_channel.close();
        connection_status = ConnectionStatus.DISCONNECTED;
      } catch (IOException cause) {
        throw new NetworkManagerException(cause);
      }
    }
    jm_socket_channel = null;
  }
 
  String getIPAddress() {
    return remote_inet_socket_address.getAddress().getHostAddress();
  }
 
  JMuleSocketChannel getJMConnection() {
    return jm_socket_channel;
  }
 
  int getPort() {
    return remote_inet_socket_address.getPort();
  }
 
  ConnectionStatus getStatus() {
    return connection_status;
  }
 
  private void notifyDisconnect() {
    connection_status = ConnectionStatus.DISCONNECTED;
    int port = jm_socket_channel.getSocket().getPort();
    if (usePort!=0)
      port = usePort;
    String peerIP = Convert.IPtoString(jm_socket_channel.getChannel().socket().getInetAddress().getAddress());
    _network_manager.peerDisconnected(peerIP, port);
   
    receiver_thread.JMStop();
  }
 
  void send(Packet packet) throws JMException {
    if (connection_status != ConnectionStatus.CONNECTED)
      throw new JMException("Not connected to " + remote_inet_socket_address);
    send_queue.add(packet);
    if (sender_thread.isSleeping()) {
      sender_thread.wakeUp();
    }
  }
 
  private void sendPacket(Packet packet) throws Exception {
    try {
      if ((!E2DKConstants.PEER_PACKETS_NOT_ALLOWED_TO_COMPRESS.contains(
        packet.getCommand()))
        && (packet.getLength() >= E2DKConstants.PACKET_SIZE_TO_COMPRESS)) {
        byte op_code = packet.getCommand();
        ByteBuffer raw_data = Misc.getByteBuffer(packet.getLength()-1-4-1);
        ByteBuffer data = packet.getAsByteBuffer();
        data.position(1 + 4 + 1);
        raw_data.put(data);
        raw_data.position(0);
        raw_data = JMuleZLib.compressData(raw_data);
        packet = new Packet(raw_data.capacity(), E2DKConstants.PROTO_EMULE_COMPRESSED_TCP);
        packet.setCommand(op_code);
        raw_data.position(0);
        packet.insertData(raw_data);
      }
//      System.out.println("Send packet to peer : " + getIPAddress() + " : " + getPort() +" Header : " + Convert.byteToHex(packet.getProtocol()) + " opcode : " + Convert.byteToHex(packet.getCommand()));
      if(jm_socket_channel.write(packet.getAsByteBuffer()) == -1 )
          notifyDisconnect();
      if (packet.getCommand() == E2DKConstants.OP_SENDINGPART) {
        uploadedFileBytes += packet.getLength() - 16 + 4 + 4;
      }
    }catch(Throwable cause) {
      if (!jm_socket_channel.isConnected())
        notifyDisconnect();
      throw new JMException("Exception in connection : " +remote_inet_socket_address + "\n"+Misc.getStackTrace(cause));
    }
  }
 
  public long getUploadedFileBytes() {
    return uploadedFileBytes;
  }
 
  void resetUploadedFileBytes() {
    uploadedFileBytes = 0;
  }
 
  public String toString() {
    return "Peer connection to : " +  remote_inet_socket_address + " Status : " + connection_status;
  }
 
  private class SenderThread extends JMThread {
   
    private volatile boolean loop = true;
    private volatile boolean is_sleeping = false;
    public SenderThread() {
      super("Peer packet sender for " + remote_inet_socket_address);
    }
   
    public void run() {
      while(loop) {
        is_sleeping = false;
        if (!jm_socket_channel.isConnected()) break;
        if (send_queue.isEmpty()) {
          is_sleeping = true;
          synchronized(this) {
            try {
              this.wait();
            } catch (InterruptedException e) {
            }
          }
          continue;
        }
        Packet packet = send_queue.poll();
        try {
          sendPacket(packet);
        } catch (Exception e) {
          if (!jm_socket_channel.isConnected()) break;
        }
       
      }
    }
    public void JMStop() {
      loop = false;
      synchronized(this) {
        this.notify();
      }
    }
    public boolean isSleeping() { return is_sleeping; }
    public void wakeUp() {
      synchronized(this) {
        this.notify();
      }
    }
   
  }
 
}
TOP

Related Classes of org.jmule.core.networkmanager.JMPeerConnection$SenderThread

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.