Win/app updates2 (#1473)

* add talk functionality to OpenThread.vcxproj

* update README.md

* fixed according to Section 4 of RFC 5952 (CR by aeliot)

* fix removing an empty context bug (can't remove twice)
This commit is contained in:
jjlee9
2017-03-21 08:44:35 -07:00
committed by Jonathan Hui
parent 27c1cb301b
commit 36ff8022dc
39 changed files with 3405 additions and 240 deletions
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public ref class ClientArgs sealed
{
public:
property Windows::Networking::HostName^ ServerHostName;
property Platform::String^ ServerPort;
property Windows::Networking::HostName^ ClientHostName;
property Platform::String^ ClientPort;
};
} // namespace Thread
+142
View File
@@ -0,0 +1,142 @@
<!--
Copyright (c) 2016, The OpenThread Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->
<UserControl
x:Class="Thread.ClientControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Thread"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Text="Server IP :"
/>
<TextBox
Grid.Row="0"
Grid.Column="2"
x:Name="ServerIP"
MinWidth="500"
/>
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="Server Port :"
/>
<TextBox
Grid.Row="2"
Grid.Column="2"
x:Name="ServerPort"
Width="100"
HorizontalAlignment="Left"
/>
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="Client IP :"
/>
<TextBox
Grid.Row="4"
Grid.Column="2"
x:Name="ClientIP"
MinWidth="500"
/>
<TextBlock
Grid.Row="6"
Grid.Column="0"
Text="Client Port :"
/>
<TextBox
Grid.Row="6"
Grid.Column="2"
x:Name="ClientPort"
Width="100"
HorizontalAlignment="Left"
/>
<Button
Grid.Row="8"
Grid.Column="0"
Grid.ColumnSpan="3"
Width="75"
Content="Connect"
Click="Connect_Click"
/>
<TextBlock
Grid.Row="10"
Grid.Column="0"
Text="Input :"
/>
<TextBox
Grid.Row="10"
Grid.Column="2"
x:Name="Input"
MinWidth="300"
/>
<StackPanel
Orientation="Horizontal"
VerticalAlignment="Top"
Grid.Row="12"
Grid.Column="0"
Grid.ColumnSpan="3"
>
<Button
Width="75"
Content="Send"
Click="Send_Click"
Margin="0,0,75,0"
/>
<Button
Width="75"
Content="Exit"
Click="Exit_Click"
/>
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,188 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include <algorithm>
#include "ClientControl.xaml.h"
#include "Factory.h"
#include "TalkHelper.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
std::atomic<int> ClientControl::_clientPort{ TalkConsts::DEF_CLIENT_PORT_INIT };
ClientControl::ClientControl()
{
InitializeComponent();
ServerPort->Text = DEF_SERVER_PORT.ToString();
auto clientPort = _clientPort.load();
ClientPort->Text = clientPort.ToString();
}
void
ClientControl::Init(
IAsyncThreadNotify^ notify,
IMainPageUIElements^ mainPageUIElements)
{
_notify = std::move(notify);
_mainPageUIElements = std::move(mainPageUIElements);
}
void
ClientControl::ProtocolChanged(
Protocol protocol)
{
_protocol = protocol;
}
void
ClientControl::Connect_Click(
Object^ sender,
RoutedEventArgs^ e)
{
try
{
auto clientArgs = ref new ClientArgs();
auto serverIP = ServerIP->Text;
if (serverIP->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Server IP");
}
// check valid chars of Ipv6 Address
if (!TalkHelper::AllValidIpv6Chars(serverIP->Data(), serverIP->Data() + serverIP->Length()))
{
throw Exception::CreateException(E_INVALIDARG, "Not a valid Server IPv6 address");
}
clientArgs->ServerHostName = ref new HostName(serverIP);
if (ServerPort->Text->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Server Port");
}
clientArgs->ServerPort = ServerPort->Text;
auto clientIP = ClientIP->Text;
if (clientIP->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Client IP");
}
// check valid chars of Ipv6 Address
if (!TalkHelper::AllValidIpv6Chars(clientIP->Data(), clientIP->Data() + clientIP->Length()))
{
throw Exception::CreateException(E_INVALIDARG, "Not a valid client IPv6 address");
}
clientArgs->ClientHostName = ref new HostName(clientIP);
if (ClientPort->Text->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Client Port");
}
clientArgs->ClientPort = ClientPort->Text;
auto cleintContext = Factory::CreateClientContext(_notify, clientArgs, _protocol);
cleintContext->Connect_Click(sender, e);
// fix Only usage of each socket address (protocol/network address/port)
// is normally permitted.
auto clientPort = ++_clientPort;
ClientPort->Text = clientPort.ToString();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Connecting failed with input error: " + ex->Message,
NotifyType::Error);
}
}
void
ClientControl::Send_Click(
Object^ sender,
RoutedEventArgs^ e)
{
try
{
auto input = Input->Text;
if (input->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Input");
}
if (!CoreApplication::Properties->HasKey("clientContext"))
{
throw Exception::CreateException(E_UNEXPECTED, "Not Connected");
}
auto clientContext = dynamic_cast<IClientContext^>(
CoreApplication::Properties->Lookup("clientContext"));
if (clientContext == nullptr)
{
throw Exception::CreateException(E_UNEXPECTED, "No clientContext");
}
clientContext->Send_Click(sender, e, input);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Sending message failed with error: " + ex->Message,
NotifyType::Error);
}
}
void
ClientControl::Exit_Click(
Object^ sender,
RoutedEventArgs^ e)
{
_mainPageUIElements->TalkGrid->Visibility = Xaml::Visibility::Collapsed;
_mainPageUIElements->ThreadGrid->Visibility = Xaml::Visibility::Visible;
}
@@ -0,0 +1,66 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <atomic>
#include "ClientControl.g.h"
#include "TalkConsts.h"
#include "IAsyncThreadNotify.h"
#include "IMainPageUIElements.h"
#include "Protocol.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class ClientControl sealed
{
public:
ClientControl();
void Init(IAsyncThreadNotify^ notify, IMainPageUIElements^ mainPageUIElements);
void ProtocolChanged(Protocol protocol);
private:
static constexpr unsigned short DEF_SERVER_PORT = TalkConsts::DEF_SERVER_PORT;
void Connect_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void Send_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void Exit_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
IAsyncThreadNotify^ _notify;
IMainPageUIElements^ _mainPageUIElements;
Protocol _protocol;
static std::atomic<int> _clientPort;
};
} // namespace Thread
@@ -0,0 +1,286 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include "DatagramClientContext.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Networking::Sockets;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
DatagramClientContext::DatagramClientContext(
IAsyncThreadNotify^ notify,
DatagramSocket^ client,
ClientArgs^ args) :
_notify{ std::move(notify) },
_client{ std::move(client) },
_args{ std::move(args) }
{
}
DatagramClientContext::~DatagramClientContext()
{
// A Client can be closed in two ways:
// - explicitly: using the 'delete' keyword (client is closed even if there are outstanding references to it).
// - implicitly: removing the last reference to it (i.e., falling out-of-scope).
//
// When a Socket is closed implicitly, it can take several seconds for the local port being used
// by it to be freed/reclaimed by the lower networking layers. During that time, other sockets on the machine
// will not be able to use the port. Thus, it is strongly recommended that Socket instances be explicitly
// closed before they go out of scope(e.g., before application exit). The call below explicitly closes the socket.
if (_client != nullptr)
{
delete _client;
_client = nullptr;
}
}
void
DatagramClientContext::Connect_Click(
Object^ sender,
RoutedEventArgs^ e)
{
task<void> removeContext;
if (CoreApplication::Properties->HasKey("clientContext"))
{
auto clientContext = dynamic_cast<IClientContext^>(
CoreApplication::Properties->Lookup("clientContext"));
if (clientContext == nullptr)
{
throw ref new FailureException(L"No clientContext");
}
removeContext = create_task(clientContext->CancelIO()).then(
[]()
{
CoreApplication::Properties->Remove("clientContext");
});
}
else
{
removeContext = create_task([]() {});
}
_client->MessageReceived += ref new MessageHandler(
this, &DatagramClientContext::OnMessage);
removeContext.then([this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
// Events cannot be hooked up directly to the ScenarioInput2 object, as the object can fall out-of-scope and be
// deleted. This would render any event hooked up to the object ineffective. The ClientContext guarantees that
// both the socket and object that serves its events have the same lifetime.
CoreApplication::Properties->Insert("clientContext", this);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Remove clientContext error: " + ex->Message,
NotifyType::Error);
}
catch (task_canceled&)
{
}
}).then([this]()
{
auto endpointPair = ref new EndpointPair(_args->ClientHostName, _args->ClientPort,
_args->ServerHostName, _args->ServerPort);
_notify->NotifyFromAsyncThread("Start connecting", NotifyType::Status);
create_task(_client->ConnectAsync(endpointPair)).then(
[this, endpointPair](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
_notify->NotifyFromAsyncThread(
"Connect from " + endpointPair->LocalHostName->CanonicalName +
" to " + endpointPair->RemoteHostName->CanonicalName,
NotifyType::Status);
SetConnected(true);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Start binding failed with error: " + ex->Message,
NotifyType::Error);
CoreApplication::Properties->Remove("clientContext");
}
catch (task_canceled&)
{
CoreApplication::Properties->Remove("clientContext");
}
});
});
}
void
DatagramClientContext::Send_Click(
Object^ sender,
RoutedEventArgs^ e,
String^ input)
{
SendMessage(GetDataWriter(), input);
}
IAsyncAction^
DatagramClientContext::CancelIO()
{
return _client->CancelIOAsync();
}
void
DatagramClientContext::SetConnected(
bool connected)
{
_connected = connected;
}
bool
Thread::DatagramClientContext::IsConnected() const
{
return _connected;
}
void
Thread::DatagramClientContext::OnMessage(
DatagramSocket^ socket,
MessageReceivedEventArgs^ eventArgs)
{
try
{
auto dataReader = eventArgs->GetDataReader();
Receive(dataReader, dataReader->UnconsumedBufferLength);
}
catch (Exception^ ex)
{
auto socketError = SocketError::GetStatus(ex->HResult);
if (socketError == SocketErrorStatus::ConnectionResetByPeer)
{
// This error would indicate that a previous send operation resulted in an ICMP "Port Unreachable" message.
_notify->NotifyFromAsyncThread(
"Peer does not listen on the specific port. Please make sure that you run step 1 first "
"or you have a server properly working on a remote server.",
NotifyType::Error);
}
else if (socketError != SocketErrorStatus::Unknown)
{
_notify->NotifyFromAsyncThread(
"Error happened when receiving a datagram: " + socketError.ToString(),
NotifyType::Error);
}
else
{
throw;
}
}
}
void
DatagramClientContext::Receive(
DataReader^ dataReader,
unsigned int strLen)
{
if (!strLen)
{
return;
}
auto msg = dataReader->ReadString(strLen);
_notify->NotifyFromAsyncThread("Received data from server: \"" + msg + "\"",
NotifyType::Status);
}
void
DatagramClientContext::SendMessage(
DataWriter^ dataWriter,
String^ msg)
{
if (!IsConnected())
{
_notify->NotifyFromAsyncThread("This socket is not yet connected.", NotifyType::Error);
return;
}
try
{
dataWriter->WriteString(msg);
_notify->NotifyFromAsyncThread("Sending - " + msg, NotifyType::Status);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Sending failed with error: " + ex->Message, NotifyType::Error);
}
// Write the locally buffered data to the network. Please note that write operation will succeed
// even if the server is not listening.
create_task(dataWriter->StoreAsync()).then(
[this](task<unsigned int> writeTask)
{
try
{
// Try getting an exception.
writeTask.get();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Send failed with error: " + ex->Message, NotifyType::Error);
}
});
}
Windows::Storage::Streams::DataWriter^
DatagramClientContext::GetDataWriter()
{
if (_dataWriter == nullptr)
{
_dataWriter = ref new DataWriter(_client->OutputStream);
}
return _dataWriter;
}
@@ -0,0 +1,78 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "IClientContext.h"
#include "IAsyncThreadNotify.h"
#include "ClientArgs.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class DatagramClientContext sealed : public IClientContext
{
public:
using DatagramSocket = Windows::Networking::Sockets::DatagramSocket;
DatagramClientContext(IAsyncThreadNotify^ notify, DatagramSocket^ client, ClientArgs^ args);
virtual ~DatagramClientContext();
virtual void Connect_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual void Send_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e, Platform::String^ input);
virtual Windows::Foundation::IAsyncAction^ CancelIO();
private:
using MessageReceivedEventArgs = Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs;
using MessageHandler = Windows::Foundation::TypedEventHandler<DatagramSocket^, MessageReceivedEventArgs^>;
using DataReader = Windows::Storage::Streams::DataReader;
using DataWriter = Windows::Storage::Streams::DataWriter;
using Args = ClientArgs;
void SetConnected(bool connected);
bool IsConnected() const;
void OnMessage(DatagramSocket^ socket, MessageReceivedEventArgs^ eventArgs);
void Receive(DataReader^, unsigned int strLen);
void SendMessage(DataWriter^, String^ msg);
DataWriter^ GetDataWriter();
IAsyncThreadNotify^ _notify;
DatagramSocket^ _client;
Args^ _args;
bool _connected = false;
DataReader^ _dataReader;
DataWriter^ _dataWriter;
};
} // namespace Thread
@@ -0,0 +1,278 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include "DatagramListenerContext.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Networking::Sockets;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
DatagramListenerContext::DatagramListenerContext(
IAsyncThreadNotify^ notify,
DatagramSocket^ listener,
ListenerArgs^ args) :
_notify{ std::move(notify) },
_listener{ std::move(listener) },
_args{ std::move(args) }
{
}
DatagramListenerContext::~DatagramListenerContext()
{
// A Listener can be closed in two ways:
// - explicitly: using the 'delete' keyword (listener is closed even if there are outstanding references to it).
// - implicitly: removing the last reference to it (i.e., falling out-of-scope).
//
// When a Socket is closed implicitly, it can take several seconds for the local port being used
// by it to be freed/reclaimed by the lower networking layers. During that time, other sockets on the machine
// will not be able to use the port. Thus, it is strongly recommended that Socket instances be explicitly
// closed before they go out of scope(e.g., before application exit). The call below explicitly closes the socket.
if (_listener != nullptr)
{
delete _listener;
_listener = nullptr;
}
}
void
DatagramListenerContext::Listen_Click(
Object^ sender,
RoutedEventArgs^ e)
{
task<void> removeContext;
if (CoreApplication::Properties->HasKey("listenerContext"))
{
auto listenerContext = dynamic_cast<IListenerContext^>(
CoreApplication::Properties->Lookup("listenerContext"));
if (listenerContext == nullptr)
{
throw ref new FailureException(L"No listenerContext");
}
removeContext = create_task(listenerContext->CancelIO()).then(
[]()
{
CoreApplication::Properties->Remove("listenerContext");
});
}
else
{
removeContext = create_task([]() {});
}
_listener->MessageReceived += ref new MessageHandler(
this, &DatagramListenerContext::OnMessage);
removeContext.then([this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
// Events cannot be hooked up directly to the ScenarioInput1 object, as the object can fall out-of-scope and be
// deleted. This would render any event hooked up to the object ineffective. The ListenerContext guarantees that
// both the listener and object that serves its events have the same lifetime.
CoreApplication::Properties->Insert("listenerContext", this);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Remove listenerContext error: " + ex->Message,
NotifyType::Error);
}
catch (task_canceled&)
{
}
}).then([this]()
{
_notify->NotifyFromAsyncThread("Start listening", NotifyType::Status);
create_task(_listener->BindEndpointAsync(_args->ServerHostName, _args->ServerPort)).then(
[this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
_notify->NotifyFromAsyncThread(
"Listening on address " + _args->ServerHostName->CanonicalName,
NotifyType::Status);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Start listening failed with error: " + ex->Message,
NotifyType::Error);
CoreApplication::Properties->Remove("listenerContext");
}
});
});
}
IAsyncAction^
DatagramListenerContext::CancelIO()
{
return _listener->CancelIOAsync();
}
void
DatagramListenerContext::OnMessage(
DatagramSocket^ socket,
MessageReceivedEventArgs^ eventArgs)
{
if (_outputStream != nullptr)
{
auto dataReader = eventArgs->GetDataReader();
Receive(dataReader, dataReader->UnconsumedBufferLength, GetDataWriter());
return;
}
// We do not have an output stream yet so create one.
create_task(socket->GetOutputStreamAsync(eventArgs->RemoteAddress, eventArgs->RemotePort)).then(
[this, socket, eventArgs](IOutputStream^ stream)
{
{
std::lock_guard<mutex_t> lock(_mtx);
// It might happen that the OnMessage was invoked more than once before the GetOutputStreamAsync call
// completed. In this case we will end up with multiple streams - just keep one of them.
if (_outputStream == nullptr)
{
_outputStream = stream;
}
}
auto dataReader = eventArgs->GetDataReader();
Receive(dataReader, dataReader->UnconsumedBufferLength, GetDataWriter());
}).then([this](task<void> prevTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
prevTask.get();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("On message with an error: " + ex->Message,
NotifyType::Error);
}
catch (task_canceled&)
{
// Do not print anything here - this will usually happen because user closed the client socket.
}
});
}
void
DatagramListenerContext::Receive(
DataReader^ dataReader,
unsigned int strLen,
DataWriter^ dataWriter)
{
if (!strLen)
{
return;
}
auto msg = dataReader->ReadString(strLen);
_notify->NotifyFromAsyncThread("Received data from client: \"" + msg + "\"",
NotifyType::Status);
auto echo = CreateEchoMessage(msg);
EchoMessage(dataWriter, echo);
}
String^
DatagramListenerContext::CreateEchoMessage(
String^ msg)
{
wchar_t buf[256];
auto len = swprintf_s(buf, L"Server%s received data from client : \"%s\"",
_args->ServerName->IsEmpty() ? L"" : (" " + _args->ServerName)->Data(), msg->Data());
len += swprintf_s(&buf[len], _countof(buf) - len, L" - got %d chars",
msg->Length());
return ref new String(buf);
}
void
DatagramListenerContext::EchoMessage(
DataWriter^ dataWriter,
String^ echo)
{
try
{
dataWriter->WriteString(echo);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Echoing failed with error: " + ex->Message,
NotifyType::Error);
}
create_task(dataWriter->StoreAsync()).then(
[this](task<unsigned int> writeTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
writeTask.get();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Echo message with an error: " + ex->Message,
NotifyType::Error);
}
});
}
Windows::Storage::Streams::DataWriter^
DatagramListenerContext::GetDataWriter()
{
if (_dataWriter == nullptr)
{
_dataWriter = ref new DataWriter(_outputStream);
}
return _dataWriter;
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <mutex>
#include "IListenerContext.h"
#include "IAsyncThreadNotify.h"
#include "ListenerArgs.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class DatagramListenerContext sealed : public IListenerContext
{
public:
using DatagramSocket = Windows::Networking::Sockets::DatagramSocket;
DatagramListenerContext(IAsyncThreadNotify^ notify, DatagramSocket^ listener, ListenerArgs^ args);
virtual ~DatagramListenerContext();
virtual void Listen_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual Windows::Foundation::IAsyncAction^ CancelIO();
private:
using MessageReceivedEventArgs = Windows::Networking::Sockets::DatagramSocketMessageReceivedEventArgs;
using MessageHandler = Windows::Foundation::TypedEventHandler<DatagramSocket^, MessageReceivedEventArgs^>;
using DataReader = Windows::Storage::Streams::DataReader;
using DataWriter = Windows::Storage::Streams::DataWriter;
using IOutputStream = Windows::Storage::Streams::IOutputStream;
using Listener = DatagramSocket;
using Args = ListenerArgs;
using mutex_t = std::mutex;
void OnMessage(DatagramSocket^ socket, MessageReceivedEventArgs^ eventArgs);
void Receive(DataReader^, unsigned int strLen, DataWriter^);
String^ CreateEchoMessage(String^ msg);
void EchoMessage(DataWriter^, String^ echo);
DataWriter^ GetDataWriter();
IAsyncThreadNotify^ _notify;
Listener^ _listener;
Args^ _args;
DataWriter^ _dataWriter;
mutable mutex_t _mtx;
// mutex protected data
IOutputStream^ _outputStream;
};
} // namespace Thread
+86
View File
@@ -0,0 +1,86 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include "Factory.h"
#include "StreamListenerContext.h"
#include "DatagramListenerContext.h"
#include "StreamClientContext.h"
#include "DatagramClientContext.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Networking::Sockets;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
IListenerContext^
Factory::CreateListenerContext(
IAsyncThreadNotify^ notify,
ListenerArgs^ listenerArgs,
Protocol protocol)
{
if (protocol == Protocol::TCP)
{
auto listener = ref new StreamSocketListener();
return ref new StreamListenerContext(notify, listener, listenerArgs);
}
else
{
auto listener = ref new DatagramSocket();
return ref new DatagramListenerContext(notify, listener, listenerArgs);
}
}
IClientContext^
Factory::CreateClientContext(
IAsyncThreadNotify^ notify,
ClientArgs^ clientArgs,
Protocol protocol)
{
if (protocol == Protocol::TCP)
{
auto client = ref new StreamSocket();
return ref new StreamClientContext(notify, client, clientArgs);
}
else
{
auto client = ref new DatagramSocket();
return ref new DatagramClientContext(notify, client, clientArgs);
}
}
+49
View File
@@ -0,0 +1,49 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "IAsyncThreadNotify.h"
#include "ListenerArgs.h"
#include "IListenerContext.h"
#include "ClientArgs.h"
#include "IClientContext.h"
#include "Protocol.h"
namespace Thread
{
class Factory
{
public:
static IListenerContext^ CreateListenerContext(IAsyncThreadNotify^, ListenerArgs^, Protocol);
static IClientContext^ CreateClientContext(IAsyncThreadNotify^, ClientArgs^, Protocol);
};
} // namespace Thread
@@ -0,0 +1,45 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public enum class NotifyType
{
Status,
Error,
};
public interface struct IAsyncThreadNotify
{
void NotifyFromAsyncThread(Platform::String^ message, NotifyType type);
};
} // namespace Thread
+43
View File
@@ -0,0 +1,43 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public interface struct IClientContext
{
void Connect_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void Send_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e, Platform::String^ input);
Windows::Foundation::IAsyncAction^ CancelIO();
};
} // namespace Thread
+41
View File
@@ -0,0 +1,41 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public interface struct IListenerContext
{
void Listen_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
Windows::Foundation::IAsyncAction^ CancelIO();
};
} // namespace Thread
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public interface struct IMainPageUIElements
{
property Windows::UI::Xaml::UIElement^ ThreadGrid
{
Windows::UI::Xaml::UIElement^ get();
}
property Windows::UI::Xaml::UIElement^ TalkGrid
{
Windows::UI::Xaml::UIElement^ get();
}
};
} // namespace Thread
+42
View File
@@ -0,0 +1,42 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public ref class ListenerArgs sealed
{
public:
property Platform::String^ ServerName;
property Windows::Networking::HostName^ ServerHostName;
property Platform::String^ ServerPort;
};
} // namespace Thread
+251 -234
View File
@@ -35,256 +35,273 @@
IsTabStop="false"
mc:Ignorable="d">
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid>
<Grid.Background>
<ImageBrush ImageSource="ms-appx:///Assets/Wide310x150Logo.png" Opacity="0.25" Stretch="Uniform"/>
</Grid.Background>
</Grid>
<Grid>
<Grid.Background>
<ImageBrush ImageSource="ms-appx:///Assets/Wide310x150Logo.png" Opacity="0.25" Stretch="Uniform"/>
</Grid.Background>
<!-- Interface List -->
<TextBlock
Text="Thread UX"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
FontSize="50"
/>
<TextBlock
Text="Interfaces"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="60,90"
FontSize="25"
/>
<ListView
Name="InterfaceList"
Margin="60,130,20,150"
SelectionMode="None">
</ListView>
<!-- Interface Configuration -->
<Grid
x:Name="InterfaceConfiguration"
Background="#B2FFFFFF"
Visibility="Collapsed"
<Grid
x:Name="ThrdGrid"
>
<TextBlock
Text="Thread UX"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
FontSize="50"
/>
<StackPanel
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
Width="600"
Height="360"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Orientation="Horizontal"
VerticalAlignment="Top"
>
<TextBlock
Text="Interface Configuration"
Text="Interfaces"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
Margin="60,90"
FontSize="25"
/>
<Grid Margin="40,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock
Text="Name"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBox
Name="InterfaceConfigName"
Text="Test Network"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="Key"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="1"
/>
<TextBox
Name="InterfaceConfigKey"
Text="00112233445566778899aabbccddeeff"
Grid.Row="1"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="Max Children"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="2"
/>
<Slider
Name="InterfaceConfigMaxChildren"
Grid.Row="2"
Grid.Column="1"
Minimum="0"
Maximum="32"
Value="16"
VerticalAlignment="Center"
/>
<TextBlock
Text="Channel"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="3"
/>
<Slider
Name="InterfaceConfigChannel"
Grid.Row="3"
Grid.Column="1"
Minimum="11"
Maximum="24"
Value="11"
VerticalAlignment="Center"
/>
<StackPanel
Grid.Row="5"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
Name="InterfaceConfigOkButton"
Content="Ok"
FontSize="22"
Margin="20,0"
/>
<Button
Name="InterfaceConfigCancelButton"
Content="Cancel"
FontSize="22"
Margin="20,0"
/>
</StackPanel>
</Grid>
<Button
x:Name="Talk"
Content="Talk"
Margin="10,0"
/>
</StackPanel>
</Grid>
<ListView
Name="InterfaceList"
Margin="60,130,20,150"
SelectionMode="None">
</ListView>
<!-- Interface Details -->
<Grid
x:Name="InterfaceDetails"
Background="#B2FFFFFF"
Visibility="Collapsed"
>
<StackPanel
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
Width="600"
Height="405"
HorizontalAlignment="Center"
VerticalAlignment="Center"
<!-- Interface Configuration -->
<Grid
x:Name="InterfaceConfiguration"
Background="#B2FFFFFF"
Visibility="Collapsed"
>
<TextBlock
Text="Interface Details"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
FontSize="25"
/>
<Grid Margin="40,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<StackPanel
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
Width="600"
Height="360"
HorizontalAlignment="Center"
VerticalAlignment="Center"
>
<TextBlock
Text="MAC"
FontSize="22"
VerticalAlignment="Center"
Text="Interface Configuration"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
FontSize="25"
/>
<Grid Margin="40,10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock
Text="Name"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBox
Name="InterfaceConfigName"
Text="Test Network"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="Key"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="1"
/>
<TextBox
Name="InterfaceConfigKey"
Text="00112233445566778899aabbccddeeff"
Grid.Row="1"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="Max Children"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="2"
/>
<Slider
Name="InterfaceConfigMaxChildren"
Grid.Row="2"
Grid.Column="1"
Minimum="0"
Maximum="32"
Value="16"
VerticalAlignment="Center"
/>
<TextBlock
Text="Channel"
FontSize="22"
VerticalAlignment="Center"
Grid.Row="3"
/>
<Slider
Name="InterfaceConfigChannel"
Grid.Row="3"
Grid.Column="1"
Minimum="11"
Maximum="24"
Value="11"
VerticalAlignment="Center"
/>
<StackPanel
Grid.Row="5"
Grid.ColumnSpan="2"
HorizontalAlignment="Center"
Orientation="Horizontal">
<Button
Name="InterfaceConfigOkButton"
Content="Ok"
FontSize="22"
Margin="20,0"
/>
<Button
Name="InterfaceConfigCancelButton"
Content="Cancel"
FontSize="22"
Margin="20,0"
/>
</StackPanel>
</Grid>
</StackPanel>
</Grid>
<!-- Interface Details -->
<Grid
x:Name="InterfaceDetails"
Background="#B2FFFFFF"
Visibility="Collapsed"
>
<StackPanel
Background="{StaticResource ApplicationPageBackgroundThemeBrush}"
Width="600"
Height="405"
HorizontalAlignment="Center"
VerticalAlignment="Center"
>
<TextBlock
Name="InterfaceMacAddress"
Text="00:00:00:00:00:00:00:00"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
Text="Interface Details"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Margin="20"
FontSize="25"
/>
<TextBlock
Text="ML-EID"
Grid.Row="1"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceML_EID"
Text="::01"
Grid.Row="1"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="RLOC"
Grid.Row="2"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceRLOC"
Text="::01"
Grid.Row="2"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceNeighborsText"
Text="Neighbors"
Grid.Row="3"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceNeighbors"
Text="0"
Grid.Row="3"
Grid.Column="1"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceChildrenText"
Text="Children"
Grid.Row="4"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceChildren"
Text="0"
Grid.Row="4"
Grid.Column="1"
FontSize="22"
VerticalAlignment="Center"
/>
<Button
Name="InterfaceDetailsCloseButton"
Grid.Row="6"
Grid.ColumnSpan="2"
Content="Close"
HorizontalAlignment="Center"
FontSize="22"
/>
</Grid>
</StackPanel>
<Grid Margin="40,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="200"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<TextBlock
Text="MAC"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceMacAddress"
Text="00:00:00:00:00:00:00:00"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="ML-EID"
Grid.Row="1"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceML_EID"
Text="::01"
Grid.Row="1"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Text="RLOC"
Grid.Row="2"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceRLOC"
Text="::01"
Grid.Row="2"
Grid.Column="1"
FontSize="18"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceNeighborsText"
Text="Neighbors"
Grid.Row="3"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceNeighbors"
Text="0"
Grid.Row="3"
Grid.Column="1"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceChildrenText"
Text="Children"
Grid.Row="4"
FontSize="22"
VerticalAlignment="Center"
/>
<TextBlock
Name="InterfaceChildren"
Text="0"
Grid.Row="4"
Grid.Column="1"
FontSize="22"
VerticalAlignment="Center"
/>
<Button
Name="InterfaceDetailsCloseButton"
Grid.Row="6"
Grid.ColumnSpan="2"
Content="Close"
HorizontalAlignment="Center"
FontSize="22"
/>
</Grid>
</StackPanel>
</Grid>
</Grid>
<local:TalkGrid
x:Name="TlkGrid"
Margin="20"
Visibility="Collapsed"
/>
</Grid>
</Page>
+22
View File
@@ -28,6 +28,7 @@
#include "pch.h"
#include "MainPage.xaml.h"
#include "TalkGrid.xaml.h"
using namespace Thread;
@@ -82,6 +83,15 @@ MainPage::MainPage() : _otApi(nullptr)
this->InterfaceDetails->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
}
);
Talk->Click +=
ref new RoutedEventHandler(
[=](Platform::Object^, RoutedEventArgs^) {
this->ThreadGrid->Visibility = Windows::UI::Xaml::Visibility::Collapsed;
this->TalkGrid->Visibility = Windows::UI::Xaml::Visibility::Visible;
}
);
TlkGrid->Init(this);
}
void MainPage::OnNavigatedTo(NavigationEventArgs^ e)
@@ -395,3 +405,15 @@ void MainPage::DisconnectNetwork(otAdapter^ adapter)
}
}
Windows::UI::Xaml::UIElement^
MainPage::ThreadGrid::get()
{
return ThrdGrid;
}
Windows::UI::Xaml::UIElement^
MainPage::TalkGrid::get()
{
return TlkGrid;
}
+13 -2
View File
@@ -29,13 +29,14 @@
#pragma once
#include "MainPage.g.h"
#include "IMainPageUIElements.h"
namespace Thread
{
/// <summary>
/// An empty page that can be used on its own or navigated to within a Frame.
/// </summary>
public ref class MainPage sealed
public ref class MainPage sealed : public IMainPageUIElements
{
public:
MainPage();
@@ -46,7 +47,17 @@ namespace Thread
void ShowInterfaceDetails(otAdapter^ adapter);
void DisconnectNetwork(otAdapter^ adapter);
protected:
property Windows::UI::Xaml::UIElement^ ThreadGrid
{
virtual Windows::UI::Xaml::UIElement^ get();
}
property Windows::UI::Xaml::UIElement^ TalkGrid
{
virtual Windows::UI::Xaml::UIElement^ get();
}
protected:
virtual void OnNavigatedTo(Windows::UI::Xaml::Navigation::NavigationEventArgs^ e) override;
private:
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
public enum class Protocol
{
TCP,
UDP,
};
} // namespace Thread
+12 -1
View File
@@ -1,6 +1,6 @@
# OpenThread App for Windows #
This sample app provides an example of how to interface with the OpenThread API in a
This sample app provides an example of how to interface with the OpenThread API and talk to each other in a
[Universal Windows App](https://developer.microsoft.com/en-us/windows/apps). The app is written in C++ /CX
and provides a simple wrapper around the OpenThread API, hiding the raw C/C++ interface.
@@ -13,3 +13,14 @@ The details list provides some more information, including extended MAC address,
about the current children.
![Interface List](../../../doc/images/windows-app-details.png)
The "Talk" button of main page switches the user interface to the talk fuctionality. This app acts
either as a server or a client role and talks to each other over a TCP or a UDP protocol.
The server listens to the clients.
![Talk Functionality](../../../doc/images/windows-app-talk-server.png)
The client sends a message to the server and the server echos that message back to the client.
![Talk Functionality](../../../doc/images/windows-app-talk-client.png)
+106
View File
@@ -0,0 +1,106 @@
<!--
Copyright (c) 2016, The OpenThread Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->
<UserControl
x:Class="Thread.ServerControl"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Thread"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock
Grid.Row="0"
Grid.Column="0"
Text="Server Name :"
/>
<TextBox
Grid.Row="0"
Grid.Column="2"
x:Name="ServerName"
Width="300"
HorizontalAlignment="Left"
/>
<TextBlock
Grid.Row="2"
Grid.Column="0"
Text="Server IP :"
/>
<TextBox
Grid.Row="2"
Grid.Column="2"
x:Name="ServerIP"
MinWidth="500"
/>
<TextBlock
Grid.Row="4"
Grid.Column="0"
Text="Server Port :"
/>
<TextBox
Grid.Row="4"
Grid.Column="2"
x:Name="ServerPort"
Width="100"
HorizontalAlignment="Left"
/>
<StackPanel
Orientation="Horizontal"
VerticalAlignment="Top"
Grid.Row="6"
Grid.Column="0"
Grid.ColumnSpan="3"
>
<Button
Width="75"
Content="Listen"
Click="Listen_Click"
Margin="0,0,75,0"
/>
<Button
Width="75"
Content="Exit"
Click="Exit_Click"
/>
</StackPanel>
</Grid>
</UserControl>
@@ -0,0 +1,124 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include <algorithm>
#include "ServerControl.xaml.h"
#include "Factory.h"
#include "TalkHelper.h"
using namespace Thread;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
ServerControl::ServerControl()
{
InitializeComponent();
ServerPort->Text = DEF_PORT.ToString();
}
void
ServerControl::Init(
IAsyncThreadNotify^ notify,
IMainPageUIElements^ mainPageUIElements)
{
_notify = std::move(notify);
_mainPageUIElements = std::move(mainPageUIElements);
}
void
ServerControl::ProtocolChanged(
Protocol protocol)
{
_protocol = protocol;
}
void
ServerControl::Listen_Click(
Object^ sender,
RoutedEventArgs^ e)
{
try
{
auto listenerArgs = ref new ListenerArgs();
listenerArgs->ServerName = ServerName->Text;
auto serverIP = ServerIP->Text;
if (serverIP->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Server IP");
}
// check valid chars of Ipv6 Address
if (!TalkHelper::AllValidIpv6Chars(serverIP->Data(), serverIP->Data() + serverIP->Length()))
{
throw Exception::CreateException(E_INVALIDARG, "Not a valid Server IPv6 address");
}
listenerArgs->ServerHostName = ref new HostName(serverIP);
if (ServerPort->Text->IsEmpty())
{
throw Exception::CreateException(E_INVALIDARG, "No Server Port");
}
listenerArgs->ServerPort = ServerPort->Text;
auto listenerContext = Factory::CreateListenerContext(_notify, listenerArgs, _protocol);
listenerContext->Listen_Click(sender, e);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Listening failed with input error: " + ex->Message,
NotifyType::Error);
}
}
void
ServerControl::Exit_Click(
Object^ sender,
RoutedEventArgs^ e)
{
_mainPageUIElements->TalkGrid->Visibility = Xaml::Visibility::Collapsed;
_mainPageUIElements->ThreadGrid->Visibility = Xaml::Visibility::Visible;
}
@@ -0,0 +1,62 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "ServerControl.g.h"
#include "TalkConsts.h"
#include "IAsyncThreadNotify.h"
#include "IMainPageUIElements.h"
#include "Protocol.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class ServerControl sealed
{
public:
ServerControl();
void Init(IAsyncThreadNotify^ notify, IMainPageUIElements^ mainPageUIElements);
void ProtocolChanged(Protocol protocol);
private:
static constexpr unsigned short DEF_PORT = TalkConsts::DEF_SERVER_PORT;
void Listen_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
void Exit_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
IAsyncThreadNotify^ _notify;
IMainPageUIElements^ _mainPageUIElements;
Protocol _protocol;
};
} // namespace Thread
@@ -0,0 +1,325 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include "StreamClientContext.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Networking::Sockets;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
StreamClientContext::StreamClientContext(
IAsyncThreadNotify^ notify,
StreamSocket^ client,
ClientArgs^ args) :
_notify{ std::move(notify) },
_client{ std::move(client) },
_args{ std::move(args) }
{
}
StreamClientContext::~StreamClientContext()
{
// A Client can be closed in two ways:
// - explicitly: using the 'delete' keyword (client is closed even if there are outstanding references to it).
// - implicitly: removing the last reference to it (i.e., falling out-of-scope).
//
// When a Socket is closed implicitly, it can take several seconds for the local port being used
// by it to be freed/reclaimed by the lower networking layers. During that time, other sockets on the machine
// will not be able to use the port. Thus, it is strongly recommended that Socket instances be explicitly
// closed before they go out of scope(e.g., before application exit). The call below explicitly closes the socket.
if (_client != nullptr)
{
delete _client;
_client = nullptr;
}
}
void
StreamClientContext::Connect_Click(
Object^ sender,
RoutedEventArgs^ e)
{
task<void> removeContext;
if (CoreApplication::Properties->HasKey("clientContext"))
{
auto clientContext = dynamic_cast<IClientContext^>(
CoreApplication::Properties->Lookup("clientContext"));
if (clientContext == nullptr)
{
throw ref new FailureException(L"No clientContext");
}
removeContext = create_task(clientContext->CancelIO()).then(
[]()
{
CoreApplication::Properties->Remove("clientContext");
});
}
else
{
removeContext = create_task([]() {});
}
removeContext.then([this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
// Events cannot be hooked up directly to the ScenarioInput2 object, as the object can fall out-of-scope and be
// deleted. This would render any event hooked up to the object ineffective. The ClientContext guarantees that
// both the socket and object that serves its events have the same lifetime.
CoreApplication::Properties->Insert("clientContext", this);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Remove clientContext error: " + ex->Message,
NotifyType::Error);
}
catch (task_canceled&)
{
}
}).then([this]()
{
auto endpointPair = ref new EndpointPair(_args->ClientHostName, _args->ClientPort,
_args->ServerHostName, _args->ServerPort);
_notify->NotifyFromAsyncThread("Start connecting", NotifyType::Status);
create_task(_client->ConnectAsync(endpointPair)).then(
[this, endpointPair](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
_notify->NotifyFromAsyncThread(
"Connect from " + endpointPair->LocalHostName->CanonicalName +
" to " + endpointPair->RemoteHostName->CanonicalName,
NotifyType::Status);
OnConnection(_client);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Start binding failed with error: " + ex->Message,
NotifyType::Error);
CoreApplication::Properties->Remove("clientContext");
}
catch (task_canceled&)
{
CoreApplication::Properties->Remove("clientContext");
}
});
});
}
void
Thread::StreamClientContext::Send_Click(
Platform::Object^ sender,
Windows::UI::Xaml::RoutedEventArgs^ e,
Platform::String^ input)
{
SendMessage(GetDataWriter(), input);
}
IAsyncAction^
Thread::StreamClientContext::CancelIO()
{
return _client->CancelIOAsync();
}
void
StreamClientContext::OnConnection(
StreamSocket^ streamSocket)
{
SetConnected(true);
ReceiveLoop(streamSocket, GetDataReader());
}
void
StreamClientContext::SetConnected(
bool connected)
{
_connected = connected;
}
bool
StreamClientContext::IsConnected() const
{
return _connected;
}
void
StreamClientContext::ReceiveLoop(
StreamSocket^ streamSocket,
DataReader^ dataReader)
{
// Read first 4 bytes (length of the subsequent string).
create_task(dataReader->LoadAsync(sizeof(UINT32))).then(
[this, dataReader](unsigned int size)
{
if (size < sizeof(UINT32))
{
// The underlying socket was closed before we were able to read the whole data.
cancel_current_task();
}
auto strLen = dataReader->ReadUInt32();
return create_task(dataReader->LoadAsync(strLen)).then(
[this, dataReader, strLen](unsigned int actualStrLen)
{
if (actualStrLen != strLen)
{
// The underlying socket was closed before we were able to read the whole data.
cancel_current_task();
}
Receive(dataReader, strLen);
});
}).then([this, streamSocket, dataReader](task<void> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
// Everything went ok, so try to receive another string. The receive will continue until the stream is
// broken (i.e. peer closed the socket).
ReceiveLoop(streamSocket, dataReader);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Read stream failed with error: " + ex->Message,
NotifyType::Error);
// Explicitly close the socket.
delete streamSocket;
}
catch (task_canceled&)
{
// Do not print anything here - this will usually happen because user closed the client socket.
// Explicitly close the socket.
delete streamSocket;
}
});
}
void
StreamClientContext::Receive(
DataReader^ dataReader,
unsigned int strLen)
{
if (!strLen)
{
return;
}
auto msg = dataReader->ReadString(strLen);
_notify->NotifyFromAsyncThread("Received data from server: \"" + msg + "\"",
NotifyType::Status);
}
void
StreamClientContext::SendMessage(
DataWriter^ dataWriter,
String^ msg)
{
if (!IsConnected())
{
_notify->NotifyFromAsyncThread("This socket is not yet connected.", NotifyType::Error);
return;
}
try
{
dataWriter->WriteUInt32(msg->Length());
dataWriter->WriteString(msg);
_notify->NotifyFromAsyncThread("Sending - " + msg, NotifyType::Status);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Sending failed with error: " + ex->Message, NotifyType::Error);
}
// Write the locally buffered data to the network. Please note that write operation will succeed
// even if the server is not listening.
create_task(dataWriter->StoreAsync()).then(
[this](task<unsigned int> writeTask)
{
try
{
// Try getting an exception.
writeTask.get();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Send failed with error: " + ex->Message, NotifyType::Error);
}
});
}
Windows::Storage::Streams::DataReader^
StreamClientContext::GetDataReader()
{
if (_dataReader == nullptr)
{
_dataReader = ref new DataReader(_client->InputStream);
}
return _dataReader;
}
Windows::Storage::Streams::DataWriter^
StreamClientContext::GetDataWriter()
{
if (_dataWriter == nullptr)
{
_dataWriter = ref new DataWriter(_client->OutputStream);
}
return _dataWriter;
}
@@ -0,0 +1,79 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "IClientContext.h"
#include "IAsyncThreadNotify.h"
#include "ClientArgs.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class StreamClientContext sealed : public IClientContext
{
public:
using StreamSocket = Windows::Networking::Sockets::StreamSocket;
StreamClientContext(IAsyncThreadNotify^ notify, StreamSocket^ client, ClientArgs^ args);
virtual ~StreamClientContext();
virtual void Connect_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual void Send_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e, Platform::String^ input);
virtual Windows::Foundation::IAsyncAction^ CancelIO();
private:
using DataReader = Windows::Storage::Streams::DataReader;
using DataWriter = Windows::Storage::Streams::DataWriter;
using Args = ClientArgs;
void OnConnection(StreamSocket^);
void SetConnected(bool connected);
bool IsConnected() const;
void ReceiveLoop(StreamSocket^, DataReader^);
void Receive(DataReader^, unsigned int strLen);
void SendMessage(DataWriter^, String^ msg);
DataReader^ GetDataReader();
DataWriter^ GetDataWriter();
IAsyncThreadNotify^ _notify;
StreamSocket^ _client;
Args^ _args;
bool _connected = false;
DataReader^ _dataReader;
DataWriter^ _dataWriter;
};
} // namespace Thread
@@ -0,0 +1,288 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include <utility>
#include "StreamListenerContext.h"
using namespace Thread;
using namespace Concurrency;
using namespace Platform;
using namespace Windows::ApplicationModel::Core;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::Networking::Sockets;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
StreamListenerContext::StreamListenerContext(
IAsyncThreadNotify^ notify,
StreamSocketListener^ listener,
ListenerArgs^ args) :
_notify{ std::move(notify) },
_listener{ std::move(listener) },
_args{ std::move(args) }
{
}
StreamListenerContext::~StreamListenerContext()
{
// A Listener can be closed in two ways:
// - explicitly: using the 'delete' keyword (listener is closed even if there are outstanding references to it).
// - implicitly: removing the last reference to it (i.e., falling out-of-scope).
//
// When a Socket is closed implicitly, it can take several seconds for the local port being used
// by it to be freed/reclaimed by the lower networking layers. During that time, other sockets on the machine
// will not be able to use the port. Thus, it is strongly recommended that Socket instances be explicitly
// closed before they go out of scope(e.g., before application exit). The call below explicitly closes the socket.
if (_listener != nullptr)
{
delete _listener;
_listener = nullptr;
}
}
void
StreamListenerContext::Listen_Click(
Object^ sender,
RoutedEventArgs^ e)
{
task<void> removeContext;
if (CoreApplication::Properties->HasKey("listenerContext"))
{
auto listenerContext = dynamic_cast<IListenerContext^>(
CoreApplication::Properties->Lookup("listenerContext"));
if (listenerContext == nullptr)
{
throw ref new FailureException(L"No listenerContext");
}
removeContext = create_task(listenerContext->CancelIO()).then(
[]()
{
CoreApplication::Properties->Remove("listenerContext");
});
}
else
{
removeContext = create_task([]() {});
}
_listener->ConnectionReceived += ref new ConnectionHandler(
this, &StreamListenerContext::OnConnection);
removeContext.then([this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
// Events cannot be hooked up directly to the ScenarioInput1 object, as the object can fall out-of-scope and be
// deleted. This would render any event hooked up to the object ineffective. The ListenerContext guarantees that
// both the listener and object that serves its events have the same lifetime.
CoreApplication::Properties->Insert("listenerContext", this);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Remove listenerContext error: " + ex->Message,
NotifyType::Error);
}
catch (task_canceled&)
{
}
}).then([this]()
{
_notify->NotifyFromAsyncThread("Start listening", NotifyType::Status);
create_task(_listener->BindEndpointAsync(_args->ServerHostName, _args->ServerPort)).then(
[this](task<void> prevTask)
{
try
{
// Try getting an exception.
prevTask.get();
_notify->NotifyFromAsyncThread(
"Listening on address " + _args->ServerHostName->CanonicalName,
NotifyType::Status);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread(
"Start listening failed with error: " + ex->Message,
NotifyType::Error);
CoreApplication::Properties->Remove("listenerContext");
}
});
});
}
IAsyncAction^
StreamListenerContext::CancelIO()
{
return _listener->CancelIOAsync();
}
void
StreamListenerContext::OnConnection(
StreamSocketListener^ listener,
ConnectionReceivedEventArgs^ args)
{
auto dataReader = ref new DataReader(args->Socket->InputStream);
auto dataWriter = ref new DataWriter(args->Socket->OutputStream);
ReceiveLoop(args->Socket, dataReader, dataWriter);
}
void
StreamListenerContext::ReceiveLoop(
StreamSocket^ streamSocket,
DataReader^ dataReader,
DataWriter^ dataWriter)
{
// Read first 4 bytes (length of the subsequent string).
create_task(dataReader->LoadAsync(sizeof(UINT32))).then(
[this, streamSocket, dataReader, dataWriter](unsigned int size)
{
if (size < sizeof(UINT32))
{
// The underlying socket was closed before we were able to read the whole data.
cancel_current_task();
}
unsigned int strLen = dataReader->ReadUInt32();
return create_task(dataReader->LoadAsync(strLen)).then(
[this, dataReader, dataWriter, strLen](unsigned int actualStrLen)
{
if (actualStrLen != strLen)
{
// The underlying socket was closed before we were able to read the whole data.
cancel_current_task();
}
Receive(dataReader, strLen, dataWriter);
});
}).then([this, streamSocket, dataReader, dataWriter](task<void> previousTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
previousTask.get();
// Everything went ok, so try to receive another string. The receive will continue until the stream is
// broken (i.e. peer closed the socket).
ReceiveLoop(streamSocket, dataReader, dataWriter);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Read stream failed with error: " + ex->Message,
NotifyType::Error);
// Explicitly close the socket.
delete streamSocket;
}
catch (task_canceled&)
{
// Do not print anything here - this will usually happen because user closed the client socket.
// Explicitly close the socket.
delete streamSocket;
}
});
}
void
StreamListenerContext::Receive(
DataReader^ dataReader,
unsigned int strLen,
DataWriter^ dataWriter)
{
if (!strLen)
{
return;
}
auto msg = dataReader->ReadString(strLen);
_notify->NotifyFromAsyncThread("Received data from client: \"" + msg + "\"",
NotifyType::Status);
auto echo = CreateEchoMessage(msg);
EchoMessage(dataWriter, echo);
}
String^
StreamListenerContext::CreateEchoMessage(
String^ msg)
{
wchar_t buf[256];
auto len = swprintf_s(buf, L"Server%s received data from client : \"%s\"",
_args->ServerName->IsEmpty() ? L"" : (" " + _args->ServerName)->Data(), msg->Data());
len += swprintf_s(&buf[len], _countof(buf) - len, L" - got %d chars",
msg->Length());
return ref new String(buf);
}
void
StreamListenerContext::EchoMessage(
DataWriter^ dataWriter,
String^ echo)
{
try
{
dataWriter->WriteUInt32(echo->Length());
dataWriter->WriteString(echo);
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Echoing failed with error: " + ex->Message,
NotifyType::Error);
}
create_task(dataWriter->StoreAsync()).then(
[this](task<unsigned int> writeTask)
{
try
{
// Try getting all exceptions from the continuation chain above this point.
writeTask.get();
}
catch (Exception^ ex)
{
_notify->NotifyFromAsyncThread("Echo message with an error: " + ex->Message,
NotifyType::Error);
}
});
}
@@ -0,0 +1,71 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "IListenerContext.h"
#include "IAsyncThreadNotify.h"
#include "ListenerArgs.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class StreamListenerContext sealed : public IListenerContext
{
public:
using StreamSocketListener = Windows::Networking::Sockets::StreamSocketListener;
StreamListenerContext(IAsyncThreadNotify^ notify, StreamSocketListener^ listener, ListenerArgs^ args);
virtual ~StreamListenerContext();
virtual void Listen_Click(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
virtual Windows::Foundation::IAsyncAction^ CancelIO();
private:
using ConnectionReceivedEventArgs = Windows::Networking::Sockets::StreamSocketListenerConnectionReceivedEventArgs;
using ConnectionHandler = Windows::Foundation::TypedEventHandler<StreamSocketListener^, ConnectionReceivedEventArgs^>;
using DataReader = Windows::Storage::Streams::DataReader;
using DataWriter = Windows::Storage::Streams::DataWriter;
using Listener = StreamSocketListener;
using StreamSocket = Windows::Networking::Sockets::StreamSocket;
using Args = ListenerArgs;
void OnConnection(StreamSocketListener^ listener, ConnectionReceivedEventArgs^ args);
void ReceiveLoop(StreamSocket^, DataReader^, DataWriter^);
void Receive(DataReader^, unsigned int strLen, DataWriter^);
String^ CreateEchoMessage(String^ msg);
void EchoMessage(DataWriter^, String^ echo);
IAsyncThreadNotify^ _notify;
Listener^ _listener;
Args^ _args;
};
} // namespace Thread
+40
View File
@@ -0,0 +1,40 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
struct TalkConsts
{
static constexpr unsigned short DEF_SERVER_PORT = 51000;
static constexpr unsigned short DEF_CLIENT_PORT_INIT = 51100;
};
} // namespace Thread
+108
View File
@@ -0,0 +1,108 @@
<!--
Copyright (c) 2016, The OpenThread Authors.
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the copyright holder nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
POSSIBILITY OF SUCH DAMAGE.
-->
<Grid
x:Class="Thread.TalkGrid"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Thread"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<StackPanel
Grid.Row="0"
Orientation="Horizontal"
VerticalAlignment="Top"
>
<RadioButton
x:Name="TcpRadio"
Content="TCP"
GroupName="ProtocolGroup"
Checked="Protocol_Changed"
Margin="0,0,20,0"
/>
<RadioButton
x:Name="UdpRadio"
Content="UDP"
GroupName="ProtocolGroup"
Checked="Protocol_Changed"
Margin="0,0,20,0"
/>
</StackPanel>
<StackPanel
Grid.Row="2"
Orientation="Horizontal"
VerticalAlignment="Top"
>
<RadioButton
x:Name="ServerRadio"
Content="Server"
GroupName="RoleGroup"
Checked="Role_Changed"
Margin="0,0,20,0"
/>
<RadioButton
x:Name="ClientRadio"
Content="Client"
GroupName="RoleGroup"
Checked="Role_Changed"
Margin="0,0,20,0"
/>
</StackPanel>
<local:ServerControl
x:Name="ServerRole"
Grid.Row="4"
Visibility="Collapsed"
/>
<local:ClientControl
x:Name="ClientRole"
Grid.Row="4"
Visibility="Collapsed"
/>
<Border
x:Name="StatusBorder"
Grid.Row="6"
>
<TextBlock
x:Name="StatusBlock"
FontWeight="Bold"
Text=""
FontSize="16"
TextWrapping="Wrap"
MaxHeight="80"
/>
</Border>
</Grid>
+150
View File
@@ -0,0 +1,150 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include "pch.h"
#include "TalkGrid.xaml.h"
#include "ClientControl.xaml.h"
#include "ServerControl.xaml.h"
using namespace Thread;
using namespace Platform;
using namespace Windows::Foundation;
using namespace Windows::Foundation::Collections;
using namespace Windows::UI;
using namespace Windows::UI::Core;
using namespace Windows::UI::Xaml;
using namespace Windows::UI::Xaml::Controls;
using namespace Windows::UI::Xaml::Controls::Primitives;
using namespace Windows::UI::Xaml::Data;
using namespace Windows::UI::Xaml::Input;
using namespace Windows::UI::Xaml::Media;
using namespace Windows::UI::Xaml::Navigation;
// The User Control item template is documented at http://go.microsoft.com/fwlink/?LinkId=234236
TalkGrid::TalkGrid()
{
InitializeComponent();
TcpRadio->IsChecked = true;
ServerRadio->IsChecked = true;
}
void
TalkGrid::Init(
IMainPageUIElements^ mainPageUIElements)
{
ServerRole->Init(this, mainPageUIElements);
ClientRole->Init(this, mainPageUIElements);
}
void
TalkGrid::NotifyFromAsyncThread(
String^ message,
NotifyType type)
{
Dispatcher->RunAsync(CoreDispatcherPriority::Normal,
ref new DispatchedHandler([this, message, type]()
{
Notify(message, type);
}));
}
void
TalkGrid::Notify(
String^ message,
NotifyType type)
{
switch (type)
{
case NotifyType::Status:
StatusBorder->Background = ref new SolidColorBrush(Colors::Green);
break;
case NotifyType::Error:
StatusBorder->Background = ref new SolidColorBrush(Colors::Red);
break;
default:
break;
}
StatusBlock->Text = message;
// Collapse the StatusBlock if it has no text to conserve real estate.
if (StatusBlock->Text != "")
{
StatusBorder->Visibility = Xaml::Visibility::Visible;
}
else
{
StatusBorder->Visibility = Xaml::Visibility::Collapsed;
}
}
void
TalkGrid::Protocol_Changed(
Object^ sender,
RoutedEventArgs^ e)
{
auto radioBtn = dynamic_cast<RadioButton^>(sender);
if (!radioBtn)
{
return;
}
auto protocol = (radioBtn == TcpRadio) ? Protocol::TCP : Protocol::UDP;
ServerRole->ProtocolChanged(protocol);
ClientRole->ProtocolChanged(protocol);
}
void
TalkGrid::Role_Changed(
Object^ sender,
RoutedEventArgs^ e)
{
auto radioBtn = dynamic_cast<RadioButton^>(sender);
if (!radioBtn)
{
return;
}
if (radioBtn == ServerRadio)
{
// switch to server role UI
ClientRole->Visibility = Xaml::Visibility::Collapsed;
ServerRole->Visibility = Xaml::Visibility::Visible;
}
else
{
// switch to client role UI
ServerRole->Visibility = Xaml::Visibility::Collapsed;
ClientRole->Visibility = Xaml::Visibility::Visible;
}
}
+61
View File
@@ -0,0 +1,61 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include "TalkGrid.g.h"
#include "IAsyncThreadNotify.h"
#include "IMainPageUIElements.h"
#include "Protocol.h"
namespace Thread
{
[Windows::Foundation::Metadata::WebHostHidden]
public ref class TalkGrid sealed : public IAsyncThreadNotify
{
public:
TalkGrid();
void Init(IMainPageUIElements^ mainPageUIElements);
// IAsyncThreadMessage
virtual void NotifyFromAsyncThread(String^ message, NotifyType type);
void Notify(String^ message, NotifyType type);
private:
// change protocol
// TCP <-> UDP
void Protocol_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
// change role from server client (or vice versa)
void Role_Changed(Platform::Object^ sender, Windows::UI::Xaml::RoutedEventArgs^ e);
};
} // namespace Thread
+63
View File
@@ -0,0 +1,63 @@
/*
* Copyright (c) 2016, The OpenThread Authors.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
namespace Thread
{
ref class ClientControl;
ref class ServerControl;
class TalkHelper
{
private:
friend ref class ClientControl;
friend ref class ServerControl;
// this is a private method for specific usage, not a general purpose one
// checks all chars are valid Ipv6 chars in the range [begin, end)
static bool AllValidIpv6Chars(const wchar_t* begin, const wchar_t* end)
{
for (auto it = begin; it != end; ++it)
{
auto c = *it;
if ((c >= '0' && c <= '9') || (c == ':') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
{
}
else
{
return false;
}
}
return true;
}
};
}
+3 -3
View File
@@ -344,9 +344,9 @@ public:
void set(String^ value)
{
char name[OT_NETWORK_NAME_MAX_SIZE + 1];
auto err = WideCharToMultiByte(CP_UTF8, WC_NO_BEST_FIT_CHARS, value->Data(), -1, name, ARRAYSIZE(name), nullptr, nullptr);
if (err == 0) ThrowOnFailure(otThreadSetNetworkName(DeviceInstance, name));
else throw Exception::CreateException(E_INVALIDARG);
auto len = WideCharToMultiByte(CP_UTF8, 0, value->Data(), -1, name, ARRAYSIZE(name), nullptr, nullptr);
if (len <= 0) throw Exception::CreateException(E_INVALIDARG);
ThrowOnFailure(otThreadSetNetworkName(DeviceInstance, name));
}
}