7 #include "packager/file/udp_file.h"
13 #define close closesocket
17 #include <arpa/inet.h>
20 #include <sys/socket.h>
22 #define INVALID_SOCKET -1
26 #ifndef IP_MULTICAST_ALL
27 #define IP_MULTICAST_ALL 49
30 #endif // defined(OS_WIN)
34 #include "packager/base/logging.h"
35 #include "packager/file/udp_options.h"
41 bool IsIpv4MulticastAddress(
const struct in_addr& addr) {
42 return (ntohl(addr.s_addr) & 0xf0000000) == 0xe0000000;
48 :
File(file_name), socket_(INVALID_SOCKET) {}
50 UdpFile::~UdpFile() {}
53 if (socket_ != INVALID_SOCKET) {
55 socket_ = INVALID_SOCKET;
63 DCHECK_GE(length, 65535u)
64 <<
"Buffer may be too small to read entire datagram.";
66 if (socket_ == INVALID_SOCKET)
72 recvfrom(socket_, reinterpret_cast<char*>(buffer), length, 0, NULL, 0);
73 }
while ((result == -1) && (errno == EINTR));
84 if (socket_ == INVALID_SOCKET)
87 return std::numeric_limits<int64_t>::max();
106 class LibWinsockInitializer {
108 LibWinsockInitializer() {
110 error_ = WSAStartup(MAKEWORD(2, 2), &wsa_data);
113 ~LibWinsockInitializer() {
118 int error()
const {
return error_; }
123 #endif // defined(OS_WIN)
127 explicit ScopedSocket(SOCKET sock_fd) : sock_fd_(sock_fd) {}
130 if (sock_fd_ != INVALID_SOCKET)
134 SOCKET
get() {
return sock_fd_; }
137 SOCKET socket = sock_fd_;
138 sock_fd_ = INVALID_SOCKET;
145 DISALLOW_COPY_AND_ASSIGN(ScopedSocket);
150 static LibWinsockInitializer lib_winsock_initializer;
151 if (lib_winsock_initializer.error() != 0) {
152 LOG(ERROR) <<
"Winsock start up failed with error "
153 << lib_winsock_initializer.error();
156 #endif // defined(OS_WIN)
158 DCHECK_EQ(INVALID_SOCKET, socket_);
160 std::unique_ptr<UdpOptions> options =
165 ScopedSocket new_socket(socket(AF_INET, SOCK_DGRAM, 0));
166 if (new_socket.get() == INVALID_SOCKET) {
167 LOG(ERROR) <<
"Could not allocate socket.";
171 struct in_addr local_in_addr = {0};
172 if (inet_pton(AF_INET, options->address().c_str(), &local_in_addr) != 1) {
173 LOG(ERROR) <<
"Malformed IPv4 address " << options->address();
177 struct sockaddr_in local_sock_addr = {0};
179 local_sock_addr.sin_family = AF_INET;
180 local_sock_addr.sin_port = htons(options->port());
181 const bool is_multicast = IsIpv4MulticastAddress(local_in_addr);
183 local_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
185 local_sock_addr.sin_addr = local_in_addr;
188 if (options->reuse()) {
189 const int optval = 1;
190 if (setsockopt(new_socket.get(), SOL_SOCKET, SO_REUSEADDR,
191 reinterpret_cast<const char*
>(&optval),
192 sizeof(optval)) < 0) {
194 <<
"Could not apply the SO_REUSEADDR property to the UDP socket";
199 if (bind(new_socket.get(),
200 reinterpret_cast<struct sockaddr*
>(&local_sock_addr),
201 sizeof(local_sock_addr))) {
202 LOG(ERROR) <<
"Could not bind UDP socket";
207 struct ip_mreq multicast_group;
208 multicast_group.imr_multiaddr = local_in_addr;
210 if (options->interface_address().empty()) {
211 LOG(ERROR) <<
"Interface address is required for multicast, which can be "
212 "specified in udp url, e.g. "
213 "udp://ip:port?interface=interface_ip.";
216 if (inet_pton(AF_INET, options->interface_address().c_str(),
217 &multicast_group.imr_interface) != 1) {
218 LOG(ERROR) <<
"Malformed IPv4 interface address "
219 << options->interface_address();
223 if (setsockopt(new_socket.get(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
224 reinterpret_cast<const char*
>(&multicast_group),
225 sizeof(multicast_group)) < 0) {
226 LOG(ERROR) <<
"Failed to join multicast group.";
230 #if defined(__linux__)
233 const int optval_zero = 0;
234 if (setsockopt(new_socket.get(), IPPROTO_IP, IP_MULTICAST_ALL,
235 reinterpret_cast<const char*
>(&optval_zero),
236 sizeof(optval_zero)) < 0 &&
237 errno != ENOPROTOOPT) {
238 LOG(ERROR) <<
"Failed to disable IP_MULTICAST_ALL option.";
241 #endif // #if defined(__linux__)
245 if (options->timeout_us() != 0) {
247 tv.tv_sec = options->timeout_us() / 1000000;
248 tv.tv_usec = options->timeout_us() % 1000000;
249 if (setsockopt(new_socket.get(), SOL_SOCKET, SO_RCVTIMEO,
250 reinterpret_cast<char*
>(&tv),
sizeof(tv)) < 0) {
251 LOG(ERROR) <<
"Failed to set socket timeout.";
256 socket_ = new_socket.release();
int64_t Read(void *buffer, uint64_t length) override
const std::string & file_name() const
bool Tell(uint64_t *position) override
bool Seek(uint64_t position) override
UdpFile(const char *address_and_port)
static std::unique_ptr< UdpOptions > ParseFromString(base::StringPiece udp_url)
Define an abstract file interface.
int64_t Write(const void *buffer, uint64_t length) override
bool Open() override
Internal open. Should not be used directly.