public StreamChannel(Stream stream, CallbackOutputProcessingNeeded onOutDirty, CallbackChannelProcessingNeeded onChannelDirty, bool passthrough = true, int passthrough_limit = 3000) : base(Channel.Encodings.BYTEARRAY, Channel.Types.BIDIRECTIONAL, onOutDirty, onChannelDirty)
        {
            /*
             * passtrough is a design decission, working like this:
             *      - if the underlying Stream is readable, read operations are done continuous and automatically
             *      - as reading could block, this is handle by a sperate thread
             *      - data read is pushed directly to the channel output queue
             *      - if the channel queue grows to passthroug_limit, this processed is paused until
             *      the communication layer responsible for output data processing has dequeued enough
             *      data, to shrink the queue below this limit
             *
             *      In summary this means data is continueosly sent to the client, as long as it could be read
             *      from the stream. Thus a readable StreamChannel puts load to theLinkLayer permanently (throttled
             *      by the passthrough_limit). Additionally, this means if data isn't processed, buffer grow - this
             *      happens on the other endpoint.
             *
             *      A different approach would be to read data "on demand". This again would involve much more control
             *      communication. With NetworkStreams in mind, this seems to be the better solution '(hopefully)
             *
             * ToDo:
             * - The channels onClose() method gets called by the client, if the channel is removed from the clients channel list.
             *   Current implementation allows the channel to close the underlying stream object. This is somehow wrong and should be initiated
             *   ba a request of the remote peer (close_stream_request). In order to allow the remote peer to send such a request, it
             *   has to be aware of the fact that the channel has been closed. This isn't the case at the moment, as the peer doesn't get informed about this.
             * - As there's no communication to the peer, when a channel gets closed, pending channel objects reside on the other endpoit when removed
             *   from this peer.
             * - as this isn't read on demand, a method has to be found to signal the remote peer if EOF is reached on reading. This could for example
             *   be done by writing an empty stream to the channel output queue (empty payload, the byte signaling that this is data has to be included)
             */



            this.stream            = stream;
            this.passthrough       = passthrough;
            this.passthrough_limit = passthrough_limit;

            //if we have a readable stream and passtrough is enabled, we create a thread to passthrough data read
            if (stream.CanRead && this.passthrough)
            {
                this.passtrough_limit_not_reached = new ManualResetEvent(true);
                this.thread_out = new Thread(new ThreadStart(this.passThruOut));
                thread_out.Start();
            }
            else if (stream.CanRead && !this.passthrough)
            {
                // prepare read buffer
                this.readbuf = new byte[60000];
            }

            Console.WriteLine(String.Format("StreamChannel created {0}, passthrough: {1}", this.ID, passthrough));
        }
        public delegate void CallbackChannelProcessingNeeded(); //the delgate is used, to inform somebody that output processing is needed (in our case the LinkLayer)

        public Channel(Encodings encoding, Types type, CallbackOutputProcessingNeeded onOutDirty, CallbackChannelProcessingNeeded onChannelDirty)
        {
            this.ID = next_id;
            next_id++;
            this.encoding       = encoding;
            this.type           = type;
            this.onOutDirty     = onOutDirty;
            this.onChannelDirty = onChannelDirty;
            this.isLinked       = false;
            // if IN channel or BIDIRECTIONAL channel, generate inbound queue
            if (this.type != Types.OUT)
            {
                this.in_queue = Queue.Synchronized(new Queue());
            }

            // if OUT channel or BIDIRECTIONAL channel, generate inbound queue
            if (this.type != Types.IN)
            {
                this.out_queue        = Queue.Synchronized(new Queue());
                this.out_queue_backup = Queue.Synchronized(new Queue());
            }
        }
        public ProcessChannel(Process process, Stream stream, Encodings encoding, Types type, CallbackOutputProcessingNeeded onOutDirty, CallbackChannelProcessingNeeded onChannelDirty) : base(encoding, type, onOutDirty, onChannelDirty)
        {
            this.stream           = stream;
            this.process          = process;
            this.lock_output      = new object();
            this.bufferedOutBytes = 0;

            //if this is an out channel, we create a thread permannently reading from the stream
            if (this.type != Types.IN)
            {
                this.accumulation_out = new List <byte>();
                this.thread_out       = new Thread(new ThreadStart(this.passThruOut));
                thread_out.Start();
            }
        }