/* * Efl.Net input/output examples. * * This example builds on the core_io example by connecting to a remote server * using a dialer and a command queue. The response is printed to stdout. */ using System; public class ExampleRunner { private eina.List waiting = null; private eina.List commands = null; private eina.Slice delimiter; private efl.net.dialer.Tcp dialer = null; private efl.io.Copier sender = null; private efl.io.Copier receiver = null; public void Run() { efl.ui.Config.Run(); } // call this method to cleanly shut down our example public void Quit() { if (waiting != null) { Console.Error.WriteLine("ERROR: {0} operations were waiting!", waiting.Length); waiting.Dispose(); waiting = null; } if (receiver != null) { receiver.Close(); receiver.GetDestination().Dispose(); receiver.Dispose(); receiver = null; } if (sender) { sender.Close(); sender.GetSource().Dispose(); source.Dispose(); } if (dialer) dialer.Dispose(); // efl_exit(retval); // TODO missing efl.ui.Config.Exit(); } // iterate through the commands to send through the dialler public void CommandNext() { efl.io.Reader send_queue = sender.GetSource(); if (commands != null) { send_queue.EosMark(); return; } string cmd = commands[0]; // commands.RemoveAt(0); // TODO missing eina.Slice slice; // slice = (Eina_Slice)EINA_SLICE_STR(cmd); // TODO missing send_queue.Write(slice, null); // Console.WriteLine("INFO: sent '{0}'", EINA_SLICE_STR_PRINT(slice)); // TODO missing // don't use delimiter directly, 'Len' may be changed! slice = delimiter; send_queue.Write(slice, null); } void ReceiverData(efl.io.Queue sender, EventArgs e) { eina.Slice slice = sender.GetSlice(); // Can be caused when we issue efl.io.Queue.Clear() if (slice.Len == 0) return; // If the server didn't send us the line terminator and closed the // connection (ie: efl_io_reader_eos_get() == true) or if the buffer // limit was reached then we may have a line without a trailing delimiter. // if (slice.EndsWith(delimiter)) // TODO missing // slice.Len -= delimiter.Len; // Console.WriteLine("INFO: received '{0}'", EINA_SLICE_STR_PRINT(slice)); // TODO missing sender.Clear(); CommandNext(); } void DialerConnected(efl.net.dialer.Tcp sender, EventArgs e) { Console.WriteLine("INFO: connected to {0} ({1})", sender.GetAddressDial(), sender.GetAddressRemote()); CommandNext(); } void CopierDone(efl.io.Copier sender, EventArgs e) { Console.WriteLine("INFO: {0} done", sender.GetName()); // waiting.Remove(sender); // TODO missing if (waiting.Empty()) Quit(EXIT_SUCCESS); } void CopierError(efl.io.Copier sender, eina.Error perr) { Console.Error.WriteLine(stderr, "INFO: {0} error: #{1} '{2}'", sender.GetName(), perr, perr.Message); Quit(EXIT_FAILURE); } private static void SetCopierCbs(efl.io.Copier copier) { copier.DONE += CopierDone; copier.ERROR += CopierError; } public ExampleRunner() { string address = "example.com:80"; ulong buffer_limit = 128; efl.io.Queue send_queue, receive_queue; commands = new eina.List(); commands.Append("HEAD / HTTP/1.1\r\nHost: example.com\r\nConnection: close\r\n\r\n"); // delimiter = (Eina_Slice)EINA_SLICE_STR("\r\n"); // TODO missing // Without a send_queue we'd have to manually implement an // efl.io.Reader object that would provide partial data when // efl.io.Reader.read() is called by efl.io.Copier. This is // cumbersome... we just want to write a full command and have the // queue to handle that for us. // // Our example's usage is to write each command at once followed by // the line delimiter, then wait for a reply from the server, then // write another. try { send_queue = new efl.io.QueueConcrete(null, (efl.io.Queue equeue) => { equeue.SetName("send_queue"); equeue.SetLimit(buffer_limit); }); } catch { Console.Error.WriteLine("ERROR: could not create efl.io.Queue (send)"); Quit(EXIT_FAILURE); throw; } // Without a receive_queue we'd have to manually implement an // efl.io.Writer object that would handle write of partial data // with efl.io.Writer.write() is called by efl.io.Copier. // // For output we could have another solution as well: use null // destination and handle "line" or "data" events manually, // stealing the buffer so it doesn't grow. // // Our example's usage is to peek its data with GetSlice() then // Clear(). try { receive_queue = new efl.io.QueueConcrete(null, (efl.io.Queue equeue) => { equeue.SetName("receive_queue"); equeue.SetLimit(buffer_limit); }); receive_queue.SLICE_CHANGED += ReceiverData; } catch { Console.Error.WriteLine("ERROR: could not create efl.io.Queue (receive)"); Quit(EXIT_FAILURE); throw; } // some objects such as the Efl.Io.Copier and Efl.Net.Dialer.Tcp // depend on main loop, thus their parent must be a loop // provider. We use the loop passed to our main method. // efl.Loop loop = ev->object; // TODO missing // The TCP client to use to send/receive network data try { dialer = new efl.net.dialer.TcpConcrete(loop, (efl.net.dialer.Tcp edialer) => { edialer.SetName("dialer"); }); dialer.CONNECTED += DialerConnected; } catch { Console.Error.WriteLine("ERROR: could not create efl.net.dialer.Tcp"); Quit(EXIT_FAILURE); throw; } // sender: send_queue->network try { sender = new efl.io.CopierConcrete(loop, (efl.io.Copier esender) => { esender.SetName("sender"); esender.SetLineDelimiter(delimiter); esender.SetSource(send_queue); esender.SetDestination(dialer); }); SetCopierCbs(sender); } catch { Console.Error.WriteLine("ERROR: could not create efl.io.Copier (sender)"); Quit(EXIT_FAILURE); throw; } // receiver: network->receive_queue try { receiver = new efl.io.CopierConcrete(loop, (efl.io.Copier ereceiver) => { ereceiver.SetName("receiver"); ereceiver.SetLineDelimiter(delimiter); ereceiver.SetSource(dialer); ereceiver.SetDestination(send_queue); }); SetCopierCbs(receiver); } catch { Console.Error.WriteLine("ERROR: could not create Efl_Io_Copier (receiver)"); Quit(EXIT_FAILURE); throw; } eina.Error err = dialer.Dial(address); if (err != eina.Error.NO_ERROR) { var msg = $"ERROR: could not dial {address}: {err.Message}"; Console.Error.WriteLine(msg); Quit(EXIT_FAILURE); throw new SEHException(msg); } waiting.Append(sender); waiting.Append(receiver); } } public static class Example { public static void Main() { efl.All.Init(efl.Components.Basic); var exr = new ExampleRunner(); exr.Run(); efl.All.Shutdown(); } }