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 if (options->is_source_specific_multicast()) {
208 struct ip_mreq_source source_multicast_group;
210 source_multicast_group.imr_multiaddr = local_in_addr;
211 if (inet_pton(AF_INET,
212 options->interface_address().c_str(),
213 &source_multicast_group.imr_interface) != 1) {
214 LOG(ERROR) <<
"Malformed IPv4 interface address " 215 << options->interface_address();
218 if (inet_pton(AF_INET,
219 options->source_address().c_str(),
220 &source_multicast_group.imr_sourceaddr) != 1) {
221 LOG(ERROR) <<
"Malformed IPv4 source specific multicast address " 222 << options->source_address();
226 if (setsockopt(new_socket.get(),
228 IP_ADD_SOURCE_MEMBERSHIP,
229 reinterpret_cast<const char*
>(&source_multicast_group),
230 sizeof(source_multicast_group)) < 0) {
231 LOG(ERROR) <<
"Failed to join multicast group.";
236 struct ip_mreq multicast_group;
238 multicast_group.imr_multiaddr = local_in_addr;
240 if (inet_pton(AF_INET, options->interface_address().c_str(),
241 &multicast_group.imr_interface) != 1) {
242 LOG(ERROR) <<
"Malformed IPv4 interface address " 243 << options->interface_address();
247 if (setsockopt(new_socket.get(), IPPROTO_IP, IP_ADD_MEMBERSHIP,
248 reinterpret_cast<const char*
>(&multicast_group),
249 sizeof(multicast_group)) < 0) {
250 LOG(ERROR) <<
"Failed to join multicast group.";
256 #if defined(__linux__) 259 const int optval_zero = 0;
260 if (setsockopt(new_socket.get(), IPPROTO_IP, IP_MULTICAST_ALL,
261 reinterpret_cast<const char*
>(&optval_zero),
262 sizeof(optval_zero)) < 0 &&
263 errno != ENOPROTOOPT) {
264 LOG(ERROR) <<
"Failed to disable IP_MULTICAST_ALL option.";
267 #endif // #if defined(__linux__) 271 if (options->timeout_us() != 0) {
273 tv.tv_sec = options->timeout_us() / 1000000;
274 tv.tv_usec = options->timeout_us() % 1000000;
275 if (setsockopt(new_socket.get(), SOL_SOCKET, SO_RCVTIMEO,
276 reinterpret_cast<char*
>(&tv),
sizeof(tv)) < 0) {
277 LOG(ERROR) <<
"Failed to set socket timeout.";
282 socket_ = new_socket.release();
int64_t Read(void *buffer, uint64_t length) override
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
const std::string & file_name() const
All the methods that are virtual are virtual for mocking.
bool Open() override
Internal open. Should not be used directly.