2 * Copyright 2016 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.
19 #include <folly/io/IOBuf.h>
20 #include <folly/ScopeGuard.h>
21 #include <folly/io/async/AsyncSocketException.h>
22 #include <folly/io/async/AsyncSocketBase.h>
23 #include <folly/io/async/EventHandler.h>
24 #include <folly/io/async/EventBase.h>
25 #include <folly/SocketAddress.h>
34 class AsyncUDPSocket : public EventHandler {
36 enum class FDOwnership {
44 * Invoked when the socket becomes readable and we want buffer
47 * NOTE: From socket we will end up reading at most `len` bytes
48 * and if there were more bytes in datagram, we will end up
51 virtual void getReadBuffer(void** buf, size_t* len) noexcept = 0;
54 * Invoked when a new datagraom is available on the socket. `len`
55 * is the number of bytes read and `truncated` is true if we had
56 * to drop few bytes because of running out of buffer space.
58 virtual void onDataAvailable(const folly::SocketAddress& client,
60 bool truncated) noexcept = 0;
63 * Invoked when there is an error reading from the socket.
65 * NOTE: Since UDP is connectionless, you can still read from the socket.
66 * But you have to re-register readCallback yourself after
69 virtual void onReadError(const AsyncSocketException& ex)
73 * Invoked when socket is closed and a read callback is registered.
75 virtual void onReadClosed() noexcept = 0;
77 virtual ~ReadCallback() = default;
81 * Create a new UDP socket that will run in the
84 explicit AsyncUDPSocket(EventBase* evb);
88 * Returns the address server is listening on
90 virtual const folly::SocketAddress& address() const {
91 CHECK_NE(-1, fd_) << "Server not yet bound to an address";
96 * Bind the socket to the following address. If port is not
97 * set in the `address` an ephemeral port is chosen and you can
98 * use `address()` method above to get it after this method successfully
101 virtual void bind(const folly::SocketAddress& address);
104 * Use an already bound file descriptor. You can either transfer ownership
105 * of this FD by using ownership = FDOwnership::OWNS or share it using
106 * FDOwnership::SHARED. In case FD is shared, it will not be `close`d in
109 virtual void setFD(int fd, FDOwnership ownership);
112 * Send the data in buffer to destination. Returns the return code from
115 virtual ssize_t write(const folly::SocketAddress& address,
116 const std::unique_ptr<folly::IOBuf>& buf);
119 * Send data in iovec to destination. Returns the return code from sendmsg.
121 virtual ssize_t writev(const folly::SocketAddress& address,
122 const struct iovec* vec, size_t veclen);
125 * Start reading datagrams
127 virtual void resumeRead(ReadCallback* cob);
130 * Pause reading datagrams
132 virtual void pauseRead();
135 * Stop listening on the socket.
137 virtual void close();
140 * Get internal FD used by this socket
142 virtual int getFD() const {
143 CHECK_NE(-1, fd_) << "Need to bind before getting FD out";
148 * Set reuse port mode to call bind() on the same address multiple times
150 virtual void setReusePort(bool reusePort) {
151 reusePort_ = reusePort;
155 * Set SO_REUSEADDR flag on the socket. Default is ON.
157 virtual void setReuseAddr(bool reuseAddr) {
158 reuseAddr_ = reuseAddr;
162 AsyncUDPSocket(const AsyncUDPSocket&) = delete;
163 AsyncUDPSocket& operator=(const AsyncUDPSocket&) = delete;
166 void handlerReady(uint16_t events) noexcept;
168 void handleRead() noexcept;
169 bool updateRegistration() noexcept;
171 EventBase* eventBase_;
172 folly::SocketAddress localAddress_;
175 FDOwnership ownership_;
177 // Temp space to receive client address
178 folly::SocketAddress clientAddress_;
180 // Non-null only when we are reading
181 ReadCallback* readCallback_;
183 bool reuseAddr_{true};
184 bool reusePort_{false};