1 // Copyright 2021 gRPC authors.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <grpc/support/port_platform.h>
16
17 #include <algorithm>
18
19 #include "absl/status/status.h"
20
21 #include "src/core/lib/gprpp/status_helper.h"
22 #include "src/core/lib/iomgr/port.h" // IWYU pragma: keep
23
24 #ifdef GRPC_HAVE_UNIX_SOCKET
25
26 #include <string.h>
27 #ifdef GPR_WINDOWS
28 // clang-format off
29 #include <ws2def.h>
30 #include <afunix.h>
31 // clang-format on
32 #else
33 #include <sys/socket.h>
34 #include <sys/un.h>
35 #endif // GPR_WINDOWS
36
37 #include <memory>
38 #include <utility>
39
40 #include "absl/status/statusor.h"
41 #include "absl/strings/str_cat.h"
42 #include "absl/strings/string_view.h"
43 #include "absl/strings/strip.h"
44
45 #include <grpc/support/log.h>
46
47 #include "src/core/lib/channel/channel_args.h"
48 #include "src/core/lib/config/core_configuration.h"
49 #include "src/core/lib/gprpp/orphanable.h"
50 #include "src/core/lib/iomgr/error.h"
51 #include "src/core/lib/iomgr/resolved_address.h"
52 #include "src/core/resolver/endpoint_addresses.h"
53 #include "src/core/resolver/resolver.h"
54 #include "src/core/resolver/resolver_factory.h"
55 #include "src/core/lib/uri/uri_parser.h"
56
57 namespace grpc_core {
58 namespace {
59
60 class BinderResolver final : public Resolver {
61 public:
BinderResolver(EndpointAddressesList addresses,ResolverArgs args)62 BinderResolver(EndpointAddressesList addresses, ResolverArgs args)
63 : result_handler_(std::move(args.result_handler)),
64 addresses_(std::move(addresses)),
65 channel_args_(std::move(args.args)) {}
66
StartLocked()67 void StartLocked() override {
68 Result result;
69 result.addresses = std::move(addresses_);
70 result.args = channel_args_;
71 channel_args_ = ChannelArgs();
72 result_handler_->ReportResult(std::move(result));
73 }
74
ShutdownLocked()75 void ShutdownLocked() override {}
76
77 private:
78 std::unique_ptr<ResultHandler> result_handler_;
79 EndpointAddressesList addresses_;
80 ChannelArgs channel_args_;
81 };
82
83 class BinderResolverFactory final : public ResolverFactory {
84 public:
scheme() const85 absl::string_view scheme() const override { return "binder"; }
86
IsValidUri(const URI & uri) const87 bool IsValidUri(const URI& uri) const override {
88 return ParseUri(uri, nullptr);
89 }
90
CreateResolver(ResolverArgs args) const91 OrphanablePtr<Resolver> CreateResolver(ResolverArgs args) const override {
92 EndpointAddressesList addresses;
93 if (!ParseUri(args.uri, &addresses)) return nullptr;
94 return MakeOrphanable<BinderResolver>(std::move(addresses),
95 std::move(args));
96 }
97
98 private:
BinderAddrPopulate(absl::string_view path,grpc_resolved_address * resolved_addr)99 static grpc_error_handle BinderAddrPopulate(
100 absl::string_view path, grpc_resolved_address* resolved_addr) {
101 path = absl::StripPrefix(path, "/");
102 if (path.empty()) {
103 return GRPC_ERROR_CREATE("path is empty");
104 }
105 // Store parsed path in a unix socket so it can be reinterpreted as
106 // sockaddr. An invalid address family (AF_MAX) is set to make sure it won't
107 // be accidentally used.
108 memset(resolved_addr, 0, sizeof(*resolved_addr));
109 struct sockaddr_un* un =
110 reinterpret_cast<struct sockaddr_un*>(resolved_addr->addr);
111 un->sun_family = AF_MAX;
112 static_assert(sizeof(un->sun_path) >= 101,
113 "unix socket path size is unexpectedly short");
114 if (path.size() + 1 > sizeof(un->sun_path)) {
115 return GRPC_ERROR_CREATE(
116 absl::StrCat(path, " is too long to be handled"));
117 }
118 // `un` has already be set to zero, no need to append null after the string
119 memcpy(un->sun_path, path.data(), path.size());
120 resolved_addr->len =
121 static_cast<socklen_t>(sizeof(un->sun_family) + path.size() + 1);
122 return absl::OkStatus();
123 }
124
ParseUri(const URI & uri,EndpointAddressesList * addresses)125 static bool ParseUri(const URI& uri, EndpointAddressesList* addresses) {
126 grpc_resolved_address addr;
127 {
128 if (!uri.authority().empty()) {
129 gpr_log(GPR_ERROR, "authority is not supported in binder scheme");
130 return false;
131 }
132 grpc_error_handle error = BinderAddrPopulate(uri.path(), &addr);
133 if (!error.ok()) {
134 gpr_log(GPR_ERROR, "%s", StatusToString(error).c_str());
135 return false;
136 }
137 }
138 if (addresses != nullptr) {
139 addresses->emplace_back(addr, ChannelArgs());
140 }
141 return true;
142 }
143 };
144
145 } // namespace
146
RegisterBinderResolver(CoreConfiguration::Builder * builder)147 void RegisterBinderResolver(CoreConfiguration::Builder* builder) {
148 builder->resolver_registry()->RegisterResolverFactory(
149 std::make_unique<BinderResolverFactory>());
150 }
151
152 } // namespace grpc_core
153
154 #endif
155