Successfully sending messages to server and responding via 0mq. TODO implement response handling on client.

zmq
MCARDLE Sean M 2016-11-30 00:18:17 -08:00
parent a20f4270f4
commit 307a31714a
9 changed files with 194 additions and 180 deletions

View File

@ -12,24 +12,21 @@ namespace WifiSitter
{
public string Request { get; set; }
public string Requestor { get; set; }
public string Target { get; set; }
public byte[] Payload { get; set; }
public Type PayloadType { get; set; }
public WifiSitterIpcMessage() { }
public WifiSitterIpcMessage(string Verb, string WhosAsking, string WhereTo, string SendingWhat = "") {
public WifiSitterIpcMessage(string Verb, string WhosAsking, string SendingWhat = "") {
Request = Verb;
Requestor = WhosAsking;
Target = WhereTo;
Payload = System.Text.Encoding.UTF8.GetBytes(SendingWhat);
Payload = Encoding.UTF8.GetBytes(SendingWhat);
PayloadType = typeof(string);
}
public WifiSitterIpcMessage(string Verb, string WhosAsking, string WhereTo, object SendingWhat, Type type) {
public WifiSitterIpcMessage(string Verb, string WhosAsking, object SendingWhat, Type type) {
Request = Verb;
Requestor = WhosAsking;
Target = WhereTo;
Payload = SendingWhat.ObjectToByteArray();
PayloadType = SendingWhat.GetType();
}
@ -37,7 +34,7 @@ namespace WifiSitter
public static class WifiSitterExtensions
{
public static string IpcMessageJsonString(this WifiSitterIpcMessage message) {
public static string ToJsonString(this WifiSitterIpcMessage message) {
string result;
result = Newtonsoft.Json.JsonConvert.SerializeObject(message);
return result;

View File

@ -12,7 +12,9 @@ using System.Threading.Tasks;
using WifiSitter.Helpers;
// 3rd party deps
using XDMessaging;
using NetMQ;
using NetMQ.Sockets;
using System.Text;
namespace WifiSitter
{
@ -23,13 +25,14 @@ namespace WifiSitter
internal volatile static NetworkState netstate;
private const string _serviceName = "WifiSitter";
private Guid _uninstGuid;
private Thread _thread;
private Thread _mainLoopThread;
private Thread _mqServerThread;
private ManualResetEvent _shutdownEvent = new ManualResetEvent(false);
private static string[] _ignoreNics;
private volatile bool _paused;
private static WifiSitterIpc _wsIpc;
private Action<object, XDMessageEventArgs> _handleMsgRecv;
private SynchronizationContext _sync;
private static string _myChannel = String.Format("{0}-{1}", Process.GetCurrentProcess().Id, Process.GetCurrentProcess().ProcessName);
#endregion // fields
@ -60,13 +63,6 @@ namespace WifiSitter
Assembly asm = GetType().Assembly;
Version v = asm.GetName().Version;
LogLine("Version: {0}", v.ToString());
// Setup IPC
// TODO make this tunable, cmd argument?
LogLine("Initializing IPC...");
_handleMsgRecv = new Action<object, XDMessageEventArgs>(HandleMsgReceived);
_wsIpc = new WifiSitterIpc(_handleMsgRecv);
// Check if there are any interfaces not detected by GetAllNetworkInterfaces()
@ -79,6 +75,7 @@ namespace WifiSitter
LogLine("Initialized...");
}
#endregion // constructor
@ -369,65 +366,100 @@ namespace WifiSitter
}
private void HandleMsgReceived(object sender, XDMessageEventArgs e) {
LogLine("Message received");
if (!e.DataGram.IsValid) {
Trace.WriteLine("Invalid datagram received.");
return;
}
WifiSitterIpcMessage _msg = null;
try { _msg = Newtonsoft.Json.JsonConvert.DeserializeObject<WifiSitterIpcMessage>(e.DataGram.Message); }
catch { LogLine("Deserialize to WifiSitterIpcMessage failed."); }
WifiSitterIpcMessage response;
if (_msg != null) {
switch (_msg.Request) {
case "get_netstate":
LogLine("Sending netstate to: {0}", _msg.Requestor);
if (_paused && netstate.CheckNet) {
netstate.UpdateNics(DiscoverAllNetworkDevices(netstate.Nics));
netstate.StateChecked();
}
response = new WifiSitterIpcMessage("give_netstate", _wsIpc.MyChannelName, "", Newtonsoft.Json.JsonConvert.SerializeObject(new Model.SimpleNetworkState(netstate)));
_wsIpc.MsgBroadcaster.SendToChannel(_msg.Target, response.IpcMessageJsonString());
break;
case "take_five":
try {
if (_paused) {
response = new WifiSitterIpcMessage("taking_five", _wsIpc.MyChannelName, "", "already_paused");
_wsIpc.MsgBroadcaster.SendToChannel(_msg.Target, response.IpcMessageJsonString());
}
else {
int minutes = 5;
private void ZeroMQRouterRun() {
// TODO handle port bind failure, increment port and try again, quit after 3 tries
int port = 37247;
int tries = 0;
string connString = String.Format("@tcp://127.0.0.1:{0}", port);
var server = new RouterSocket(connString);
server.Options.Identity = Encoding.UTF8.GetBytes(_myChannel);
while (true) { // TODO need to signal stop
var clientMessage = server.ReceiveMultipartMessage();
if (clientMessage.FrameCount > 2) {
WifiSitterIpcMessage _msg = null;
string response = String.Empty;
var msgString = String.Concat(clientMessage.Skip(2).ToList().Select(x => x.ConvertToString()));
try { _msg = Newtonsoft.Json.JsonConvert.DeserializeObject<WifiSitterIpcMessage>(msgString); }
catch {
LogLine("Deserialize to WifiSitterIpcMessage failed.");
// TODO respond with failure
}
if (_msg != null) {
switch (_msg.Request) {
case "get_netstate":
LogLine("Sending netstate to: {0}", _msg.Requestor);
if (_paused && netstate.CheckNet) {
netstate.UpdateNics(DiscoverAllNetworkDevices(netstate.Nics));
netstate.StateChecked();
}
// form response
response = new WifiSitterIpcMessage("give_netstate",
server.Options.Identity.ToString(),
Newtonsoft.Json.JsonConvert.SerializeObject(new Model.SimpleNetworkState(netstate))).ToJsonString();
break;
case "take_five":
try {
if (_paused) {
response = new WifiSitterIpcMessage("taking_five",
server.Options.Identity.ToString(),
"already_paused").ToJsonString();
}
else {
int minutes = 5;
#if DEBUG
minutes = 1; // I'm impatient while debugging
#endif
minutes = 1; // I'm impatient while debugging
#endif
WriteLog(LogType.info, "Taking {0} minute break and restoring interfaces to initial state.", minutes.ToString());
OnPause();
Task.Delay(minutes * 60 * 1000).ContinueWith((task) => {
WriteLog(LogType.info, "Break elapsed. Resuming operation.");
netstate.ShouldCheckState(); // Main loop should check state again when resuming from paused state
OnContinue();
response = new WifiSitterIpcMessage("taking_five", _wsIpc.MyChannelName, "", "resuming");
_wsIpc.MsgBroadcaster.SendToChannel(_msg.Target, response.IpcMessageJsonString());
});
ResetNicState(netstate);
response = new WifiSitterIpcMessage("taking_five", _wsIpc.MyChannelName, "", "pausing");
_wsIpc.MsgBroadcaster.SendToChannel(_msg.Target, response.IpcMessageJsonString());
}
WriteLog(LogType.info, "Taking {0} minute break and restoring interfaces to initial state.", minutes.ToString());
OnPause();
Task.Delay(minutes * 60 * 1000).ContinueWith((task) => {
WriteLog(LogType.info, "Break elapsed. Resuming operation.");
netstate.ShouldCheckState(); // Main loop should check state again when resuming from paused state
OnContinue();
// prefixing t_ to differentiate from outer scope
string t_response = new WifiSitterIpcMessage("taking_five",
server.Options.Identity.ToString(),
"resuming").ToJsonString();
// Send response
var t_responseMessage = new NetMQMessage();
t_responseMessage.Append(server.Options.Identity);
t_responseMessage.AppendEmptyFrame();
t_responseMessage.Append(t_response);
server.SendMultipartMessage(t_responseMessage);
});
ResetNicState(netstate);
response = new WifiSitterIpcMessage("taking_five",
server.Options.Identity.ToString(),
"pausing").ToJsonString();
}
}
catch { WriteLog(LogType.error, "Failed to enter paused state after 'take_five' request received."); }
break;
default:
break;
}
catch { WriteLog(LogType.error, "Failed to enter paused state after 'take_five' request received."); }
break;
default:
break;
// Send response
var responseMessage = new NetMQMessage();
responseMessage.Append(server.Options.Identity);
responseMessage.AppendEmptyFrame();
responseMessage.Append(response);
server.SendMultipartMessage(responseMessage);
}
else {
Trace.WriteLine(String.Format("Message issue: {0}", clientMessage.ToString()));
}
}
}
else {
Trace.WriteLine(String.Format("Message issue: {0}", e.DataGram.Message));
}
}
#endregion // methods
@ -440,10 +472,22 @@ namespace WifiSitter
Intialize();
_thread = new Thread(WorkerThreadFunc);
_thread.Name = "WifiSitter Main Loop";
_thread.IsBackground = true;
_thread.Start();
// Setup background thread for running main loop
_mainLoopThread = new Thread(WorkerThreadFunc);
_mainLoopThread.Name = "WifiSitter Main Loop";
_mainLoopThread.IsBackground = true;
_mainLoopThread.Start();
// Setup IPC, 0mq messaging thread
// TODO make this tunable, cmd argument?
LogLine("Initializing IPC...");
_mqServerThread = new Thread(ZeroMQRouterRun);
_mqServerThread.Name = "0MQ Server Thread";
_mqServerThread.IsBackground = true;
_mqServerThread.Start();
}
catch (Exception e) {
WriteLog(LogType.error, e.Source, e.Message);
@ -454,8 +498,8 @@ namespace WifiSitter
protected override void OnStopImpl() {
ResetNicState(netstate);
_shutdownEvent.Set();
if (!_thread.Join(3000)) {
_thread.Abort();
if (!_mainLoopThread.Join(3000)) {
_mainLoopThread.Abort();
}
}

View File

@ -83,6 +83,14 @@
<ApplicationIcon>wifisitter-icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AsyncIO, Version=0.1.20.0, Culture=neutral, PublicKeyToken=44a94435bd6f33f8, processorArchitecture=MSIL">
<HintPath>..\packages\AsyncIO.0.1.20.0\lib\net40\AsyncIO.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NetMQ, Version=3.3.3.4, Culture=neutral, PublicKeyToken=a6decef4ddc58b3a, processorArchitecture=MSIL">
<HintPath>..\packages\NetMQ.3.3.3.4\lib\net40\NetMQ.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
@ -95,10 +103,6 @@
<Reference Include="System.Xml.Linq" />
<Reference Include="Microsoft.CSharp" />
<Reference Include="System.Xml" />
<Reference Include="XDMessaging.Lite, Version=5.0.1.0, Culture=neutral, PublicKeyToken=737bc70442f2c4af, processorArchitecture=MSIL">
<HintPath>..\packages\XDMessaging.Lite.5.0.1\lib\net40-Client\XDMessaging.Lite.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="Helpers\AbstractService.cs">
@ -115,7 +119,6 @@
</Compile>
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="Model\SitterNic.cs" />
<Compile Include="WifiSitterIpc.cs" />
<Compile Include="Model\WifiSitterIpcMessage.cs" />
</ItemGroup>
<ItemGroup>
@ -147,7 +150,7 @@
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<ProjectExtensions>
<VisualStudio>
<UserProperties BuildVersion_UpdateFileVersion="False" BuildVersion_BuildVersioningStyle="None.None.None.Increment" BuildVersion_StartDate="2000/1/1" />
<UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_BuildVersioningStyle="None.None.None.Increment" BuildVersion_UpdateFileVersion="False" />
</VisualStudio>
</ProjectExtensions>
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.

View File

@ -1,39 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Diagnostics;
using XDMessaging;
namespace WifiSitter
{
public class WifiSitterIpc
{
private static string _myChannel = String.Format("{0}-{1}", Process.GetCurrentProcess().Id, Process.GetCurrentProcess().ProcessName);
private XDMessagingClient _msgClient = new XDMessagingClient();
public IXDListener MsgListener { get; private set; }
public IXDBroadcaster MsgBroadcaster { get; private set; }
public string MyChannelName { get { return _myChannel; } }
public WifiSitterIpc(Action<object, XDMessageEventArgs> MessageReceivedHandler) {
try {
WifiSitter.LogLine("Registering listener channel: {0}", _myChannel);
MsgListener = _msgClient.Listeners.GetListenerForMode(XDTransportMode.Compatibility);
MsgListener.RegisterChannel(_myChannel);
}
catch {
WifiSitter.LogLine("Failed to register IPC listener channel {0}", _myChannel);
}
MsgListener.MessageReceived += (o, e) => { MessageReceivedHandler(o, e); };
MsgBroadcaster = _msgClient.Broadcasters.GetBroadcasterForMode(XDTransportMode.Compatibility);
}
}
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AsyncIO" version="0.1.20.0" targetFramework="net452" />
<package id="NetMQ" version="3.3.3.4" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="XDMessaging.Lite" version="5.0.1" targetFramework="net452" />
</packages>

View File

@ -17,8 +17,6 @@ using WifiSitterGui.ViewModel;
using WifiSitter;
using WifiSitter.Model;
using XDMessaging;
namespace WifiSitterGui
{
/// <summary>

View File

@ -9,11 +9,14 @@ using System.Windows.Input;
using System.ServiceProcess;
using System.Net.NetworkInformation;
// internal usings
using WifiSitter;
using WifiSitter.Model;
using WifiSitterGui.Helpers;
using XDMessaging;
// 3rd party usings
using NetMQ;
using NetMQ.Sockets;
namespace WifiSitterGui.ViewModel
{
@ -25,17 +28,16 @@ namespace WifiSitterGui.ViewModel
private RelayCommand _launchWindowCommand;
private RelayCommand _takeFiveCommand; // Asks service to pause for 5 minutes
private static MainWindow _statusGui;
private static WifiSitterIpc _wsIpc;
private Action<object, XDMessageEventArgs> _handleMsgRcv;
private static string _serviceChannel;
private System.Timers.Timer _netstateCheckTimer;
private static string _myChannel = String.Format("{0}-{1}", Process.GetCurrentProcess().Id, Process.GetCurrentProcess().ProcessName);
private static DealerSocket _mqClient;
#endregion // fields
#region constructor
public WifiSitterAgentViewModel() {
Intitialize();
}
@ -46,6 +48,13 @@ namespace WifiSitterGui.ViewModel
private void Intitialize() {
int port = 37247;
string connString = String.Format("tcp://127.0.0.1:{0}", port);
_mqClient = new DealerSocket();
_mqClient.Options.Identity = Encoding.UTF8.GetBytes(_myChannel);
_mqClient.Connect(connString);
// Get NetState
RequestNetworkState();
@ -66,19 +75,7 @@ namespace WifiSitterGui.ViewModel
#endregion // constructor
#region properties
internal WifiSitterIpc WsIpc {
get {
if (_wsIpc == null) {
// Setup IPC message listener
_handleMsgRcv = new Action<object, XDMessageEventArgs>(wsIpc_MessageReceived);
_wsIpc = new WifiSitterIpc(_handleMsgRcv);
}
return _wsIpc;
}
}
public MainWindowViewModel WindowVM {
get { if (_windowVM == null) {
_windowVM = new MainWindowViewModel();
@ -115,7 +112,13 @@ namespace WifiSitterGui.ViewModel
if (!String.IsNullOrEmpty(ServiceChannelName)) {
try {
Trace.WriteLine("Checking for network state.");
WsIpc.MsgBroadcaster.SendToChannel(ServiceChannelName, new WifiSitterIpcMessage("get_netstate", _wsIpc.MyChannelName, _wsIpc.MyChannelName).IpcMessageJsonString());
string request = new WifiSitterIpcMessage("get_netstate", _myChannel).ToJsonString();
var reqMessage = new NetMQMessage();
reqMessage.Append(_mqClient.Options.Identity);
reqMessage.AppendEmptyFrame();
reqMessage.Append(request);
bool success = _mqClient.TrySendMultipartMessage(reqMessage);
if (!success) Trace.WriteLine("Failed to send get_networkstate");
}
catch (Exception e) {
Trace.WriteLine(e.Message);
@ -152,8 +155,13 @@ namespace WifiSitterGui.ViewModel
get {
if (_takeFiveCommand == null) {
_takeFiveCommand = new RelayCommand(() => {
var request = new WifiSitterIpcMessage("take_five", _wsIpc.MyChannelName, _wsIpc.MyChannelName);
WsIpc.MsgBroadcaster.SendToChannel(ServiceChannelName, request.IpcMessageJsonString());
var request = new WifiSitterIpcMessage("take_five", _myChannel).ToJsonString();
var reqMessage = new NetMQMessage();
reqMessage.Append(_mqClient.Options.Identity);
reqMessage.AppendEmptyFrame();
reqMessage.Append(request);
bool success = _mqClient.TrySendMultipartMessage(reqMessage);
if (!success) Trace.WriteLine("Failed to send take_five");
// TODO need response validation mechanism
});
}
@ -165,36 +173,36 @@ namespace WifiSitterGui.ViewModel
#region events
internal void wsIpc_MessageReceived(object sender, XDMessageEventArgs e) {
if (!e.DataGram.IsValid) {
Trace.WriteLine("Invalid datagram received.");
return;
}
internal void wsIpc_MessageReceived() {
//if (!e.DataGram.IsValid) {
// Trace.WriteLine("Invalid datagram received.");
// return;
//}
WifiSitterIpcMessage _sr = null;
try { _sr = Newtonsoft.Json.JsonConvert.DeserializeObject<WifiSitterIpcMessage>(e.DataGram.Message); }
catch { Trace.WriteLine("Deserialize to ServiceRequest failed."); }
//WifiSitterIpcMessage _sr = null;
//try { _sr = Newtonsoft.Json.JsonConvert.DeserializeObject<WifiSitterIpcMessage>(e.DataGram.Message); }
//catch { Trace.WriteLine("Deserialize to ServiceRequest failed."); }
if (_sr != null) {
switch (_sr.Request) {
case "give_netstate":
try { WindowVM.NetState = Newtonsoft.Json.JsonConvert.DeserializeObject<SimpleNetworkState>(Encoding.UTF8.GetString(_sr.Payload)); }
catch { WifiSitter.WifiSitter.LogLine("Failed to deserialize netstate, payload."); }
break;
case "taking_five":
Trace.WriteLine(String.Format("Responded 'taking_five' : {0}", Encoding.UTF8.GetString(_sr.Payload)));
break;
case "service_status":
// TODO issue service status update
break;
default:
Trace.WriteLine(String.Format("Unknown request type: {0} from {1}", _sr?.Request, _sr?.Requestor));
break;
}
}
else {
Trace.WriteLine(e.DataGram.Message);
}
//if (_sr != null) {
// switch (_sr.Request) {
// case "give_netstate":
// try { WindowVM.NetState = Newtonsoft.Json.JsonConvert.DeserializeObject<SimpleNetworkState>(Encoding.UTF8.GetString(_sr.Payload)); }
// catch { WifiSitter.WifiSitter.LogLine("Failed to deserialize netstate, payload."); }
// break;
// case "taking_five":
// Trace.WriteLine(String.Format("Responded 'taking_five' : {0}", Encoding.UTF8.GetString(_sr.Payload)));
// break;
// case "service_status":
// // TODO issue service status update
// break;
// default:
// Trace.WriteLine(String.Format("Unknown request type: {0} from {1}", _sr?.Request, _sr?.Requestor));
// break;
// }
//}
//else {
// Trace.WriteLine(e.DataGram.Message);
//}
}
#endregion // events

View File

@ -40,10 +40,18 @@
<ApplicationIcon>wifisitter-icon.ico</ApplicationIcon>
</PropertyGroup>
<ItemGroup>
<Reference Include="AsyncIO, Version=0.1.20.0, Culture=neutral, PublicKeyToken=44a94435bd6f33f8, processorArchitecture=MSIL">
<HintPath>..\packages\AsyncIO.0.1.20.0\lib\net40\AsyncIO.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Hardcodet.Wpf.TaskbarNotification, Version=1.0.5.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\Hardcodet.NotifyIcon.Wpf.1.0.8\lib\net451\Hardcodet.Wpf.TaskbarNotification.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="NetMQ, Version=3.3.3.4, Culture=neutral, PublicKeyToken=a6decef4ddc58b3a, processorArchitecture=MSIL">
<HintPath>..\packages\NetMQ.3.3.3.4\lib\net40\NetMQ.dll</HintPath>
<Private>True</Private>
</Reference>
<Reference Include="Newtonsoft.Json, Version=9.0.0.0, Culture=neutral, PublicKeyToken=30ad4fe6b2a6aeed, processorArchitecture=MSIL">
<HintPath>..\packages\Newtonsoft.Json.9.0.1\lib\net45\Newtonsoft.Json.dll</HintPath>
<Private>True</Private>
@ -61,10 +69,6 @@
<Reference Include="WindowsBase" />
<Reference Include="PresentationCore" />
<Reference Include="PresentationFramework" />
<Reference Include="XDMessaging.Lite, Version=5.0.1.0, Culture=neutral, PublicKeyToken=737bc70442f2c4af, processorArchitecture=MSIL">
<HintPath>..\packages\XDMessaging.Lite.5.0.1\lib\net40-Client\XDMessaging.Lite.dll</HintPath>
<Private>True</Private>
</Reference>
</ItemGroup>
<ItemGroup>
<ApplicationDefinition Include="App.xaml">
@ -86,9 +90,6 @@
<Compile Include="..\WifiSitter\Model\WifiSitterIpcMessage.cs">
<Link>Model\WifiSitterIpcMessage.cs</Link>
</Compile>
<Compile Include="..\WifiSitter\WifiSitterIpc.cs">
<Link>WifiSitterIpc.cs</Link>
</Compile>
<Compile Include="Helpers\RelayCommand.cs" />
<Compile Include="Model\WifiSitterStub.cs" />
<Compile Include="TrayIconControl.xaml.cs">

View File

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="AsyncIO" version="0.1.20.0" targetFramework="net452" />
<package id="Hardcodet.NotifyIcon.Wpf" version="1.0.8" targetFramework="net452" />
<package id="NetMQ" version="3.3.3.4" targetFramework="net452" />
<package id="Newtonsoft.Json" version="9.0.1" targetFramework="net452" />
<package id="XDMessaging.Lite" version="5.0.1" targetFramework="net452" />
</packages>