private void addRequestedClientMethodToQueue(ClientMethod method) { Monitor.Enter(this.pendingMethodCallsLock); this.pending_method_calls[method.id] = method; Monitor.Exit(this.pendingMethodCallsLock); this.setProcessingNeeded(true); }
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); } }
private void __processTransportLayerInput() { //For now only input of control channel has to be delivered // Input for ProcessChannels (STDIN) is directly written to the STDIN pipe of the process (when TransportLayer enqueues data) while (this.running) { this.tl.waitForData(); // blocks if no input from transport layer /* * hand over data to respective channels */ while (this.tl.hasData()) //as long as linklayer has data { List <byte> stream = new List <byte>(this.tl.readInputStream()); UInt32 ch_id = Struct.extractUInt32(stream); byte[] data = stream.ToArray(); //the extract method removed the first elements from the List<byte> and we convert back to an array now Channel target_ch = this.GetChannel(ch_id); if (target_ch == null) { Console.WriteLine(String.Format("Received data for channel with ID {0}, this channel doesn't exist!", ch_id)); continue; } target_ch.EnqueueInput(data); } /* * process control channel data */ while (control_channel.hasPendingInData()) { List <byte> data = Struct.packByteArray(control_channel.read()); // extract control message type UInt32 CtrlMessageType = Struct.extractUInt32(data); switch (CtrlMessageType) { case CTRL_MSG_FROM_SERVER_RUN_METHOD: ClientMethod new_method = new ClientMethod(data); this.addRequestedClientMethodToQueue(new_method); Console.WriteLine(String.Format("Received control message RUN_METHOD! Method ID: {0}, Method Name: {1}, Method Args: {2}", new_method.id, new_method.name, new_method.args)); break; case CTRL_MSG_FROM_SERVER_DESTROY: this.SendControlMessage(Client.CTRL_MSG_FROM_CLIENT_DESTROY_RESPONSE); this.stop(); break; case CTRL_MSG_FROM_SERVER_CLOSE_CHANNEL: UInt32 channel_id = Struct.extractUInt32(data); Channel ch = this.GetChannel(channel_id); if (ch != null) { ch.CloseRequestedForLocal = true; } break; default: String data_utf8 = Encoding.UTF8.GetString(data.ToArray()); Console.WriteLine(String.Format("Received unknown MESSAGE TYPE for control channel! MessageType: {0}, Data: {1}", CtrlMessageType, data_utf8)); break; } } } }