// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/conn/MultiplexedConnection.java
// public class MultiplexedConnection {
// 
//     private final Multiplexer multiplexer;
// 
//     private final short connectionID;
// 
//     private final PacketSender packetSender;
// 
//     private final Queue<Frame> frameQueue = new LinkedList<>();
// 
//     private volatile boolean alive = true;
// 
//     private volatile boolean stopSend = false;
// 
//     private final Object closeLock = new Object();
// 
//     private final Object frameLock = new Object();
// 
//     private volatile int bufSize = 0;
// 
//     private volatile boolean remotePauseSend = false; //Told remote to stop send
// 
//     private volatile boolean localPauseSend = false; //Remote told to stop send
// 
//     private final Object sendLock = new Object();
// 
//     public MultiplexedConnection(final Multiplexer multiplexer, final short connectionID, final PacketSender packetSender) {
//         this.multiplexer = multiplexer;
//         this.connectionID = connectionID;
//         this.packetSender = packetSender;
//     }
// 
//     protected void addFrame(final Frame frame) {
//         if (alive) {
//             synchronized (frameLock) {
//                 frameQueue.add(frame);
// 
//                 if (frame instanceof DataFrame) {
//                     bufSize += ((DataFrame) frame).getData().length;
//                     if (bufSize > MuxGlobalConstants.CONNECTION_MAX_DATA_BUFFER_SIZE && !remotePauseSend) {
//                         remotePauseSend = true;
//                         packetSender.sendPacket(new PauseConnectionFrame(connectionID).toBytes());
//                     }
//                 }
// 
//                 frameLock.notifyAll();
//             }
//         }
//     }
// 
//     private byte[] readRaw() throws InterruptedException, ConnectionNotAliveException {
//         if (alive) {
//             Frame frame;
//             synchronized (frameLock) {
//                 while ((frame = frameQueue.poll()) == null && alive) {
//                     frameLock.wait();
//                 }
//             }
// 
//             if (frame == null) {
//                 throw new ConnectionNotAliveException();
//             }
// 
//             if (frame instanceof DataFrame) {
//                 final byte[] data = ((DataFrame) frame).getData();
// 
//                 synchronized (frameLock) {
//                     bufSize -= data.length;
//                     if (bufSize < MuxGlobalConstants.CONNECTION_MAX_DATA_BUFFER_SIZE && remotePauseSend) {
//                         remotePauseSend = false;
//                         packetSender.sendPacket(new ContinueConnectionFrame(connectionID).toBytes());
//                     }
//                 }
// 
//                 return data;
//             } else if (frame instanceof CloseConnectionFrame) {
//                 close();
//                 return null;
//             } else {
//                 return null;
//             }
//         } else {
//             throw new ConnectionNotAliveException();
//         }
//     }
// 
//     public byte[] read() throws ConnectionNotAliveException, InterruptedException {
//         byte[] tmp = null;
//         while (tmp == null) {
//             tmp = readRaw();
//         }
//         return tmp;
//     }
// 
//     private boolean canSend() {
//         return alive && !stopSend;
//     }
// 
//     public void send(final byte[] bytes) throws SenderClosedException, InterruptedException {
//         if (canSend()) {
//             synchronized (sendLock) {
//                 while (localPauseSend && canSend()) {
//                     sendLock.wait();
//                 }
//             }
//             packetSender.sendPacket(new DataFrame(connectionID, bytes).toBytes());
//         } else {
//             throw new SenderClosedException();
//         }
//     }
// 
//     protected void pauseSend() {
//         localPauseSend = true;
//     }
// 
//     protected void continueSend() {
//         localPauseSend = false;
//         synchronized (sendLock) {
//             sendLock.notifyAll();
//         }
//     }
// 
//     public boolean isAlive() {
//         return alive;
//     }
// 
//     public short getID() {
//         return connectionID;
//     }
// 
//     protected void closeSender() {
//         stopSend = true;
//     }
// 
//     public void close() {
//         close_impl(true);
//     }
// 
//     protected void closeNoRemove() {
//         close_impl(false);
//     }
// 
//     private void close_impl(final boolean removeFromMap) {
//         synchronized (closeLock) {
//             if (alive) {
// 
//                 packetSender.sendPacket(new CloseConnectionFrame(connectionID).toBytes());
// 
//                 alive = false;
// 
//                 continueSend();
// 
//                 if (removeFromMap) multiplexer.removeConnectionFromMap(connectionID);
// 
//                 synchronized (frameLock) {
//                     frameQueue.clear();
//                     frameLock.notifyAll();
//                 }
// 
//             }
//         }
//     }
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionNotAliveException.java
// public class ConnectionNotAliveException extends MuxException {
// 
//     public ConnectionNotAliveException() {
//         super("Connection is not alive");
//     }
// 
//     public ConnectionNotAliveException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/SenderClosedException.java
// public class SenderClosedException extends MuxException {
// 
//     public SenderClosedException() {
//         super("Sender closed");
//     }
// 
//     public SenderClosedException(final String msg) {
//         super(msg);
//     }
// 
// }


import com.vecsight.dragonite.mux.conn.MultiplexedConnection;
import com.vecsight.dragonite.mux.exception.ConnectionNotAliveException;
import com.vecsight.dragonite.mux.exception.SenderClosedException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
/*
 * The Dragonite Project
 * -------------------------
 * See the LICENSE file in the root directory for license information.
 */


package com.vecsight.dragonite.forwarder.network;



public class Pipe {

    private final short bufferSize;

    public Pipe(final short bufferSize) {
        this.bufferSize = bufferSize;
    }

// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/conn/MultiplexedConnection.java
// public class MultiplexedConnection {
// 
//     private final Multiplexer multiplexer;
// 
//     private final short connectionID;
// 
//     private final PacketSender packetSender;
// 
//     private final Queue<Frame> frameQueue = new LinkedList<>();
// 
//     private volatile boolean alive = true;
// 
//     private volatile boolean stopSend = false;
// 
//     private final Object closeLock = new Object();
// 
//     private final Object frameLock = new Object();
// 
//     private volatile int bufSize = 0;
// 
//     private volatile boolean remotePauseSend = false; //Told remote to stop send
// 
//     private volatile boolean localPauseSend = false; //Remote told to stop send
// 
//     private final Object sendLock = new Object();
// 
//     public MultiplexedConnection(final Multiplexer multiplexer, final short connectionID, final PacketSender packetSender) {
//         this.multiplexer = multiplexer;
//         this.connectionID = connectionID;
//         this.packetSender = packetSender;
//     }
// 
//     protected void addFrame(final Frame frame) {
//         if (alive) {
//             synchronized (frameLock) {
//                 frameQueue.add(frame);
// 
//                 if (frame instanceof DataFrame) {
//                     bufSize += ((DataFrame) frame).getData().length;
//                     if (bufSize > MuxGlobalConstants.CONNECTION_MAX_DATA_BUFFER_SIZE && !remotePauseSend) {
//                         remotePauseSend = true;
//                         packetSender.sendPacket(new PauseConnectionFrame(connectionID).toBytes());
//                     }
//                 }
// 
//                 frameLock.notifyAll();
//             }
//         }
//     }
// 
//     private byte[] readRaw() throws InterruptedException, ConnectionNotAliveException {
//         if (alive) {
//             Frame frame;
//             synchronized (frameLock) {
//                 while ((frame = frameQueue.poll()) == null && alive) {
//                     frameLock.wait();
//                 }
//             }
// 
//             if (frame == null) {
//                 throw new ConnectionNotAliveException();
//             }
// 
//             if (frame instanceof DataFrame) {
//                 final byte[] data = ((DataFrame) frame).getData();
// 
//                 synchronized (frameLock) {
//                     bufSize -= data.length;
//                     if (bufSize < MuxGlobalConstants.CONNECTION_MAX_DATA_BUFFER_SIZE && remotePauseSend) {
//                         remotePauseSend = false;
//                         packetSender.sendPacket(new ContinueConnectionFrame(connectionID).toBytes());
//                     }
//                 }
// 
//                 return data;
//             } else if (frame instanceof CloseConnectionFrame) {
//                 close();
//                 return null;
//             } else {
//                 return null;
//             }
//         } else {
//             throw new ConnectionNotAliveException();
//         }
//     }
// 
//     public byte[] read() throws ConnectionNotAliveException, InterruptedException {
//         byte[] tmp = null;
//         while (tmp == null) {
//             tmp = readRaw();
//         }
//         return tmp;
//     }
// 
//     private boolean canSend() {
//         return alive && !stopSend;
//     }
// 
//     public void send(final byte[] bytes) throws SenderClosedException, InterruptedException {
//         if (canSend()) {
//             synchronized (sendLock) {
//                 while (localPauseSend && canSend()) {
//                     sendLock.wait();
//                 }
//             }
//             packetSender.sendPacket(new DataFrame(connectionID, bytes).toBytes());
//         } else {
//             throw new SenderClosedException();
//         }
//     }
// 
//     protected void pauseSend() {
//         localPauseSend = true;
//     }
// 
//     protected void continueSend() {
//         localPauseSend = false;
//         synchronized (sendLock) {
//             sendLock.notifyAll();
//         }
//     }
// 
//     public boolean isAlive() {
//         return alive;
//     }
// 
//     public short getID() {
//         return connectionID;
//     }
// 
//     protected void closeSender() {
//         stopSend = true;
//     }
// 
//     public void close() {
//         close_impl(true);
//     }
// 
//     protected void closeNoRemove() {
//         close_impl(false);
//     }
// 
//     private void close_impl(final boolean removeFromMap) {
//         synchronized (closeLock) {
//             if (alive) {
// 
//                 packetSender.sendPacket(new CloseConnectionFrame(connectionID).toBytes());
// 
//                 alive = false;
// 
//                 continueSend();
// 
//                 if (removeFromMap) multiplexer.removeConnectionFromMap(connectionID);
// 
//                 synchronized (frameLock) {
//                     frameQueue.clear();
//                     frameLock.notifyAll();
//                 }
// 
//             }
//         }
//     }
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/ConnectionNotAliveException.java
// public class ConnectionNotAliveException extends MuxException {
// 
//     public ConnectionNotAliveException() {
//         super("Connection is not alive");
//     }
// 
//     public ConnectionNotAliveException(final String msg) {
//         super(msg);
//     }
// 
// }
// 
// Path: dragonite-mux/src/main/java/com/vecsight/dragonite/mux/exception/SenderClosedException.java
// public class SenderClosedException extends MuxException {
// 
//     public SenderClosedException() {
//         super("Sender closed");
//     }
// 
//     public SenderClosedException(final String msg) {
//         super(msg);
//     }
// 
// }


// Path: dragonite-forwarder/src/main/java/com/vecsight/dragonite/forwarder/network/Pipe.java
import com.vecsight.dragonite.mux.conn.MultiplexedConnection;
import com.vecsight.dragonite.mux.exception.ConnectionNotAliveException;
import com.vecsight.dragonite.mux.exception.SenderClosedException;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;

/*
 * The Dragonite Project
 * -------------------------
 * See the LICENSE file in the root directory for license information.
 */


package com.vecsight.dragonite.forwarder.network;



public class Pipe {

    private final short bufferSize;

    public Pipe(final short bufferSize) {
        this.bufferSize = bufferSize;
    }

    public void pipe(final InputStream inputStream, final MultiplexedConnection connection) throws IOException, SenderClosedException, InterruptedException {