void AsyncUDPSocket::handleRead() noexcept { void* buf{nullptr}; size_t len{0}; readCallback_->getReadBuffer(&buf, &len); if (buf == nullptr || len == 0) { AsyncSocketException ex( AsyncSocketException::BAD_ARGS, "AsyncUDPSocket::getReadBuffer() returned empty buffer"); auto cob = readCallback_; readCallback_ = nullptr; cob->onReadError(ex); updateRegistration(); return; } struct sockaddr_storage addrStorage; socklen_t addrLen = sizeof(addrStorage); memset(&addrStorage, 0, addrLen); struct sockaddr* rawAddr = reinterpret_cast<sockaddr*>(&addrStorage); rawAddr->sa_family = localAddress_.getFamily(); ssize_t bytesRead = recvfrom(fd_, buf, len, MSG_TRUNC, rawAddr, &addrLen); if (bytesRead >= 0) { clientAddress_.setFromSockaddr(rawAddr, addrLen); if (bytesRead > 0) { bool truncated = false; if ((size_t)bytesRead > len) { truncated = true; bytesRead = len; } readCallback_->onDataAvailable(clientAddress_, bytesRead, truncated); } } else { if (errno == EAGAIN || errno == EWOULDBLOCK) { // No data could be read without blocking the socket return; } AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, "::recvfrom() failed", errno); // In case of UDP we can continue reading from the socket // even if the current request fails. We notify the user // so that he can do some logging/stats collection if he wants. auto cob = readCallback_; readCallback_ = nullptr; cob->onReadError(ex); updateRegistration(); } }
void AsyncUDPSocket::attachEventBase(folly::EventBase* evb) { DCHECK(!eventBase_); DCHECK(evb && evb->isInEventBaseThread()); eventBase_ = evb; EventHandler::attachEventBase(evb); updateRegistration(); }
void AsyncUDPSocket::handleRead() noexcept { void *buf{nullptr}; size_t len{0}; struct msghdr *msg{nullptr}; readCallback_->getMessageHeader(&msg); if (msg == nullptr) { AsyncSocketException ex( AsyncSocketException::BAD_ARGS, "AsyncUDPSocket::getMessageHeader() returned empty header"); auto cob = readCallback_; readCallback_ = nullptr; cob->onReadError(ex); updateRegistration(); return; } ssize_t bytesRead = ::recvmsg(fd_, msg, MSG_DONTWAIT); if (bytesRead >= 0) { readCallback_->onMessageAvailable(bytesRead); } else { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINTR) { // No data could be read without blocking the socket return; } AsyncSocketException ex(AsyncSocketException::INTERNAL_ERROR, "::recvmsg() failed", errno); // In case of UDP we can continue reading from the socket // even if the current request fails. We notify the user // so that he can do some logging/stats collection if he wants. auto cob = readCallback_; readCallback_ = nullptr; cob->onReadError(ex); updateRegistration(); } }
void AsyncUDPSocket::resumeRead(ReadCallback* cob) { CHECK(!readCallback_) << "Another read callback already installed"; CHECK_NE(-1, fd_) << "UDP server socket not yet bind to an address"; readCallback_ = CHECK_NOTNULL(cob); if (!updateRegistration()) { AsyncSocketException ex( AsyncSocketException::NOT_OPEN, "failed to register for accept events"); readCallback_ = nullptr; cob->onReadError(ex); return; } }
void AsyncUDPSocket::pauseRead() { // It is ok to pause an already paused socket readCallback_ = nullptr; updateRegistration(); }