diff --git a/doc/images/windows-app-details.png b/doc/images/windows-app-details.png
index be3e3c5fb..a8be63924 100644
Binary files a/doc/images/windows-app-details.png and b/doc/images/windows-app-details.png differ
diff --git a/doc/images/windows-app-interface-list.png b/doc/images/windows-app-interface-list.png
index 8fdde7d13..be71b98cc 100644
Binary files a/doc/images/windows-app-interface-list.png and b/doc/images/windows-app-interface-list.png differ
diff --git a/doc/images/windows-app-talk-client.png b/doc/images/windows-app-talk-client.png
new file mode 100644
index 000000000..f59a24f9c
Binary files /dev/null and b/doc/images/windows-app-talk-client.png differ
diff --git a/doc/images/windows-app-talk-server.png b/doc/images/windows-app-talk-server.png
new file mode 100644
index 000000000..7496344c9
Binary files /dev/null and b/doc/images/windows-app-talk-server.png differ
diff --git a/etc/visual-studio/OpenThread.vcxproj b/etc/visual-studio/OpenThread.vcxproj
index f2a392e57..ba8beba6b 100644
--- a/etc/visual-studio/OpenThread.vcxproj
+++ b/etc/visual-studio/OpenThread.vcxproj
@@ -59,6 +59,19 @@
+
+
+ ..\..\examples\apps\windows\ClientControl.xaml
+
+
+
+
+
+
+
+
+
+
@@ -68,14 +81,33 @@
..\..\examples\apps\windows\MainPage.xaml
+
+ ..\..\examples\apps\windows\ServerControl.xaml
+
+
+
+
+
+ ..\..\examples\apps\windows\TalkGrid.xaml
+
+ Designer
+
+ Designer
+ Designer
+
+ Designer
+
+
+ Designer
+
@@ -96,12 +128,26 @@
..\..\examples\apps\windows\App.xaml
+
+ ..\..\examples\apps\windows\ClientControl.xaml
+
+
+
+ ..\..\examples\apps\windows\MainPage.xamlCreate
+
+ ..\..\examples\apps\windows\ServerControl.xaml
+
+
+
+
+ ..\..\examples\apps\windows\TalkGrid.xaml
+
diff --git a/etc/visual-studio/OpenThread.vcxproj.filters b/etc/visual-studio/OpenThread.vcxproj.filters
index 6fc36479f..5fb431551 100644
--- a/etc/visual-studio/OpenThread.vcxproj.filters
+++ b/etc/visual-studio/OpenThread.vcxproj.filters
@@ -16,6 +16,14 @@
+
+
+
+
+
+
+
+
@@ -23,6 +31,23 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -55,5 +80,8 @@
+
+
+
\ No newline at end of file
diff --git a/examples/apps/windows/ClientArgs.h b/examples/apps/windows/ClientArgs.h
new file mode 100644
index 000000000..6b11c9336
--- /dev/null
+++ b/examples/apps/windows/ClientArgs.h
@@ -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
diff --git a/examples/apps/windows/ClientControl.xaml b/examples/apps/windows/ClientControl.xaml
new file mode 100644
index 000000000..927ba48a8
--- /dev/null
+++ b/examples/apps/windows/ClientControl.xaml
@@ -0,0 +1,142 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/apps/windows/ClientControl.xaml.cpp b/examples/apps/windows/ClientControl.xaml.cpp
new file mode 100644
index 000000000..9b5c7310a
--- /dev/null
+++ b/examples/apps/windows/ClientControl.xaml.cpp
@@ -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
+#include
+#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 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(
+ 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;
+}
diff --git a/examples/apps/windows/ClientControl.xaml.h b/examples/apps/windows/ClientControl.xaml.h
new file mode 100644
index 000000000..305e51527
--- /dev/null
+++ b/examples/apps/windows/ClientControl.xaml.h
@@ -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
+#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 _clientPort;
+};
+
+} // namespace Thread
diff --git a/examples/apps/windows/DatagramClientContext.cpp b/examples/apps/windows/DatagramClientContext.cpp
new file mode 100644
index 000000000..8fa94f145
--- /dev/null
+++ b/examples/apps/windows/DatagramClientContext.cpp
@@ -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
+#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 removeContext;
+
+ if (CoreApplication::Properties->HasKey("clientContext"))
+ {
+ auto clientContext = dynamic_cast(
+ 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 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 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 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;
+}
diff --git a/examples/apps/windows/DatagramClientContext.h b/examples/apps/windows/DatagramClientContext.h
new file mode 100644
index 000000000..c9b4f6cfb
--- /dev/null
+++ b/examples/apps/windows/DatagramClientContext.h
@@ -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;
+ 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
diff --git a/examples/apps/windows/DatagramListenerContext.cpp b/examples/apps/windows/DatagramListenerContext.cpp
new file mode 100644
index 000000000..16e781481
--- /dev/null
+++ b/examples/apps/windows/DatagramListenerContext.cpp
@@ -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
+#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 removeContext;
+
+ if (CoreApplication::Properties->HasKey("listenerContext"))
+ {
+ auto listenerContext = dynamic_cast(
+ 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 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 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 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 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 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;
+}
diff --git a/examples/apps/windows/DatagramListenerContext.h b/examples/apps/windows/DatagramListenerContext.h
new file mode 100644
index 000000000..b4bd22a96
--- /dev/null
+++ b/examples/apps/windows/DatagramListenerContext.h
@@ -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
+#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;
+ 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
diff --git a/examples/apps/windows/Factory.cpp b/examples/apps/windows/Factory.cpp
new file mode 100644
index 000000000..0d424cef0
--- /dev/null
+++ b/examples/apps/windows/Factory.cpp
@@ -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);
+ }
+}
diff --git a/examples/apps/windows/Factory.h b/examples/apps/windows/Factory.h
new file mode 100644
index 000000000..c0f85d537
--- /dev/null
+++ b/examples/apps/windows/Factory.h
@@ -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
diff --git a/examples/apps/windows/IAsyncThreadNotify.h b/examples/apps/windows/IAsyncThreadNotify.h
new file mode 100644
index 000000000..e2645a071
--- /dev/null
+++ b/examples/apps/windows/IAsyncThreadNotify.h
@@ -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
diff --git a/examples/apps/windows/IClientContext.h b/examples/apps/windows/IClientContext.h
new file mode 100644
index 000000000..d987da2b7
--- /dev/null
+++ b/examples/apps/windows/IClientContext.h
@@ -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
diff --git a/examples/apps/windows/IListenerContext.h b/examples/apps/windows/IListenerContext.h
new file mode 100644
index 000000000..5ea044947
--- /dev/null
+++ b/examples/apps/windows/IListenerContext.h
@@ -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
diff --git a/examples/apps/windows/IMainPageUIElements.h b/examples/apps/windows/IMainPageUIElements.h
new file mode 100644
index 000000000..4c3df16c1
--- /dev/null
+++ b/examples/apps/windows/IMainPageUIElements.h
@@ -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
diff --git a/examples/apps/windows/ListenerArgs.h b/examples/apps/windows/ListenerArgs.h
new file mode 100644
index 000000000..9ffa21d9d
--- /dev/null
+++ b/examples/apps/windows/ListenerArgs.h
@@ -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
diff --git a/examples/apps/windows/MainPage.xaml b/examples/apps/windows/MainPage.xaml
index 73698f02e..7be179d18 100644
--- a/examples/apps/windows/MainPage.xaml
+++ b/examples/apps/windows/MainPage.xaml
@@ -35,256 +35,273 @@
IsTabStop="false"
mc:Ignorable="d">
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
+
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/apps/windows/MainPage.xaml.cpp b/examples/apps/windows/MainPage.xaml.cpp
index 0a10da12a..95dffef50 100644
--- a/examples/apps/windows/MainPage.xaml.cpp
+++ b/examples/apps/windows/MainPage.xaml.cpp
@@ -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;
+}
diff --git a/examples/apps/windows/MainPage.xaml.h b/examples/apps/windows/MainPage.xaml.h
index 57d1b8402..644422dce 100644
--- a/examples/apps/windows/MainPage.xaml.h
+++ b/examples/apps/windows/MainPage.xaml.h
@@ -29,13 +29,14 @@
#pragma once
#include "MainPage.g.h"
+#include "IMainPageUIElements.h"
namespace Thread
{
///
/// An empty page that can be used on its own or navigated to within a Frame.
///
- 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:
diff --git a/examples/apps/windows/Protocol.h b/examples/apps/windows/Protocol.h
new file mode 100644
index 000000000..afcde2250
--- /dev/null
+++ b/examples/apps/windows/Protocol.h
@@ -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
diff --git a/examples/apps/windows/README.md b/examples/apps/windows/README.md
index bc6926e79..e1b3f698b 100644
--- a/examples/apps/windows/README.md
+++ b/examples/apps/windows/README.md
@@ -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.

+
+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.
+
+
+
+The client sends a message to the server and the server echos that message back to the client.
+
+
\ No newline at end of file
diff --git a/examples/apps/windows/ServerControl.xaml b/examples/apps/windows/ServerControl.xaml
new file mode 100644
index 000000000..5c866fc52
--- /dev/null
+++ b/examples/apps/windows/ServerControl.xaml
@@ -0,0 +1,106 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/apps/windows/ServerControl.xaml.cpp b/examples/apps/windows/ServerControl.xaml.cpp
new file mode 100644
index 000000000..d931109a1
--- /dev/null
+++ b/examples/apps/windows/ServerControl.xaml.cpp
@@ -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
+#include
+#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;
+}
diff --git a/examples/apps/windows/ServerControl.xaml.h b/examples/apps/windows/ServerControl.xaml.h
new file mode 100644
index 000000000..79458a422
--- /dev/null
+++ b/examples/apps/windows/ServerControl.xaml.h
@@ -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
diff --git a/examples/apps/windows/StreamClientContext.cpp b/examples/apps/windows/StreamClientContext.cpp
new file mode 100644
index 000000000..ccce0fa4c
--- /dev/null
+++ b/examples/apps/windows/StreamClientContext.cpp
@@ -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
+#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 removeContext;
+
+ if (CoreApplication::Properties->HasKey("clientContext"))
+ {
+ auto clientContext = dynamic_cast(
+ 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 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 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 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 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;
+}
diff --git a/examples/apps/windows/StreamClientContext.h b/examples/apps/windows/StreamClientContext.h
new file mode 100644
index 000000000..892baad74
--- /dev/null
+++ b/examples/apps/windows/StreamClientContext.h
@@ -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
diff --git a/examples/apps/windows/StreamListenerContext.cpp b/examples/apps/windows/StreamListenerContext.cpp
new file mode 100644
index 000000000..7bb04b85d
--- /dev/null
+++ b/examples/apps/windows/StreamListenerContext.cpp
@@ -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
+#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 removeContext;
+
+ if (CoreApplication::Properties->HasKey("listenerContext"))
+ {
+ auto listenerContext = dynamic_cast(
+ 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 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 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 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 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);
+ }
+ });
+}
diff --git a/examples/apps/windows/StreamListenerContext.h b/examples/apps/windows/StreamListenerContext.h
new file mode 100644
index 000000000..3fd1a51c6
--- /dev/null
+++ b/examples/apps/windows/StreamListenerContext.h
@@ -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;
+ 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
diff --git a/examples/apps/windows/TalkConsts.h b/examples/apps/windows/TalkConsts.h
new file mode 100644
index 000000000..6b9b29ebe
--- /dev/null
+++ b/examples/apps/windows/TalkConsts.h
@@ -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
diff --git a/examples/apps/windows/TalkGrid.xaml b/examples/apps/windows/TalkGrid.xaml
new file mode 100644
index 000000000..a391f3366
--- /dev/null
+++ b/examples/apps/windows/TalkGrid.xaml
@@ -0,0 +1,108 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/examples/apps/windows/TalkGrid.xaml.cpp b/examples/apps/windows/TalkGrid.xaml.cpp
new file mode 100644
index 000000000..efc7c8ea8
--- /dev/null
+++ b/examples/apps/windows/TalkGrid.xaml.cpp
@@ -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(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(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;
+ }
+}
diff --git a/examples/apps/windows/TalkGrid.xaml.h b/examples/apps/windows/TalkGrid.xaml.h
new file mode 100644
index 000000000..72ea34e48
--- /dev/null
+++ b/examples/apps/windows/TalkGrid.xaml.h
@@ -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
diff --git a/examples/apps/windows/TalkHelper.h b/examples/apps/windows/TalkHelper.h
new file mode 100644
index 000000000..96da077e8
--- /dev/null
+++ b/examples/apps/windows/TalkHelper.h
@@ -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;
+ }
+};
+
+}
\ No newline at end of file
diff --git a/examples/apps/windows/otAdapter.h b/examples/apps/windows/otAdapter.h
index 746cd5eab..17b0a89c3 100644
--- a/examples/apps/windows/otAdapter.h
+++ b/examples/apps/windows/otAdapter.h
@@ -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));
}
}