1 /*
2  * Copyright (c) Facebook, Inc. and its affiliates.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #pragma once
18 
19 #include <folly/SocketAddress.h>
20 #include <folly/futures/Future.h>
21 #include <folly/io/SocketOptionMap.h>
22 #include <folly/io/async/AsyncSSLSocket.h>
23 #include <folly/io/async/AsyncSocket.h>
24 #include <folly/ssl/SSLSession.h>
25 #include <wangle/channel/Pipeline.h>
26 #include <memory>
27 
28 namespace wangle {
29 
30 class SSLSessionEstablishedCallback {
31  public:
32   virtual ~SSLSessionEstablishedCallback() = default;
33   // notified when a non-reused SSLSession is established.
34   virtual void onEstablished(
35       std::shared_ptr<folly::ssl::SSLSession> session) = 0;
36 };
37 
38 class ClientBootstrapSocketOptions {
39  public:
setV4OptionMap(const folly::SocketOptionMap & options)40   ClientBootstrapSocketOptions& setV4OptionMap(
41       const folly::SocketOptionMap& options) {
42     v4_ = options;
43     return *this;
44   }
getV4OptionMap()45   folly::SocketOptionMap const& getV4OptionMap() const {
46     return v4_;
47   }
setV6OptionMap(const folly::SocketOptionMap & options)48   ClientBootstrapSocketOptions& setV6OptionMap(
49       const folly::SocketOptionMap& options) {
50     v6_ = options;
51     return *this;
52   }
getV6OptionMap()53   folly::SocketOptionMap const& getV6OptionMap() const {
54     return v6_;
55   }
56 
57  private:
58   folly::SocketOptionMap v4_;
59   folly::SocketOptionMap v6_;
60 };
61 
62 using SSLSessionEstablishedCallbackUniquePtr =
63     std::unique_ptr<SSLSessionEstablishedCallback>;
64 
65 /*
66  * A wrapper template around Pipeline and AsyncSocket or SPDY/HTTP/2 session to
67  * match ServerBootstrap so BroadcastPool can work with either option
68  */
69 template <typename P = DefaultPipeline>
70 class BaseClientBootstrap {
71  public:
72   using Ptr = std::unique_ptr<BaseClientBootstrap>;
BaseClientBootstrap()73   BaseClientBootstrap() {}
74 
75   virtual ~BaseClientBootstrap() = default;
76 
pipelineFactory(std::shared_ptr<PipelineFactory<P>> factory)77   BaseClientBootstrap<P>* pipelineFactory(
78       std::shared_ptr<PipelineFactory<P>> factory) noexcept {
79     pipelineFactory_ = factory;
80     return this;
81   }
82 
getPipeline()83   P* getPipeline() {
84     return pipeline_.get();
85   }
86 
87   virtual folly::Future<P*> connect(
88       const folly::SocketAddress& address,
89       std::chrono::milliseconds timeout = std::chrono::milliseconds(0)) = 0;
90 
sslContext(folly::SSLContextPtr sslContext)91   BaseClientBootstrap* sslContext(folly::SSLContextPtr sslContext) {
92     sslContext_ = sslContext;
93     return this;
94   }
95 
sslSession(std::shared_ptr<folly::ssl::SSLSession> sslSession)96   BaseClientBootstrap* sslSession(
97       std::shared_ptr<folly::ssl::SSLSession> sslSession) {
98     sslSession_ = sslSession;
99     return this;
100   }
101 
serverName(const std::string & sni)102   BaseClientBootstrap* serverName(const std::string& sni) {
103     sni_ = sni;
104     return this;
105   }
106 
sslSessionEstablishedCallback(SSLSessionEstablishedCallbackUniquePtr sslSessionEstablishedCallback)107   BaseClientBootstrap* sslSessionEstablishedCallback(
108       SSLSessionEstablishedCallbackUniquePtr sslSessionEstablishedCallback) {
109     sslSessionEstablishedCallback_ = std::move(sslSessionEstablishedCallback);
110     return this;
111   }
112 
deferSecurityNegotiation(bool deferSecurityNegotiation)113   BaseClientBootstrap* deferSecurityNegotiation(bool deferSecurityNegotiation) {
114     deferSecurityNegotiation_ = deferSecurityNegotiation;
115     return this;
116   }
117 
setPipeline(const typename P::Ptr & pipeline)118   void setPipeline(const typename P::Ptr& pipeline) {
119     pipeline_ = pipeline;
120   }
121 
makePipeline(std::shared_ptr<folly::AsyncTransport> socket)122   virtual void makePipeline(std::shared_ptr<folly::AsyncTransport> socket) {
123     pipeline_ = pipelineFactory_->newPipeline(socket);
124   }
125 
setSocketOptions(const ClientBootstrapSocketOptions & sockOpts)126   void setSocketOptions(const ClientBootstrapSocketOptions& sockOpts) {
127     socketOptions_ = sockOpts;
128   }
129 
130  protected:
getSocketOptions(sa_family_t ipFamily)131   const folly::SocketOptionMap& getSocketOptions(sa_family_t ipFamily) {
132     if (ipFamily == AF_INET) {
133       return socketOptions_.getV4OptionMap();
134     } else if (ipFamily == AF_INET6) {
135       return socketOptions_.getV6OptionMap();
136     }
137     return folly::emptySocketOptionMap;
138   }
139 
140   std::shared_ptr<PipelineFactory<P>> pipelineFactory_;
141   typename P::Ptr pipeline_;
142   folly::SSLContextPtr sslContext_;
143   std::shared_ptr<folly::ssl::SSLSession> sslSession_{nullptr};
144   std::string sni_;
145   bool deferSecurityNegotiation_{false};
146   SSLSessionEstablishedCallbackUniquePtr sslSessionEstablishedCallback_;
147   ClientBootstrapSocketOptions socketOptions_;
148 };
149 
150 template <typename ClientBootstrap = BaseClientBootstrap<>>
151 class BaseClientBootstrapFactory {
152  public:
153   virtual typename ClientBootstrap::Ptr newClient() = 0;
154   virtual ~BaseClientBootstrapFactory() = default;
155 };
156 
157 } // namespace wangle
158