/*
- * Copyright 2016 Facebook, Inc.
+ * Copyright 2017 Facebook, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <folly/Optional.h>
#include <folly/SocketAddress.h>
+#include <folly/detail/SocketFastOpen.h>
#include <folly/io/IOBuf.h>
#include <folly/io/ShutdownSocketSet.h>
#include <folly/io/async/AsyncSocketException.h>
* responding and no further progress can be made sending the data.
*/
+#if defined __linux__ && !defined SO_NO_TRANSPARENT_TLS
+#define SO_NO_TRANSPARENT_TLS 200
+#endif
+
#ifdef _MSC_VER
// We do a dynamic_cast on this, in
// AsyncTransportWrapper::getUnderlyingTransport so be safe and
noexcept = 0;
};
+ class EvbChangeCallback {
+ public:
+ virtual ~EvbChangeCallback() = default;
+
+ // Called when the socket has been attached to a new EVB
+ // and is called from within that EVB thread
+ virtual void evbAttached(AsyncSocket* socket) = 0;
+
+ // Called when the socket is detached from an EVB and
+ // is called from the EVB thread being detached
+ virtual void evbDetached(AsyncSocket* socket) = 0;
+ };
+
explicit AsyncSocket();
/**
* Create a new unconnected AsyncSocket.
void getPeerAddress(
folly::SocketAddress* address) const override;
- bool isEorTrackingEnabled() const override { return false; }
+ bool isEorTrackingEnabled() const override {
+ return trackEor_;
+ }
- void setEorTracking(bool /*track*/) override {}
+ void setEorTracking(bool track) override {
+ trackEor_ = track;
+ }
bool connecting() const override {
return (state_ == StateEnum::CONNECTING);
return connectTimeout_;
}
+ bool getTFOAttempted() const {
+ return tfoAttempted_;
+ }
+
+ /**
+ * Returns whether or not the attempt to use TFO
+ * finished successfully. This does not necessarily
+ * mean TFO worked, just that trying to use TFO
+ * succeeded.
+ */
+ bool getTFOFinished() const {
+ return tfoFinished_;
+ }
+
+ /**
+ * Returns whether or not TFO attempt succeded on this
+ * connection.
+ * For servers this is pretty straightforward API and can
+ * be invoked right after the connection is accepted. This API
+ * will perform one syscall.
+ * This API is a bit tricky to use for clients, since clients
+ * only know this for sure after the SYN-ACK is returned. So it's
+ * appropriate to call this only after the first application
+ * data is read from the socket when the caller knows that
+ * the SYN has been ACKed by the server.
+ */
+ bool getTFOSucceded() const;
+
// Methods controlling socket options
/**
peek_ = peek;
}
+ /**
+ * Enables TFO behavior on the AsyncSocket if FOLLY_ALLOW_TFO
+ * is set.
+ */
+ void enableTFO() {
+ // No-op if folly does not allow tfo
+#if FOLLY_ALLOW_TFO
+ tfoEnabled_ = true;
+#endif
+ }
+
+ void disableTransparentTls() {
+ noTransparentTls_ = true;
+ }
+
enum class StateEnum : uint8_t {
UNINIT,
CONNECTING,
ESTABLISHED,
CLOSED,
- ERROR
+ ERROR,
+ FAST_OPEN,
};
void setBufferCallback(BufferCallback* cb);
+ // Callers should set this prior to connecting the socket for the safest
+ // behavior.
+ void setEvbChangedCallback(std::unique_ptr<EvbChangeCallback> cb) {
+ evbChangeCb_ = std::move(cb);
+ }
+
/**
* writeReturn is the total number of bytes written, or WRITE_ERROR on error.
* If no data has been written, 0 is returned.
WriteRequest(AsyncSocket* socket, WriteCallback* callback) :
socket_(socket), callback_(callback) {}
- virtual void start() {};
+ virtual void start() {}
virtual void destroy() = 0;
}
void bytesWritten(size_t count) {
- totalBytesWritten_ += count;
+ totalBytesWritten_ += uint32_t(count);
socket_->appBytesWritten_ += count;
}
}
}
+ /**
+ * Schedule handleInitalReadWrite to run in the next iteration.
+ */
+ void scheduleInitialReadWrite() noexcept {
+ if (good()) {
+ DestructorGuard dg(this);
+ eventBase_->runInLoop([this, dg] {
+ if (good()) {
+ handleInitialReadWrite();
+ }
+ });
+ }
+ }
+
// event notification methods
void ioReady(uint16_t events) noexcept;
virtual void checkForImmediateRead() noexcept;
virtual void handleInitialReadWrite() noexcept;
- virtual void prepareReadBuffer(void** buf, size_t* buflen) noexcept;
+ virtual void prepareReadBuffer(void** buf, size_t* buflen);
virtual void handleRead() noexcept;
virtual void handleWrite() noexcept;
virtual void handleConnect() noexcept;
uint32_t* countWritten,
uint32_t* partialWritten);
+ /**
+ * Sends the message over the socket using sendmsg
+ *
+ * @param msg Message to send
+ * @param msg_flags Flags to pass to sendmsg
+ */
+ AsyncSocket::WriteResult
+ sendSocketMessage(int fd, struct msghdr* msg, int msg_flags);
+
+ virtual ssize_t tfoSendMsg(int fd, struct msghdr* msg, int msg_flags);
+
+ int socketConnect(const struct sockaddr* addr, socklen_t len);
+
+ virtual void scheduleConnectTimeout();
+ void registerForConnectEvents();
+
bool updateEventRegistration();
/**
// error handling methods
void startFail();
void finishFail();
+ void finishFail(const AsyncSocketException& ex);
+ void invokeAllErrors(const AsyncSocketException& ex);
void fail(const char* fn, const AsyncSocketException& ex);
void failConnect(const char* fn, const AsyncSocketException& ex);
void failRead(const char* fn, const AsyncSocketException& ex);
const AsyncSocketException& ex);
void failWrite(const char* fn, const AsyncSocketException& ex);
void failAllWrites(const AsyncSocketException& ex);
- void invokeConnectErr(const AsyncSocketException& ex);
- void invokeConnectSuccess();
+ virtual void invokeConnectErr(const AsyncSocketException& ex);
+ virtual void invokeConnectSuccess();
void invalidState(ConnectCallback* callback);
void invalidState(ReadCallback* callback);
void invalidState(WriteCallback* callback);
std::chrono::milliseconds connectTimeout_{0};
BufferCallback* bufferCallback_{nullptr};
+ bool tfoEnabled_{false};
+ bool tfoAttempted_{false};
+ bool tfoFinished_{false};
+ bool noTransparentTls_{false};
+ // Whether to track EOR or not.
+ bool trackEor_{false};
+
+ std::unique_ptr<EvbChangeCallback> evbChangeCb_{nullptr};
};
#ifdef _MSC_VER
#pragma vtordisp(pop)