Skip to content

Commit 026f571

Browse files
lwilkovichlwwilkov
and
lwwilkov
authored
Tunnel Notification Sample (#201)
* Tunnel Notification Sample * Update for namespace fix Co-authored-by: lwwilkov <[email protected]>
1 parent 171ec02 commit 026f571

File tree

9 files changed

+324
-9
lines changed

9 files changed

+324
-9
lines changed

devicedefender/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,11 @@ install(EXPORT "IotDeviceDefender-cpp-targets"
115115
NAMESPACE AWS::
116116
COMPONENT Development)
117117

118-
configure_file("cmake/IotDeviceDefender-cpp-config.cmake"
119-
"${CMAKE_CURRENT_BINARY_DIR}/IotDeviceDefender-cpp-config.cmake"
118+
configure_file("cmake/iotdevicedefender-cpp-config.cmake"
119+
"${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake"
120120
@ONLY)
121121

122-
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/IotDeviceDefender-cpp-config.cmake"
122+
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicedefender-cpp-config.cmake"
123123
DESTINATION "lib/IotDeviceDefender-cpp/cmake/"
124124
COMPONENT Development)
125125

iotdevicecommon/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -111,10 +111,10 @@ install(EXPORT "IotDeviceCommon-cpp-targets"
111111
NAMESPACE AWS::
112112
COMPONENT Development)
113113

114-
configure_file("cmake/IotDeviceCommon-cpp-config.cmake"
115-
"${CMAKE_CURRENT_BINARY_DIR}/IotDeviceCommon-cpp-config.cmake"
114+
configure_file("cmake/iotdevicecommon-cpp-config.cmake"
115+
"${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake"
116116
@ONLY)
117117

118-
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/IotDeviceCommon-cpp-config.cmake"
118+
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotdevicecommon-cpp-config.cmake"
119119
DESTINATION "lib/IotDeviceCommon-cpp/cmake/"
120120
COMPONENT Development)

samples/README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,16 @@ and receive.
340340
</pre>
341341
</details>
342342

343+
## Secure Tunneling
344+
345+
This sample uses the AWS IoT [Secure Tunneling](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling.html) Service to receive a tunnel notification.
346+
347+
This sample requires you to create a tunnel for your thing. See [instructions here](https://docs.aws.amazon.com/iot/latest/developerguide/secure-tunneling-tutorial.html).
348+
349+
On startup, the sample will wait until it receives, and then displays the tunnel notification.
350+
351+
Source: `samples/secure_tunneling`
352+
343353
## Greengrass discovery
344354

345355
This sample is intended for direct usage with the Greengrass tutorial found [here](https://docs.aws.amazon.com/greengrass/latest/developerguide/gg-gs.html).
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
cmake_minimum_required(VERSION 3.1)
2+
# note: cxx-17 requires cmake 3.8, cxx-20 requires cmake 3.12
3+
project(tunnel-notification CXX)
4+
5+
file(GLOB SRC_FILES
6+
"*.cpp"
7+
)
8+
9+
add_executable(${PROJECT_NAME} ${SRC_FILES})
10+
11+
set_target_properties(${PROJECT_NAME} PROPERTIES
12+
CXX_STANDARD 14)
13+
14+
#set warnings
15+
if (MSVC)
16+
target_compile_options(${PROJECT_NAME} PRIVATE /W4 /WX)
17+
else ()
18+
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wno-long-long -pedantic -Werror)
19+
endif ()
20+
21+
find_package(aws-crt-cpp REQUIRED)
22+
find_package(IotDeviceCommon-cpp REQUIRED)
23+
find_package(IotSecureTunneling-cpp REQUIRED)
24+
25+
install(TARGETS ${PROJECT_NAME} DESTINATION bin)
26+
27+
target_link_libraries(${PROJECT_NAME} PRIVATE AWS::aws-crt-cpp AWS::IotDeviceCommon-cpp AWS::IotSecureTunneling-cpp)

samples/secure_tunneling/main.cpp

Lines changed: 278 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,278 @@
1+
/**
2+
* Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3+
* SPDX-License-Identifier: Apache-2.0.
4+
*/
5+
6+
#include <aws/crt/Api.h>
7+
#include <aws/crt/UUID.h>
8+
#include <aws/crt/io/HostResolver.h>
9+
10+
#include <aws/iot/MqttClient.h>
11+
12+
#include <aws/iotsecuretunneling/IotSecureTunnelingClient.h>
13+
#include <aws/iotsecuretunneling/SecureTunnelingNotifyResponse.h>
14+
#include <aws/iotsecuretunneling/SubscribeToTunnelsNotifyRequest.h>
15+
#include <iostream>
16+
17+
#include <algorithm>
18+
#include <condition_variable>
19+
#include <iostream>
20+
#include <mutex>
21+
22+
using namespace std;
23+
using namespace Aws::Iot;
24+
using namespace Aws::Crt;
25+
using namespace Aws::Crt::Mqtt;
26+
using namespace Aws::Iotsecuretunneling;
27+
28+
static void s_printHelp()
29+
{
30+
fprintf(stdout, "Usage:\n");
31+
fprintf(
32+
stdout,
33+
"tunnel-notification --endpoint <endpoint> --cert <path to cert>"
34+
" --key <path to key> --ca_file <optional: path to custom ca>"
35+
" --thing_name <thing name> \n\n");
36+
fprintf(stdout, "endpoint: the endpoint of the mqtt server not including a port\n");
37+
fprintf(stdout, "cert: path to your client certificate in PEM format\n");
38+
fprintf(stdout, "key: path to your key in PEM format\n");
39+
fprintf(
40+
stdout,
41+
"ca_file: Optional, if the mqtt server uses a certificate that's not already"
42+
" in your trust store, set this.\n");
43+
fprintf(stdout, "\tIt's the path to a CA file in PEM format\n");
44+
fprintf(stdout, "thing_name: the name of your IOT thing\n");
45+
}
46+
47+
bool s_cmdOptionExists(char **begin, char **end, const String &option)
48+
{
49+
return std::find(begin, end, option) != end;
50+
}
51+
52+
char *s_getCmdOption(char **begin, char **end, const String &option)
53+
{
54+
char **itr = std::find(begin, end, option);
55+
if (itr != end && ++itr != end)
56+
{
57+
return *itr;
58+
}
59+
return 0;
60+
}
61+
62+
int main(int argc, char *argv[])
63+
{
64+
/************************ Setup the Lib ****************************/
65+
/*
66+
* Do the global initialization for the API.
67+
*/
68+
ApiHandle apiHandle;
69+
70+
String endpoint;
71+
String certificatePath;
72+
String keyPath;
73+
String caFile;
74+
String clientId(String("test-") + Aws::Crt::UUID().ToString());
75+
String thingName;
76+
77+
/*********************** Parse Arguments ***************************/
78+
if (!(s_cmdOptionExists(argv, argv + argc, "--endpoint") && s_cmdOptionExists(argv, argv + argc, "--cert") &&
79+
s_cmdOptionExists(argv, argv + argc, "--key") && s_cmdOptionExists(argv, argv + argc, "--thing_name")))
80+
{
81+
s_printHelp();
82+
return 0;
83+
}
84+
85+
endpoint = s_getCmdOption(argv, argv + argc, "--endpoint");
86+
certificatePath = s_getCmdOption(argv, argv + argc, "--cert");
87+
keyPath = s_getCmdOption(argv, argv + argc, "--key");
88+
thingName = s_getCmdOption(argv, argv + argc, "--thing_name");
89+
90+
if (s_cmdOptionExists(argv, argv + argc, "--ca_file"))
91+
{
92+
caFile = s_getCmdOption(argv, argv + argc, "--ca_file");
93+
}
94+
95+
/********************** Now Setup an Mqtt Client ******************/
96+
/*
97+
* You need an event loop group to process IO events.
98+
* If you only have a few connections, 1 thread is ideal
99+
*/
100+
Io::EventLoopGroup eventLoopGroup(1);
101+
if (!eventLoopGroup)
102+
{
103+
fprintf(
104+
stderr, "Event Loop Group Creation failed with error %s\n", ErrorDebugString(eventLoopGroup.LastError()));
105+
exit(-1);
106+
}
107+
108+
Io::DefaultHostResolver defaultHostResolver(eventLoopGroup, 2, 30);
109+
Io::ClientBootstrap bootstrap(eventLoopGroup, defaultHostResolver);
110+
111+
if (!bootstrap)
112+
{
113+
fprintf(stderr, "ClientBootstrap failed with error %s\n", ErrorDebugString(bootstrap.LastError()));
114+
exit(-1);
115+
}
116+
117+
auto clientConfigBuilder = Aws::Iot::MqttClientConnectionConfigBuilder(certificatePath.c_str(), keyPath.c_str());
118+
clientConfigBuilder.WithEndpoint(endpoint);
119+
if (!caFile.empty())
120+
{
121+
clientConfigBuilder.WithCertificateAuthority(caFile.c_str());
122+
}
123+
auto clientConfig = clientConfigBuilder.Build();
124+
125+
if (!clientConfig)
126+
{
127+
fprintf(
128+
stderr,
129+
"Client Configuration initialization failed with error %s\n",
130+
ErrorDebugString(clientConfig.LastError()));
131+
exit(-1);
132+
}
133+
134+
/*
135+
* Now Create a client. This can not throw.
136+
* An instance of a client must outlive its connections.
137+
* It is the users responsibility to make sure of this.
138+
*/
139+
Aws::Iot::MqttClient mqttClient(bootstrap);
140+
141+
/*
142+
* Since no exceptions are used, always check the bool operator
143+
* when an error could have occurred.
144+
*/
145+
if (!mqttClient)
146+
{
147+
fprintf(stderr, "MQTT Client Creation failed with error %s\n", ErrorDebugString(mqttClient.LastError()));
148+
exit(-1);
149+
}
150+
151+
/*
152+
* Now create a connection object. Note: This type is move only
153+
* and its underlying memory is managed by the client.
154+
*/
155+
auto connection = mqttClient.NewConnection(clientConfig);
156+
157+
if (!*connection)
158+
{
159+
fprintf(stderr, "MQTT Connection Creation failed with error %s\n", ErrorDebugString(connection->LastError()));
160+
exit(-1);
161+
}
162+
163+
/*
164+
* In a real world application you probably don't want to enforce synchronous behavior
165+
* but this is a sample console application, so we'll just do that with a condition variable.
166+
*/
167+
std::promise<bool> connectionCompletedPromise;
168+
std::promise<void> connectionClosedPromise;
169+
170+
/*
171+
* This will execute when an mqtt connect has completed or failed.
172+
*/
173+
auto onConnectionCompleted = [&](Mqtt::MqttConnection &, int errorCode, Mqtt::ReturnCode returnCode, bool) {
174+
if (errorCode)
175+
{
176+
fprintf(stdout, "Connection failed with error %s\n", ErrorDebugString(errorCode));
177+
connectionCompletedPromise.set_value(false);
178+
}
179+
else
180+
{
181+
fprintf(stdout, "Connection completed with return code %d\n", returnCode);
182+
connectionCompletedPromise.set_value(true);
183+
}
184+
};
185+
186+
/*
187+
* Invoked when a disconnect message has completed.
188+
*/
189+
auto onDisconnect = [&](Mqtt::MqttConnection & /*conn*/) {
190+
{
191+
fprintf(stdout, "Disconnect completed\n");
192+
connectionClosedPromise.set_value();
193+
}
194+
};
195+
196+
connection->OnConnectionCompleted = std::move(onConnectionCompleted);
197+
connection->OnDisconnect = std::move(onDisconnect);
198+
199+
/*
200+
* Actually perform the connect dance.
201+
*/
202+
fprintf(stdout, "Connecting...\n");
203+
if (!connection->Connect(clientId.c_str(), true, 0))
204+
{
205+
fprintf(stderr, "MQTT Connection failed with error %s\n", ErrorDebugString(connection->LastError()));
206+
exit(-1);
207+
}
208+
209+
auto onSubscribeToTunnelsNotifyResponse = [&](Aws::Iotsecuretunneling::SecureTunnelingNotifyResponse *response,
210+
int ioErr) -> void {
211+
if (ioErr == 0)
212+
{
213+
fprintf(stdout, "Received MQTT Tunnel Notification\n");
214+
215+
std::string clientAccessToken = response->ClientAccessToken->c_str();
216+
std::string clientMode = response->ClientMode->c_str();
217+
std::string region = response->Region->c_str();
218+
219+
fprintf(
220+
stdout,
221+
"Recv: Token:%s, Mode:%s, Region:%s\n",
222+
clientAccessToken.c_str(),
223+
clientMode.c_str(),
224+
region.c_str());
225+
226+
size_t nServices = response->Services->size();
227+
if (nServices <= 0)
228+
{
229+
fprintf(stdout, "No service requested\n");
230+
}
231+
else
232+
{
233+
std::string service = response->Services->at(0).c_str();
234+
fprintf(stdout, "Requested service=%s\n", service.c_str());
235+
236+
if (nServices > 1)
237+
{
238+
fprintf(stdout, "Multiple services not supported yet\n");
239+
}
240+
}
241+
}
242+
else
243+
{
244+
fprintf(stderr, "MQTT Connection failed with error %d\n", ioErr);
245+
}
246+
/* Disconnect */
247+
if (connection->Disconnect())
248+
{
249+
connectionClosedPromise.get_future().wait();
250+
}
251+
};
252+
253+
auto OnSubscribeComplete = [&](int ioErr) -> void {
254+
if (ioErr)
255+
{
256+
fprintf(stderr, "MQTT Connection failed with error %d\n", ioErr);
257+
}
258+
/* Disconnect */
259+
if (connection->Disconnect())
260+
{
261+
connectionClosedPromise.get_future().wait();
262+
}
263+
};
264+
265+
if (connectionCompletedPromise.get_future().get())
266+
{
267+
SubscribeToTunnelsNotifyRequest request;
268+
request.ThingName = thingName;
269+
270+
IotSecureTunnelingClient client(connection);
271+
client.SubscribeToTunnelsNotify(
272+
request, AWS_MQTT_QOS_AT_LEAST_ONCE, onSubscribeToTunnelsNotifyResponse, OnSubscribeComplete);
273+
}
274+
while (1)
275+
{
276+
continue;
277+
}
278+
}

secure_tunneling/CMakeLists.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -115,11 +115,11 @@ install(EXPORT "IotSecureTunneling-cpp-targets"
115115
NAMESPACE AWS::
116116
COMPONENT Development)
117117

118-
configure_file("cmake/IotSecureTunneling-cpp-config.cmake"
119-
"${CMAKE_CURRENT_BINARY_DIR}/IotSecureTunneling-cpp-config.cmake"
118+
configure_file("cmake/iotsecuretunneling-cpp-config.cmake"
119+
"${CMAKE_CURRENT_BINARY_DIR}/iotsecuretunneling-cpp-config.cmake"
120120
@ONLY)
121121

122-
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/IotSecureTunneling-cpp-config.cmake"
122+
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/iotsecuretunneling-cpp-config.cmake"
123123
DESTINATION "lib/IotSecureTunneling-cpp/cmake/"
124124
COMPONENT Development)
125125

0 commit comments

Comments
 (0)