Initial import of Widevine Common Encryption DRM engine

Builds libwvmdrmengine.so, which is loaded by the new
MediaDrm APIs to support playback of Widevine/CENC
protected content.

Change-Id: I6f57dd37083dfd96c402cb9dd137c7d74edc8f1c
This commit is contained in:
Jeff Tinker
2013-03-21 17:39:02 -07:00
parent 38334efbe7
commit 1a8aa0dd05
211 changed files with 51913 additions and 144 deletions

View File

@@ -0,0 +1,192 @@
// Copyright 2013 Google Inc. All Rights Reserved.
#include "http_socket.h"
#include <errno.h>
#include <fcntl.h>
#include <netdb.h>
#include <string.h>
#include <sys/socket.h>
#include "log.h"
namespace wvcdm {
HttpSocket::HttpSocket() : socket_fd_(-1), timeout_enabled_(false) {}
HttpSocket::~HttpSocket()
{
CloseSocket();
}
void HttpSocket::CloseSocket()
{
if (socket_fd_ != -1) {
close(socket_fd_);
socket_fd_ = -1;
}
}
// Extracts the domain name and resource path from the input url parameter.
// The results are put in domain_name and resource_path respectively.
// The format of the url can begin with <protocol/scheme>:://domain server/...
// or dowmain server/resource_path
void HttpSocket::GetDomainNameAndPathFromUrl(const std::string& url,
std::string& domain_name,
std::string& resource_path) {
domain_name.clear();
resource_path.clear();
size_t start = url.find("//");
size_t end = url.npos;
if (start != url.npos) {
end = url.find("/", start + 2);
if (end != url.npos) {
domain_name.assign(url, start + 2, end - start - 2);
resource_path.assign(url, end + 1, url.npos);
} else {
domain_name.assign(url, start + 2, url.npos);
}
} else {
// no scheme/protocol in url
end = url.find("/");
if (end != url.npos) {
domain_name.assign(url, 0, end);
resource_path.assign(url, end + 1, url.npos);
} else {
domain_name.assign(url);
}
}
// strips port number if present, e.g. https://www.domain.com:8888/...
end = domain_name.find(":");
if (end != domain_name.npos) {
domain_name.erase(end);
}
}
bool HttpSocket::Connect(const char* url, const std::string& port, bool enable_timeout)
{
GetDomainNameAndPathFromUrl(url, domain_name_, resource_path_);
socket_fd_ = socket(AF_INET, SOCK_STREAM, 0);
if (socket_fd_ < 0) {
LOGE("cannot open socket %d", errno);
return false;
}
int reuse = 1;
if (setsockopt(socket_fd_, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)) == -1) {
CloseSocket();
LOGE("setsockopt error %d", errno);
return false;
}
struct addrinfo hints;
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_INET;
hints.ai_socktype = SOCK_STREAM;
struct addrinfo* addr_info = NULL;
bool status = true;
int ret = getaddrinfo(domain_name_.c_str(), port.c_str(), &hints, &addr_info);
if (ret != 0) {
CloseSocket();
LOGE("getaddrinfo failed with %d", ret);
status = false;
} else {
if (connect(socket_fd_, addr_info->ai_addr, addr_info->ai_addrlen) == -1) {
CloseSocket();
LOGE("cannot connect socket to %s, error=%d", domain_name_.c_str(), errno);
status = false;
}
}
timeout_enabled_ = enable_timeout;
if (addr_info != NULL) {
freeaddrinfo(addr_info);
}
return status;
}
int HttpSocket::Read(char* data, int len) {
return(Read(data, len, 0));
}
// makes non-blocking mode only during read, it supports timeout for read
// returns -1 for error, number of bytes read for success
int HttpSocket::Read(char* data, int len, int timeout_in_ms)
{
bool use_timeout = (timeout_enabled_ && (timeout_in_ms > 0));
int original_flags = 0;
if (use_timeout) {
original_flags = fcntl(socket_fd_, F_GETFL, 0);
if (original_flags == -1) {
LOGE("fcntl error %d", errno);
return -1;
}
if (fcntl(socket_fd_, F_SETFL, original_flags | O_NONBLOCK) == -1) {
LOGE("fcntl error %d", errno);
return -1;
}
}
int total_read = 0;
int read = 0;
int to_read = len;
while (to_read > 0) {
if (use_timeout) {
fd_set read_fds;
struct timeval tv;
tv.tv_sec = timeout_in_ms / 1000;
tv.tv_usec = (timeout_in_ms % 1000) * 1000;
FD_ZERO(&read_fds);
FD_SET(socket_fd_, &read_fds);
if (select(socket_fd_ + 1, &read_fds, NULL, NULL, &tv) == -1) {
LOGE("select failed");
break;
}
if (!FD_ISSET(socket_fd_, &read_fds)) {
LOGE("socket read timeout");
break;
}
}
read = recv(socket_fd_, data, to_read, 0);
if (read > 0) {
to_read -= read;
data += read;
total_read += read;
} else if (read == 0) {
// in blocking mode, zero read mean's peer closed.
// in non-blocking mode, select said that there is data. so it should not happen
break;
} else {
LOGE("recv returned %d, error = %d", read, errno);
break;
}
}
if (use_timeout) {
fcntl(socket_fd_, F_SETFL, original_flags); // now blocking again
}
return total_read;
}
int HttpSocket::Write(const char* data, int len)
{
int total_sent = 0;
int sent = 0;
int to_send = len;
while (to_send > 0) {
sent = send(socket_fd_, data, to_send, 0);
if (sent > 0) {
to_send -= sent;
data += sent;
total_sent += sent;
} else if (sent == 0) {
usleep(10); // retry later
} else {
LOGE("send returned error %d", errno);
}
}
return total_sent;
}
} // namespace wvcdm