Merge branch 'development' into LTS_development

# Conflicts:
#	CMakeLists.txt
#	src/input/input_buffer.cpp
This commit is contained in:
Thulinma 2017-07-22 18:55:12 +02:00
commit d42bf9777e
23 changed files with 381 additions and 27 deletions

117
lib/downloader.cpp Normal file
View file

@ -0,0 +1,117 @@
#include "downloader.h"
#include "defines.h"
#include "timing.h"
namespace HTTP{
/// Returns a reference to the internal HTTP::Parser body element
std::string &Downloader::data(){return H.body;}
/// Returns the status text of the HTTP Request.
std::string &Downloader::getStatusText(){return H.method;}
/// Returns the status code of the HTTP Request.
uint32_t Downloader::getStatusCode(){return atoi(H.url.c_str());}
/// Returns true if the HTTP Request is OK
bool Downloader::isOk(){return (getStatusCode() == 200);}
/// Returns the given header from the response, or empty string if it does not exist.
std::string Downloader::getHeader(const std::string &headerName){
return H.GetHeader(headerName);
}
/// Simply turns link into a HTTP::URL and calls get(const HTTP::URL&)
bool Downloader::get(const std::string &link){
HTTP::URL uri(link);
return get(uri);
}
/// Sets an extra (or overridden) header to be sent with outgoing requests.
void Downloader::setHeader(const std::string &name, const std::string &val){
extraHeaders[name] = val;
}
/// Clears all extra/override headers for outgoing requests.
void Downloader::clearHeaders(){extraHeaders.clear();}
/// Downloads the given URL into 'H', returns true on success.
/// Makes at most 5 attempts, and will wait no longer than 5 seconds without receiving data.
bool Downloader::get(const HTTP::URL &link, uint8_t maxRecursiveDepth){
if (!link.host.size()){return false;}
if (link.protocol != "http"){
FAIL_MSG("Protocol not supported: %s", link.protocol.c_str());
return false;
}
INFO_MSG("Retrieving %s", link.getUrl().c_str());
unsigned int loop = 6; // max 5 attempts
while (--loop){// loop while we are unsuccessful
H.Clean();
// Reconnect if needed
if (!S || link.host != connectedHost || link.getPort() != connectedPort){
S.close();
connectedHost = link.host;
connectedPort = link.getPort();
S = Socket::Connection(connectedHost, connectedPort, true);
}
H.url = "/" + link.path;
if (link.args.size()){H.url += "?" + link.args;}
if (link.port.size()){
H.SetHeader("Host", link.host + ":" + link.port);
}else{
H.SetHeader("Host", link.host);
}
H.SetHeader("User-Agent", "MistServer " PACKAGE_VERSION);
H.SetHeader("X-Version", PACKAGE_VERSION);
H.SetHeader("Accept", "*/*");
if (extraHeaders.size()){
for (std::map<std::string, std::string>::iterator it = extraHeaders.begin();
it != extraHeaders.end(); ++it){
H.SetHeader(it->first, it->second);
}
}
H.SendRequest(S);
H.Clean();
uint64_t reqTime = Util::bootSecs();
while (S && Util::bootSecs() < reqTime + 5){
// No data? Wait for a second or so.
if (!S.spool()){
if (progressCallback != 0){
if (!progressCallback()){
WARN_MSG("Download aborted by callback");
return false;
}
}
Util::sleep(250);
continue;
}
// Data! Check if we can parse it...
if (H.Read(S)){
if (getStatusCode() >= 300 && getStatusCode() < 400){
// follow redirect
std::string location = getHeader("Location");
if (maxRecursiveDepth == 0){
FAIL_MSG("Maximum redirect depth reached: %s", location.c_str());
return false;
}else{
FAIL_MSG("Following redirect to %s", location.c_str());
return get(link.link(location), maxRecursiveDepth--);
}
}
return true; // Success!
}
// reset the 5 second timeout
reqTime = Util::bootSecs();
}
if (S){
FAIL_MSG("Timeout while retrieving %s", link.getUrl().c_str());
return false;
}
Util::sleep(500); // wait a bit before retrying
}
FAIL_MSG("Could not retrieve %s", link.getUrl().c_str());
return false;
}
}

27
lib/downloader.h Normal file
View file

@ -0,0 +1,27 @@
#include "http_parser.h"
#include "socket.h"
namespace HTTP{
class Downloader{
public:
Downloader(){progressCallback = 0;}
std::string &data();
bool get(const std::string &link);
bool get(const HTTP::URL &link, uint8_t maxRecursiveDepth = 6);
std::string getHeader(const std::string &headerName);
std::string &getStatusText();
uint32_t getStatusCode();
bool isOk();
bool (*progressCallback)(); ///< Called every time the socket stalls, up to 4X per second.
void setHeader(const std::string &name, const std::string &val);
void clearHeaders();
private:
std::map<std::string, std::string> extraHeaders; ///< Holds extra headers to sent with request
std::string connectedHost; ///< Currently connected host name
uint32_t connectedPort; ///< Currently connected port number
Parser H; ///< HTTP parser for downloader
Socket::Connection S; ///< TCP socket for downloader
};
}

View file

@ -154,7 +154,7 @@ std::string HTTP::URL::getBareUrl() const{
}
///Returns a URL object for the given link, resolved relative to the current URL object.
HTTP::URL HTTP::URL::link(const std::string &l){
HTTP::URL HTTP::URL::link(const std::string &l) const{
//Full link
if (l.find("://") < l.find('/') && l.find('/' != std::string::npos)){
DONTEVEN_MSG("Full link: %s", l.c_str());

View file

@ -83,7 +83,7 @@ namespace HTTP {
std::string path;///<Path after the first slash (not inclusive) but before any question mark
std::string args;///<Everything after the question mark in the path, if it was present
std::string frag;///<Everything after the # in the path, if it was present
URL link(const std::string &l);
URL link(const std::string &l) const;
};
}//HTTP namespace

View file

@ -574,7 +574,12 @@ namespace MP4 {
}
uint32_t AVCC::getSPSLen() {
return getInt16(6);
uint16_t len = getInt16(6);
if (len > payloadSize() - 8){
WARN_MSG("SPS length of %u is more than AVCC box size %lu", len, payloadSize());
return 0;
}
return len;
}
char * AVCC::getSPS() {
@ -621,7 +626,16 @@ namespace MP4 {
uint32_t AVCC::getPPSLen() {
int offset = 8 + getSPSLen() + 1;
return getInt16(offset);
if (offset > payloadSize() - 2){
WARN_MSG("Invalid PPS length offset! Aborting PPS read.");
return 0;
}
uint16_t len = getInt16(offset);
if (len > payloadSize() - offset - 2){
WARN_MSG("PPS length of %u is more than AVCC box size %lu", len, payloadSize());
return 0;
}
return len;
}
char * AVCC::getPPS() {

View file

@ -15,7 +15,6 @@ namespace Util {
/// Deals with spawning, monitoring and stopping child processes
class Procs {
private:
static bool childRunning(pid_t p);
static tthread::mutex plistMutex;
static std::set<pid_t> plist; ///< Holds active process list.
static bool thread_handler;///< True while thread handler should be running.
@ -25,6 +24,7 @@ namespace Util {
static char* const* dequeToArgv(std::deque<std::string> & argDeq);
static void grim_reaper(void * n);
public:
static bool childRunning(pid_t p);
static tthread::thread * reaper_thread;
static bool handler_set; ///< If true, the sigchld handler has been setup.
static void setHandler();

View file

@ -548,6 +548,9 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
flags |= O_NONBLOCK;
fcntl(sock, F_SETFL, flags);
}
int optval = 1;
int optlen = sizeof(optval);
setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
}
}// Socket::Connection TCP Contructor
@ -985,6 +988,11 @@ Socket::Connection Socket::Server::accept(bool nonblock){
flags |= O_NONBLOCK;
fcntl(r, F_SETFL, flags);
}
if (r >= 0){
int optval = 1;
int optlen = sizeof(optval);
setsockopt(r, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
}
Socket::Connection tmp(r);
tmp.remoteaddr = tmpaddr;
if (r < 0){