2 * Copyright 2017 Facebook, Inc.
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <folly/Optional.h>
19 #include <folly/io/async/AsyncSSLSocket.h>
20 #include <folly/io/async/AsyncSocket.h>
21 #include <folly/io/async/SSLContext.h>
23 class BlockingSocket : public folly::AsyncSocket::ConnectCallback,
24 public folly::AsyncTransportWrapper::ReadCallback,
25 public folly::AsyncTransportWrapper::WriteCallback {
27 explicit BlockingSocket(int fd)
28 : sock_(new folly::AsyncSocket(&eventBase_, fd)) {}
31 folly::SocketAddress address,
32 std::shared_ptr<folly::SSLContext> sslContext)
34 sslContext ? new folly::AsyncSSLSocket(sslContext, &eventBase_)
35 : new folly::AsyncSocket(&eventBase_)),
38 explicit BlockingSocket(folly::AsyncSocket::UniquePtr socket)
39 : sock_(std::move(socket)) {
40 sock_->attachEventBase(&eventBase_);
47 void setAddress(folly::SocketAddress address) {
52 std::chrono::milliseconds timeout = std::chrono::milliseconds::zero()) {
53 sock_->connect(this, address_, timeout.count());
55 if (err_.hasValue()) {
63 void closeWithReset() {
64 sock_->closeWithReset();
67 int32_t write(uint8_t const* buf, size_t len) {
68 sock_->write(this, buf, len);
70 if (err_.hasValue()) {
78 int32_t readAll(uint8_t* buf, size_t len) {
79 return readHelper(buf, len, true);
82 int32_t read(uint8_t* buf, size_t len) {
83 return readHelper(buf, len, false);
86 int getSocketFD() const {
87 return sock_->getFd();
90 folly::AsyncSocket* getSocket() {
94 folly::AsyncSSLSocket* getSSLSocket() {
95 return dynamic_cast<folly::AsyncSSLSocket*>(sock_.get());
99 folly::EventBase eventBase_;
100 folly::AsyncSocket::UniquePtr sock_;
101 folly::Optional<folly::AsyncSocketException> err_;
102 uint8_t* readBuf_{nullptr};
104 folly::SocketAddress address_;
106 void connectSuccess() noexcept override {}
107 void connectErr(const folly::AsyncSocketException& ex) noexcept override {
110 void getReadBuffer(void** bufReturn, size_t* lenReturn) override {
111 *bufReturn = readBuf_;
112 *lenReturn = readLen_;
114 void readDataAvailable(size_t len) noexcept override {
118 sock_->setReadCB(nullptr);
121 void readEOF() noexcept override {}
122 void readErr(const folly::AsyncSocketException& ex) noexcept override {
125 void writeSuccess() noexcept override {}
127 size_t /* bytesWritten */,
128 const folly::AsyncSocketException& ex) noexcept override {
132 int32_t readHelper(uint8_t* buf, size_t len, bool all) {
133 if (!sock_->good()) {
139 sock_->setReadCB(this);
140 while (!err_ && sock_->good() && readLen_ > 0) {
141 eventBase_.loopOnce();
146 sock_->setReadCB(nullptr);
147 if (err_.hasValue()) {
150 if (all && readLen_ > 0) {
151 throw folly::AsyncSocketException(
152 folly::AsyncSocketException::UNKNOWN, "eof");
154 return len - readLen_;