|
1 | 1 | // Copyright 2018 Amazon.com, Inc. or its affiliates. All Rights Reserved. |
2 | 2 | // SPDX-License-Identifier: Apache-2.0 |
3 | 3 | #include "TcpAdapterProxy.h" |
| 4 | +#include "InputValidation.h" |
4 | 5 | #include "ProxySettings.h" |
5 | 6 | #include "WebProxyAdapter.h" |
6 | 7 | #include "config/ConfigFile.h" |
7 | 8 | #include <boost/algorithm/string.hpp> |
8 | 9 | #include <boost/asio.hpp> |
| 10 | +#ifndef _WIN32 |
| 11 | +#include <boost/asio/local/stream_protocol.hpp> |
| 12 | +#include <unistd.h> // for close() and unlink() |
| 13 | +#endif |
9 | 14 | #include <boost/asio/ssl/host_name_verification.hpp> |
10 | 15 | #include <boost/beast/core/flat_buffer.hpp> |
11 | 16 | #include <boost/beast/websocket.hpp> |
@@ -3147,6 +3152,92 @@ namespace iot { |
3147 | 3152 | ); |
3148 | 3153 | } |
3149 | 3154 |
|
| 3155 | +#ifndef _WIN32 |
| 3156 | + void tcp_adapter_proxy::connect_and_setup_unix_socket( |
| 3157 | + tcp_adapter_context &tac, |
| 3158 | + std::shared_ptr<basic_retry_config> retry_config, |
| 3159 | + const string &service_id, |
| 3160 | + const uint32_t &connection_id, |
| 3161 | + const std::string &socket_path |
| 3162 | + ) { |
| 3163 | + BOOST_LOG_SEV(log, trace) |
| 3164 | + << "Connecting to Unix domain socket: " << socket_path |
| 3165 | + << " for service id: " << service_id |
| 3166 | + << " connection id: " << connection_id; |
| 3167 | + |
| 3168 | + tcp_client::pointer client |
| 3169 | + = tac.serviceId_to_tcp_client_map[service_id]; |
| 3170 | + |
| 3171 | + // Create a Unix domain socket and connect |
| 3172 | + boost::asio::local::stream_protocol::socket unix_socket(tac.io_ctx); |
| 3173 | + boost::system::error_code connect_ec; |
| 3174 | + |
| 3175 | + try { |
| 3176 | + unix_socket.connect( |
| 3177 | + boost::asio::local::stream_protocol::endpoint(socket_path), |
| 3178 | + connect_ec |
| 3179 | + ); |
| 3180 | + |
| 3181 | + if (connect_ec) { |
| 3182 | + BOOST_LOG_SEV(log, error) |
| 3183 | + << (boost::format( |
| 3184 | + "Could not connect to Unix socket %1% -- %2%" |
| 3185 | + ) |
| 3186 | + % socket_path % connect_ec.message()) |
| 3187 | + .str(); |
| 3188 | + basic_retry_execute( |
| 3189 | + log, retry_config, [this, &tac, service_id]() { |
| 3190 | + BOOST_LOG_SEV(log, trace) |
| 3191 | + << "resetting stream for service id:" |
| 3192 | + << service_id |
| 3193 | + << ", then listen for stream start"; |
| 3194 | + async_send_stream_reset(tac, service_id); |
| 3195 | + setup_tcp_socket(std::ref(tac), service_id); |
| 3196 | + } |
| 3197 | + ); |
| 3198 | + } else { |
| 3199 | + BOOST_LOG_SEV(log, info) |
| 3200 | + << "Connected to Unix socket: " << socket_path; |
| 3201 | + |
| 3202 | + // Transfer the Unix socket to the TCP connection |
| 3203 | + // Get the native file descriptor and assign it to the TCP |
| 3204 | + // socket |
| 3205 | + int fd = unix_socket.release(); |
| 3206 | + boost::system::error_code assign_ec; |
| 3207 | + client->connectionId_to_tcp_connection_map[connection_id] |
| 3208 | + ->socket() |
| 3209 | + .assign(boost::asio::ip::tcp::v4(), fd, assign_ec); |
| 3210 | + |
| 3211 | + if (assign_ec) { |
| 3212 | + BOOST_LOG_SEV(log, error) |
| 3213 | + << "Failed to assign Unix socket to TCP socket: " |
| 3214 | + << assign_ec.message(); |
| 3215 | + ::close(fd); |
| 3216 | + basic_retry_execute( |
| 3217 | + log, retry_config, [this, &tac, service_id]() { |
| 3218 | + async_send_stream_reset(tac, service_id); |
| 3219 | + setup_tcp_socket(std::ref(tac), service_id); |
| 3220 | + } |
| 3221 | + ); |
| 3222 | + } else { |
| 3223 | + async_setup_bidirectional_data_transfers( |
| 3224 | + tac, service_id, connection_id |
| 3225 | + ); |
| 3226 | + } |
| 3227 | + } |
| 3228 | + } catch (const std::exception &e) { |
| 3229 | + BOOST_LOG_SEV(log, error) |
| 3230 | + << "Exception connecting to Unix socket: " << e.what(); |
| 3231 | + basic_retry_execute( |
| 3232 | + log, retry_config, [this, &tac, service_id]() { |
| 3233 | + async_send_stream_reset(tac, service_id); |
| 3234 | + setup_tcp_socket(std::ref(tac), service_id); |
| 3235 | + } |
| 3236 | + ); |
| 3237 | + } |
| 3238 | + } |
| 3239 | +#endif |
| 3240 | + |
3150 | 3241 | void tcp_adapter_proxy::async_resolve_destination_for_connect( |
3151 | 3242 | tcp_adapter_context &tac, |
3152 | 3243 | std::shared_ptr<basic_retry_config> retry_config, |
@@ -3291,6 +3382,28 @@ namespace iot { |
3291 | 3382 | ); |
3292 | 3383 | } |
3293 | 3384 |
|
| 3385 | + // Check if endpoint is a Unix domain socket path (contains '/') |
| 3386 | +#ifndef _WIN32 |
| 3387 | + if (endpoint.find('/') != std::string::npos) { |
| 3388 | + BOOST_LOG_SEV(log, debug) |
| 3389 | + << "Detected Unix domain socket path: " << endpoint; |
| 3390 | + connect_and_setup_unix_socket( |
| 3391 | + tac, retry_config, service_id, connection_id, endpoint |
| 3392 | + ); |
| 3393 | + return; |
| 3394 | + } |
| 3395 | +#else |
| 3396 | + // On Windows, reject Unix socket paths with a clear error |
| 3397 | + if (endpoint.find('/') != std::string::npos) { |
| 3398 | + BOOST_LOG_SEV(log, error) |
| 3399 | + << "Unix domain sockets are not supported on Windows. " |
| 3400 | + << "Path provided: " << endpoint; |
| 3401 | + throw std::runtime_error( |
| 3402 | + "Unix domain sockets are not supported on Windows" |
| 3403 | + ); |
| 3404 | + } |
| 3405 | +#endif |
| 3406 | + |
3294 | 3407 | if (tac.adapter_config.bind_address.has_value()) { |
3295 | 3408 | BOOST_LOG_SEV(log, debug) |
3296 | 3409 | << "Resolving local address host: " |
|
0 commit comments