123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325 |
- /*
- * Copyright 2014-present Facebook, Inc.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- #pragma once
- #include <memory>
- #include <folly/ScopeGuard.h>
- #include <folly/SocketAddress.h>
- #include <folly/io/IOBuf.h>
- #include <folly/io/async/AsyncSocketBase.h>
- #include <folly/io/async/AsyncSocketException.h>
- #include <folly/io/async/EventBase.h>
- #include <folly/io/async/EventHandler.h>
- namespace folly {
- /**
- * UDP socket
- */
- class AsyncUDPSocket : public EventHandler {
- public:
- enum class FDOwnership { OWNS, SHARED };
- class ReadCallback {
- public:
- /**
- * Invoked when the socket becomes readable and we want buffer
- * to write to.
- *
- * NOTE: From socket we will end up reading at most `len` bytes
- * and if there were more bytes in datagram, we will end up
- * dropping them.
- */
- virtual void getReadBuffer(void** buf, size_t* len) noexcept = 0;
- /**
- * Invoked when a new datagraom is available on the socket. `len`
- * is the number of bytes read and `truncated` is true if we had
- * to drop few bytes because of running out of buffer space.
- */
- virtual void onDataAvailable(
- const folly::SocketAddress& client,
- size_t len,
- bool truncated) noexcept = 0;
- /**
- * Invoked when there is an error reading from the socket.
- *
- * NOTE: Since UDP is connectionless, you can still read from the socket.
- * But you have to re-register readCallback yourself after
- * onReadError.
- */
- virtual void onReadError(const AsyncSocketException& ex) noexcept = 0;
- /**
- * Invoked when socket is closed and a read callback is registered.
- */
- virtual void onReadClosed() noexcept = 0;
- virtual ~ReadCallback() = default;
- };
- class ErrMessageCallback {
- public:
- virtual ~ErrMessageCallback() = default;
- /**
- * errMessage() will be invoked when kernel puts a message to
- * the error queue associated with the socket.
- *
- * @param cmsg Reference to cmsghdr structure describing
- * a message read from error queue associated
- * with the socket.
- */
- virtual void errMessage(const cmsghdr& cmsg) noexcept = 0;
- /**
- * errMessageError() will be invoked if an error occurs reading a message
- * from the socket error stream.
- *
- * @param ex An exception describing the error that occurred.
- */
- virtual void errMessageError(const AsyncSocketException& ex) noexcept = 0;
- };
- /**
- * Create a new UDP socket that will run in the
- * given eventbase
- */
- explicit AsyncUDPSocket(EventBase* evb);
- ~AsyncUDPSocket() override;
- /**
- * Returns the address server is listening on
- */
- virtual const folly::SocketAddress& address() const {
- CHECK_NE(-1, fd_) << "Server not yet bound to an address";
- return localAddress_;
- }
- /**
- * Bind the socket to the following address. If port is not
- * set in the `address` an ephemeral port is chosen and you can
- * use `address()` method above to get it after this method successfully
- * returns.
- */
- virtual void bind(const folly::SocketAddress& address);
- /**
- * Use an already bound file descriptor. You can either transfer ownership
- * of this FD by using ownership = FDOwnership::OWNS or share it using
- * FDOwnership::SHARED. In case FD is shared, it will not be `close`d in
- * destructor.
- */
- virtual void setFD(int fd, FDOwnership ownership);
- /**
- * Send the data in buffer to destination. Returns the return code from
- * ::sendmsg.
- */
- virtual ssize_t write(
- const folly::SocketAddress& address,
- const std::unique_ptr<folly::IOBuf>& buf);
- /**
- * Send the data in buffer to destination. Returns the return code from
- * ::sendmsg.
- * gso is the generic segmentation offload value
- * writeGSO will return -1 if
- * buf->computeChainDataLength() <= gso
- * Before calling writeGSO with a positive value
- * verify GSO is supported on this platform by calling getGSO
- */
- virtual ssize_t writeGSO(
- const folly::SocketAddress& address,
- const std::unique_ptr<folly::IOBuf>& buf,
- int gso);
- /**
- * Send data in iovec to destination. Returns the return code from sendmsg.
- */
- virtual ssize_t writev(
- const folly::SocketAddress& address,
- const struct iovec* vec,
- size_t veclen,
- int gso);
- virtual ssize_t writev(
- const folly::SocketAddress& address,
- const struct iovec* vec,
- size_t veclen);
- /**
- * Start reading datagrams
- */
- virtual void resumeRead(ReadCallback* cob);
- /**
- * Pause reading datagrams
- */
- virtual void pauseRead();
- /**
- * Stop listening on the socket.
- */
- virtual void close();
- /**
- * Get internal FD used by this socket
- */
- virtual int getFD() const {
- CHECK_NE(-1, fd_) << "Need to bind before getting FD out";
- return fd_;
- }
- /**
- * Set reuse port mode to call bind() on the same address multiple times
- */
- virtual void setReusePort(bool reusePort) {
- reusePort_ = reusePort;
- }
- /**
- * Set SO_REUSEADDR flag on the socket. Default is ON.
- */
- virtual void setReuseAddr(bool reuseAddr) {
- reuseAddr_ = reuseAddr;
- }
- /**
- * Set SO_RCVBUF option on the socket, if not zero. Default is zero.
- */
- virtual void setRcvBuf(int rcvBuf) {
- rcvBuf_ = rcvBuf;
- }
- /**
- * Set SO_SNDBUG option on the socket, if not zero. Default is zero.
- */
- virtual void setSndBuf(int sndBuf) {
- sndBuf_ = sndBuf;
- }
- /**
- * Set SO_BUSY_POLL option on the socket, if not zero. Default is zero.
- * Caution! The feature is not available on Apple's systems.
- */
- virtual void setBusyPoll(int busyPollUs) {
- busyPollUs_ = busyPollUs;
- }
- EventBase* getEventBase() const {
- return eventBase_;
- }
- /**
- * Enable or disable fragmentation on the socket.
- *
- * On Linux, this sets IP(V6)_MTU_DISCOVER to IP(V6)_PMTUDISC_DO when enabled,
- * and to IP(V6)_PMTUDISC_WANT when disabled. IP(V6)_PMTUDISC_WANT will use
- * per-route setting to set DF bit. It may be more desirable to use
- * IP(V6)_PMTUDISC_PROBE as opposed to IP(V6)_PMTUDISC_DO for apps that has
- * its own PMTU Discovery mechanism.
- * Note this doesn't work on Apple.
- */
- virtual void dontFragment(bool df);
- /**
- * Callback for receiving errors on the UDP sockets
- */
- virtual void setErrMessageCallback(ErrMessageCallback* errMessageCallback);
- /**
- * Connects the UDP socket to a remote destination address provided in
- * address. This can speed up UDP writes on linux because it will cache flow
- * state on connects.
- * Using connect has many quirks, and you should be aware of them before using
- * this API:
- * 1. This must only be called after binding the socket.
- * 2. Normally UDP can use the 2 tuple (src ip, src port) to steer packets
- * sent by the peer to the socket, however after connecting the socket, only
- * packets destined to the destination address specified in connect() will be
- * forwarded and others will be dropped. If the server can send a packet
- * from a different destination port / IP then you probably do not want to use
- * this API.
- * 3. It can be called repeatedly on either the client or server however it's
- * normally only useful on the client and not server.
- *
- * Returns the result of calling the connect syscall.
- */
- virtual int connect(const folly::SocketAddress& address);
- virtual bool isBound() const {
- return fd_ != -1;
- }
- virtual void detachEventBase();
- virtual void attachEventBase(folly::EventBase* evb);
- // generic segmentation offload get/set
- // negative return value means GSO is not available
- int getGSO();
- bool setGSO(int val);
- protected:
- virtual ssize_t sendmsg(int socket, const struct msghdr* message, int flags) {
- return ::sendmsg(socket, message, flags);
- }
- size_t handleErrMessages() noexcept;
- void failErrMessageRead(const AsyncSocketException& ex);
- // Non-null only when we are reading
- ReadCallback* readCallback_;
- private:
- AsyncUDPSocket(const AsyncUDPSocket&) = delete;
- AsyncUDPSocket& operator=(const AsyncUDPSocket&) = delete;
- // EventHandler
- void handlerReady(uint16_t events) noexcept override;
- void handleRead() noexcept;
- bool updateRegistration() noexcept;
- EventBase* eventBase_;
- folly::SocketAddress localAddress_;
- int fd_;
- FDOwnership ownership_;
- // Temp space to receive client address
- folly::SocketAddress clientAddress_;
- bool reuseAddr_{true};
- bool reusePort_{false};
- int rcvBuf_{0};
- int sndBuf_{0};
- int busyPollUs_{0};
- // generic segmentation offload value, if available
- // See https://lwn.net/Articles/188489/ for more details
- folly::Optional<int> gso_;
- ErrMessageCallback* errMessageCallback_{nullptr};
- };
- } // namespace folly
|