diff --git a/AUTHORS b/AUTHORS index 41f3a0f641..f156b9c792 100644 --- a/AUTHORS +++ b/AUTHORS @@ -14,6 +14,7 @@ # Please keep the list sorted. Anders Hasselqvist +Chun-da Chen Google Inc. <*@google.com> Leandro Moreira Philo Inc. <*@philo.com> diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 8f7c6b1ea4..9a8afa8601 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -24,6 +24,7 @@ Anders Hasselqvist Bei Li +Chun-da Chen Gabe Kopley Haoming Chen Jacob Trimble diff --git a/packager/media/file/file.gyp b/packager/media/file/file.gyp index ed7d8af97d..355afe87bc 100644 --- a/packager/media/file/file.gyp +++ b/packager/media/file/file.gyp @@ -26,21 +26,11 @@ 'memory_file.h', 'threaded_io_file.cc', 'threaded_io_file.h', + 'udp_file.cc', 'udp_file.h', 'udp_options.cc', 'udp_options.h', ], - 'conditions': [ - ['OS == "win"', { - 'sources': [ - 'udp_file_win.cc', - ], - }, { - 'sources': [ - 'udp_file_posix.cc', - ], - }], - ], 'dependencies': [ '../../base/base.gyp:base', '../../third_party/gflags/gflags.gyp:gflags', diff --git a/packager/media/file/udp_file_posix.cc b/packager/media/file/udp_file.cc similarity index 66% rename from packager/media/file/udp_file_posix.cc rename to packager/media/file/udp_file.cc index 769dada00c..e0bb970efd 100644 --- a/packager/media/file/udp_file_posix.cc +++ b/packager/media/file/udp_file.cc @@ -6,26 +6,29 @@ #include "packager/media/file/udp_file.h" +#if defined(OS_WIN) +#include +#include +#define close closesocket +#else #include #include #include #include #include +#define INVALID_SOCKET -1 +#endif // defined(OS_WIN) #include #include "packager/base/logging.h" #include "packager/media/file/udp_options.h" -// TODO(tinskip): Adapt to work with winsock. - namespace shaka { namespace media { namespace { -const int kInvalidSocket(-1); - bool IsIpv4MulticastAddress(const struct in_addr& addr) { return (ntohl(addr.s_addr) & 0xf0000000) == 0xe0000000; } @@ -34,14 +37,14 @@ bool IsIpv4MulticastAddress(const struct in_addr& addr) { UdpFile::UdpFile(const char* file_name) : File(file_name), - socket_(kInvalidSocket) {} + socket_(INVALID_SOCKET) {} UdpFile::~UdpFile() {} bool UdpFile::Close() { - if (socket_ != kInvalidSocket) { + if (socket_ != INVALID_SOCKET) { close(socket_); - socket_ = kInvalidSocket; + socket_ = INVALID_SOCKET; } delete this; return true; @@ -52,12 +55,13 @@ int64_t UdpFile::Read(void* buffer, uint64_t length) { DCHECK_GE(length, 65535u) << "Buffer may be too small to read entire datagram."; - if (socket_ == kInvalidSocket) + if (socket_ == INVALID_SOCKET) return -1; int64_t result; do { - result = recvfrom(socket_, buffer, length, 0, NULL, 0); + result = recvfrom(socket_, reinterpret_cast(buffer), + length, 0, NULL, 0); } while ((result == -1) && (errno == EINTR)); return result; @@ -69,7 +73,7 @@ int64_t UdpFile::Write(const void* buffer, uint64_t length) { } int64_t UdpFile::Size() { - if (socket_ == kInvalidSocket) + if (socket_ == INVALID_SOCKET) return -1; return std::numeric_limits::max(); @@ -90,32 +94,60 @@ bool UdpFile::Tell(uint64_t* position) { return false; } +#if defined(OS_WIN) +class LibWinsockInitializer { + public: + LibWinsockInitializer() { + WSADATA wsa_data; + error_ = WSAStartup(MAKEWORD(2, 2), &wsa_data); + } + + ~LibWinsockInitializer() { + if (error_ == 0) WSACleanup(); + } + + int error() const { return error_; } + + private: + int error_; +}; +#endif // defined(OS_WIN) + class ScopedSocket { public: - explicit ScopedSocket(int sock_fd) + explicit ScopedSocket(SOCKET sock_fd) : sock_fd_(sock_fd) {} ~ScopedSocket() { - if (sock_fd_ != kInvalidSocket) + if (sock_fd_ != INVALID_SOCKET) close(sock_fd_); } - int get() { return sock_fd_; } + SOCKET get() { return sock_fd_; } - int release() { - int socket = sock_fd_; - sock_fd_ = kInvalidSocket; + SOCKET release() { + SOCKET socket = sock_fd_; + sock_fd_ = INVALID_SOCKET; return socket; } private: - int sock_fd_; + SOCKET sock_fd_; DISALLOW_COPY_AND_ASSIGN(ScopedSocket); }; bool UdpFile::Open() { - DCHECK_EQ(kInvalidSocket, socket_); +#if defined(OS_WIN) + static LibWinsockInitializer lib_winsock_initializer; + if (lib_winsock_initializer.error() != 0) { + LOG(ERROR) << "Winsock start up failed with error " + << lib_winsock_initializer.error(); + return false; + } +#endif // defined(OS_WIN) + + DCHECK_EQ(INVALID_SOCKET, socket_); std::unique_ptr options = UdpOptions::ParseFromString(file_name()); @@ -123,25 +155,33 @@ bool UdpFile::Open() { return false; ScopedSocket new_socket(socket(AF_INET, SOCK_DGRAM, 0)); - if (new_socket.get() == kInvalidSocket) { + if (new_socket.get() == INVALID_SOCKET) { LOG(ERROR) << "Could not allocate socket."; return false; } - struct sockaddr_in local_sock_addr; - bzero(&local_sock_addr, sizeof(local_sock_addr)); - // TODO(kqyang): Support IPv6. - local_sock_addr.sin_family = AF_INET; - local_sock_addr.sin_port = htons(options->port()); + struct in_addr local_in_addr = {0}; if (inet_pton(AF_INET, options->address().c_str(), - &local_sock_addr.sin_addr) != 1) { + &local_in_addr) != 1) { LOG(ERROR) << "Malformed IPv4 address " << options->address(); return false; } + struct sockaddr_in local_sock_addr = {0}; + // TODO(kqyang): Support IPv6. + local_sock_addr.sin_family = AF_INET; + local_sock_addr.sin_port = htons(options->port()); + const bool is_multicast = IsIpv4MulticastAddress(local_in_addr); + if (is_multicast) { + local_sock_addr.sin_addr.s_addr = htonl(INADDR_ANY); + } else { + local_sock_addr.sin_addr = local_in_addr; + } + if (options->reuse()) { const int optval = 1; - if (setsockopt(new_socket.get(), SOL_SOCKET, SO_REUSEADDR, &optval, + if (setsockopt(new_socket.get(), SOL_SOCKET, SO_REUSEADDR, + reinterpret_cast(&optval), sizeof(optval)) < 0) { LOG(ERROR) << "Could not apply the SO_REUSEADDR property to the UDP socket"; @@ -156,9 +196,9 @@ bool UdpFile::Open() { return false; } - if (IsIpv4MulticastAddress(local_sock_addr.sin_addr)) { + if (is_multicast) { struct ip_mreq multicast_group; - multicast_group.imr_multiaddr = local_sock_addr.sin_addr; + multicast_group.imr_multiaddr = local_in_addr; if (options->interface_address().empty()) { LOG(ERROR) << "Interface address is required for multicast, which can be " @@ -174,7 +214,8 @@ bool UdpFile::Open() { } if (setsockopt(new_socket.get(), IPPROTO_IP, IP_ADD_MEMBERSHIP, - &multicast_group, sizeof(multicast_group)) < 0) { + reinterpret_cast(&multicast_group), + sizeof(multicast_group)) < 0) { LOG(ERROR) << "Failed to join multicast group."; return false; } diff --git a/packager/media/file/udp_file.h b/packager/media/file/udp_file.h index d85b25f699..6d08df9e11 100644 --- a/packager/media/file/udp_file.h +++ b/packager/media/file/udp_file.h @@ -14,6 +14,12 @@ #include "packager/base/compiler_specific.h" #include "packager/media/file/file.h" +#if defined(OS_WIN) +#include +#else +typedef int SOCKET; +#endif // defined(OS_WIN) + namespace shaka { namespace media { @@ -41,7 +47,7 @@ class UdpFile : public File { bool Open() override; private: - int socket_; + SOCKET socket_; DISALLOW_COPY_AND_ASSIGN(UdpFile); }; diff --git a/packager/media/file/udp_file_win.cc b/packager/media/file/udp_file_win.cc deleted file mode 100644 index 1dde154846..0000000000 --- a/packager/media/file/udp_file_win.cc +++ /dev/null @@ -1,61 +0,0 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file or at -// https://developers.google.com/open-source/licenses/bsd - -#include "packager/media/file/udp_file.h" - -#include "packager/base/logging.h" - -namespace shaka { -namespace media { - -UdpFile::UdpFile(const char* file_name) : File(file_name), socket_(0) { -} - -UdpFile::~UdpFile() {} - -bool UdpFile::Close() { - NOTIMPLEMENTED(); - delete this; - return false; -} - -int64_t UdpFile::Read(void* buffer, uint64_t length) { - NOTIMPLEMENTED(); - return -1; -} - -int64_t UdpFile::Write(const void* buffer, uint64_t length) { - NOTIMPLEMENTED(); - return -1; -} - -int64_t UdpFile::Size() { - NOTIMPLEMENTED(); - return -1; -} - -bool UdpFile::Flush() { - NOTIMPLEMENTED(); - return false; -} - -bool UdpFile::Seek(uint64_t position) { - NOTIMPLEMENTED(); - return false; -} - -bool UdpFile::Tell(uint64_t* position) { - NOTIMPLEMENTED(); - return false; -} - -bool UdpFile::Open() { - NOTIMPLEMENTED(); - return false; -} - -} // namespace media -} // namespace shaka