7 #include "packager/media/file/udp_file.h"
12 #define close closesocket
14 #include <arpa/inet.h>
17 #include <sys/socket.h>
19 #define INVALID_SOCKET -1
20 #endif // defined(OS_WIN)
24 #include "packager/base/logging.h"
25 #include "packager/media/file/udp_options.h"
32 bool IsIpv4MulticastAddress(
const struct in_addr& addr) {
33 return (ntohl(addr.s_addr) & 0xf0000000) == 0xe0000000;
40 socket_(INVALID_SOCKET) {}
42 UdpFile::~UdpFile() {}
45 if (socket_ != INVALID_SOCKET) {
47 socket_ = INVALID_SOCKET;
55 DCHECK_GE(length, 65535u)
56 <<
"Buffer may be too small to read entire datagram.";
58 if (socket_ == INVALID_SOCKET)
63 result = recvfrom(socket_, reinterpret_cast<char *>(buffer),
65 }
while ((result == -1) && (errno == EINTR));
76 if (socket_ == INVALID_SOCKET)
79 return std::numeric_limits<int64_t>::max();
98 class LibWinsockInitializer {
100 LibWinsockInitializer() {
102 error_ = WSAStartup(MAKEWORD(2, 2), &wsa_data);
105 ~LibWinsockInitializer() {
106 if (error_ == 0) WSACleanup();
109 int error()
const {
return error_; }
114 #endif // defined(OS_WIN)
118 explicit ScopedSocket(SOCKET sock_fd)
119 : sock_fd_(sock_fd) {}
122 if (sock_fd_ != INVALID_SOCKET)
126 SOCKET
get() {
return sock_fd_; }
129 SOCKET socket = sock_fd_;
130 sock_fd_ = INVALID_SOCKET;
137 DISALLOW_COPY_AND_ASSIGN(ScopedSocket);
142 static LibWinsockInitializer lib_winsock_initializer;
143 if (lib_winsock_initializer.error() != 0) {
144 LOG(ERROR) <<
"Winsock start up failed with error "
145 << lib_winsock_initializer.error();
148 #endif // defined(OS_WIN)
150 DCHECK_EQ(INVALID_SOCKET, socket_);
152 std::unique_ptr<UdpOptions> options =
157 ScopedSocket new_socket(socket(AF_INET, SOCK_DGRAM, 0));
158 if (new_socket.get() == INVALID_SOCKET) {
159 LOG(ERROR) <<
"Could not allocate socket.";
163 struct in_addr local_in_addr = {0};
164 if (inet_pton(AF_INET, options->address().c_str(),
165 &local_in_addr) != 1) {
166 LOG(ERROR) <<
"Malformed IPv4 address " << options->address();
170 struct sockaddr_in local_sock_addr = {0};
172 local_sock_addr.sin_family = AF_INET;
173 local_sock_addr.sin_port = htons(options->port());
174 const bool is_multicast = IsIpv4MulticastAddress(local_in_addr);
176 local_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY);
178 local_sock_addr.sin_addr = local_in_addr;
181 if (options->reuse()) {
182 const int optval = 1;
183 if (setsockopt(new_socket.get(), SOL_SOCKET, SO_REUSEADDR,
184 reinterpret_cast<const char *
>(&optval),
185 sizeof(optval)) < 0) {
187 <<
"Could not apply the SO_REUSEADDR property to the UDP socket";
192 if (bind(new_socket.get(),
193 reinterpret_cast<struct sockaddr*
>(&local_sock_addr),
194 sizeof(local_sock_addr))) {
195 LOG(ERROR) <<
"Could not bind UDP socket";
200 struct ip_mreq multicast_group;
201 multicast_group.imr_multiaddr = local_in_addr;
203 if (options->interface_address().empty()) {
204 LOG(ERROR) <<
"Interface address is required for multicast, which can be "
205 "specified in udp url, e.g. "
206 "udp://ip:port?interface=interface_ip.";
209 if (inet_pton(AF_INET, options->interface_address().c_str(),
210 &multicast_group.imr_interface) != 1) {
211 LOG(ERROR) <<
"Malformed IPv4 interface address "
212 << options->interface_address();
216 if (setsockopt(new_socket.get(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
217 reinterpret_cast<const char *
>(&multicast_group),
218 sizeof(multicast_group)) < 0) {
219 LOG(ERROR) <<
"Failed to join multicast group.";
225 if (options->timeout_us() != 0) {
227 tv.tv_sec = options->timeout_us() / 1000000;
228 tv.tv_usec = options->timeout_us() % 1000000;
229 if (setsockopt(new_socket.get(), SOL_SOCKET, SO_RCVTIMEO,
230 reinterpret_cast<char*
>(&tv),
sizeof(tv)) < 0) {
231 LOG(ERROR) <<
"Failed to set socket timeout.";
236 socket_ = new_socket.release();