33
44#include < memory>
55#include < list>
6+ #include < string>
7+ #include < random>
8+
69#include < grpcpp/ext/proto_server_reflection_plugin.h>
710
811#include " opentelemetry/version.h"
@@ -24,6 +27,10 @@ namespace exporter
2427namespace otlp
2528{
2629
30+ // Send this header along with unique random number, which we'll reject if received back.
31+ // This is to avoid loops due to misconfugration
32+ static std::string kFwProxyIdHeader { " otelcpp-otlp-grpc-forward-proxy-id" };
33+
2734using namespace opentelemetry ;
2835
2936using namespace opentelemetry ::exporter::otlp;
@@ -80,6 +87,15 @@ struct OtlpGrpcForwardProxy::Impl
8087 std::unique_ptr<TraceExporterProxy> traceExporterProxy;
8188 std::unique_ptr<MetricExporterProxy> metricExporterProxy;
8289
90+ std::string fw_proxy_id;
91+
92+ bool LoopDetected ( const std::multimap<grpc::string_ref, grpc::string_ref>& client_metadata ) const
93+ {
94+ const auto key{ grpc::string_ref ( kFwProxyIdHeader ) };
95+ const auto it{ client_metadata.find (key) };
96+ return it != client_metadata.cend () && it->second .compare ( grpc::string_ref ( fw_proxy_id ) ) == 0 ;
97+ }
98+
8399 Impl (const OtlpGrpcClientOptions&);
84100#if defined(ENABLE_ASYNC_EXPORT)
85101 bool HandleExportResult (sdk::common::ExportResult result) const ;
@@ -93,6 +109,14 @@ OtlpGrpcForwardProxy::Impl::Impl(const OtlpGrpcClientOptions& options)
93109 arenaOptions.initial_block_size = 65536 ;
94110 arenaOptions.max_block_size = 128 * 1024 * 1024 ;
95111 client = OtlpGrpcClientFactory::Create (clientOptions);
112+
113+ char buf[32 ]{};
114+ std::random_device rd;
115+ uint64_t p0 = (uint64_t (rd ())<<32 ) | uint64_t (rd ());
116+ uint64_t p1 = (uint64_t (rd ())<<32 ) | uint64_t (rd ());
117+ sprintf_s (buf, " %08.8lx%08.8lx" , p0, p1);
118+ fw_proxy_id = buf;
119+
96120}
97121
98122#if defined(ENABLE_ASYNC_EXPORT)
@@ -168,10 +192,13 @@ grpc::ServerUnaryReactor* OtlpGrpcForwardProxy::Impl::Finish(grpc::CallbackServe
168192 explicit NAME (OtlpGrpcForwardProxy::Impl& impl_): impl(impl_){} \
169193 grpc::ServerUnaryReactor* Export (grpc::CallbackServerContext* cbServerContext, const REQUEST* req, RESPONSE* resp) override { \
170194 auto exportResult{ sdk::common::ExportResult::kFailure }; \
195+ if ( impl.LoopDetected (cbServerContext->client_metadata ()) ) \
196+ return impl.Finish (cbServerContext, exportResult, grpc::Status (grpc::StatusCode::FAILED_PRECONDITION, " OtlpGrpcForwardProxy detected loop." )); \
171197 if ( impl.active ) { \
172198 OTEL_INTERNAL_LOG_DEBUG (" [otlp_grpc_forward_proxy] " TEXT " export" ); \
173199 auto syncStatus{ grpc::Status (grpc::Status (grpc::StatusCode::DO_NOT_USE, " " )) }; \
174200 auto context{ impl.client ->MakeClientContext (impl.clientOptions ) }; \
201+ context->AddMetadata (kFwProxyIdHeader , impl.fw_proxy_id ); \
175202 auto arena{ std::make_unique<google::protobuf::Arena>(impl.arenaOptions ) }; \
176203 auto request{ *req }; \
177204 exportResult = impl.client ->DelegateAsyncExport ( impl.clientOptions , impl.STUB .get (), std::move (context), std::move (arena), std::move (request), \
@@ -193,10 +220,13 @@ grpc::ServerUnaryReactor* OtlpGrpcForwardProxy::Impl::Finish(grpc::CallbackServe
193220 struct OtlpGrpcForwardProxy ::Impl::NAME final : public SERVICE::Service { \
194221 OtlpGrpcForwardProxy::Impl& impl; \
195222 explicit NAME (OtlpGrpcForwardProxy::Impl& impl_): impl(impl_){} \
196- grpc::Status Export (grpc::ServerContext*, const REQUEST* req, RESPONSE* resp) override { \
223+ grpc::Status Export (grpc::ServerContext* serverContext, const REQUEST* req, RESPONSE* resp) override { \
224+ if ( impl.LoopDetected (serverContext->client_metadata ()) ) \
225+ return grpc::Status (grpc::StatusCode::FAILED_PRECONDITION, " OtlpGrpcForwardProxy detected loop." ); \
197226 if ( impl.active ) { \
198227 OTEL_INTERNAL_LOG_DEBUG (" [otlp_grpc_forward_proxy] " TEXT " export" ); \
199228 auto context{ impl.client ->MakeClientContext (impl.clientOptions ) }; \
229+ context->AddMetadata (kFwProxyIdHeader , impl.fw_proxy_id ); \
200230 return impl.STUB ->Export ( context.get (), *req, resp ); \
201231 } \
202232 return grpc::Status (grpc::StatusCode::FAILED_PRECONDITION, " OtlpGrpcForwardProxy is not active." ); \
0 commit comments