Merge branch 'development' into LTS_development
This commit is contained in:
commit
c867ea6d26
9 changed files with 105 additions and 39 deletions
|
@ -30,6 +30,11 @@ HTTP::URL::URL(const std::string & url){
|
||||||
size_t first_slash = url.find('/', proto_sep);
|
size_t first_slash = url.find('/', proto_sep);
|
||||||
if (first_slash != std::string::npos){
|
if (first_slash != std::string::npos){
|
||||||
path = url.substr(first_slash+1);
|
path = url.substr(first_slash+1);
|
||||||
|
size_t qmark = path.find('?');
|
||||||
|
if (qmark != std::string::npos){
|
||||||
|
args = path.substr(qmark+1);
|
||||||
|
path.erase(qmark);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
//host and port are now definitely between proto_sep and first_slash
|
//host and port are now definitely between proto_sep and first_slash
|
||||||
//we check for [ at the start because we may have an IPv6 address as host
|
//we check for [ at the start because we may have an IPv6 address as host
|
||||||
|
@ -73,6 +78,7 @@ HTTP::URL::URL(const std::string & url){
|
||||||
EXTREME_MSG("URL protocol: %s", protocol.c_str());
|
EXTREME_MSG("URL protocol: %s", protocol.c_str());
|
||||||
EXTREME_MSG("URL port: %s", port.c_str());
|
EXTREME_MSG("URL port: %s", port.c_str());
|
||||||
EXTREME_MSG("URL path: %s", path.c_str());
|
EXTREME_MSG("URL path: %s", path.c_str());
|
||||||
|
EXTREME_MSG("URL args: %s", args.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
///Returns the port in numeric format
|
///Returns the port in numeric format
|
||||||
|
|
|
@ -77,7 +77,8 @@ namespace HTTP {
|
||||||
std::string host;///< Hostname or IP address of URL
|
std::string host;///< Hostname or IP address of URL
|
||||||
std::string protocol;///<Protocol of URL
|
std::string protocol;///<Protocol of URL
|
||||||
std::string port;///<Port of URL
|
std::string port;///<Port of URL
|
||||||
std::string path;///<Path after the first slash, not inclusive
|
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
|
||||||
};
|
};
|
||||||
|
|
||||||
}//HTTP namespace
|
}//HTTP namespace
|
||||||
|
|
|
@ -807,7 +807,7 @@ namespace IPC {
|
||||||
|
|
||||||
///\brief Creates the next page with the correct size
|
///\brief Creates the next page with the correct size
|
||||||
void sharedServer::newPage() {
|
void sharedServer::newPage() {
|
||||||
sharedPage tmp(std::string(baseName.substr(1) + (char)(myPages.size() + (int)'A')), std::min(((8192 * 2) << myPages.size()), (32 * 1024 * 1024)), false);
|
sharedPage tmp(std::string(baseName.substr(1) + (char)(myPages.size() + (int)'A')), std::min(((8192 * 2) << myPages.size()), (32 * 1024 * 1024)), false, false);
|
||||||
if (!tmp.mapped){
|
if (!tmp.mapped){
|
||||||
tmp.init(std::string(baseName.substr(1) + (char)(myPages.size() + (int)'A')), std::min(((8192 * 2) << myPages.size()), (32 * 1024 * 1024)), true);
|
tmp.init(std::string(baseName.substr(1) + (char)(myPages.size() + (int)'A')), std::min(((8192 * 2) << myPages.size()), (32 * 1024 * 1024)), true);
|
||||||
tmp.master = false;
|
tmp.master = false;
|
||||||
|
|
|
@ -21,6 +21,17 @@
|
||||||
#define SOCKETSIZE 51200ul
|
#define SOCKETSIZE 51200ul
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/// Local-scope only helper function that prints address families
|
||||||
|
static const char* addrFam(int f){
|
||||||
|
switch(f){
|
||||||
|
case AF_UNSPEC: return "Unspecified";
|
||||||
|
case AF_INET: return "IPv4";
|
||||||
|
case AF_INET6: return "IPv6";
|
||||||
|
case PF_UNIX: return "Unix";
|
||||||
|
default: return "???";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Checks bytes (length len) containing a binary-encoded IPv4 or IPv6 IP address, and writes it in human-readable notation to target.
|
/// Checks bytes (length len) containing a binary-encoded IPv4 or IPv6 IP address, and writes it in human-readable notation to target.
|
||||||
/// Writes "unknown" if it cannot decode to a sensible value.
|
/// Writes "unknown" if it cannot decode to a sensible value.
|
||||||
void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
|
void Socket::hostBytesToStr(const char *bytes, size_t len, std::string &target){
|
||||||
|
@ -940,6 +951,7 @@ Socket::UDPConnection::UDPConnection(const UDPConnection &o){
|
||||||
down = 0;
|
down = 0;
|
||||||
if (o.destAddr && o.destAddr_size){
|
if (o.destAddr && o.destAddr_size){
|
||||||
destAddr = malloc(o.destAddr_size);
|
destAddr = malloc(o.destAddr_size);
|
||||||
|
destAddr_size = o.destAddr_size;
|
||||||
if (destAddr){memcpy(destAddr, o.destAddr, o.destAddr_size);}
|
if (destAddr){memcpy(destAddr, o.destAddr, o.destAddr_size);}
|
||||||
}else{
|
}else{
|
||||||
destAddr = 0;
|
destAddr = 0;
|
||||||
|
@ -1015,6 +1027,7 @@ void Socket::UDPConnection::SetDestination(std::string destIp, uint32_t port){
|
||||||
close();
|
close();
|
||||||
family = rp->ai_family;
|
family = rp->ai_family;
|
||||||
sock = socket(family, SOCK_DGRAM, 0);
|
sock = socket(family, SOCK_DGRAM, 0);
|
||||||
|
HIGH_MSG("Set UDP destination: %s:%d (%s)", destIp.c_str(), port, addrFam(family));
|
||||||
freeaddrinfo(result);
|
freeaddrinfo(result);
|
||||||
return;
|
return;
|
||||||
//\todo Possibly detect and handle failure
|
//\todo Possibly detect and handle failure
|
||||||
|
@ -1103,15 +1116,20 @@ void Socket::UDPConnection::SendNow(const char *sdata, size_t len){
|
||||||
/// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets. Optional, left out means automatically chosen
|
/// \arg multicastInterfaces Comma-separated list of interfaces to listen on for multicast packets. Optional, left out means automatically chosen
|
||||||
/// by kernel.
|
/// by kernel.
|
||||||
/// \return Actually bound port number, or zero on error.
|
/// \return Actually bound port number, or zero on error.
|
||||||
int Socket::UDPConnection::bind(int port, std::string iface, const std::string &multicastInterfaces){
|
uint16_t Socket::UDPConnection::bind(int port, std::string iface, const std::string &multicastInterfaces){
|
||||||
close(); // we open a new socket for each attempt
|
close(); // we open a new socket for each attempt
|
||||||
int result = 0;
|
int result = 0;
|
||||||
int addr_ret;
|
int addr_ret;
|
||||||
bool multicast = false;
|
bool multicast = false;
|
||||||
struct addrinfo hints, *addr_result, *rp;
|
struct addrinfo hints, *addr_result, *rp;
|
||||||
memset(&hints, 0, sizeof(hints));
|
memset(&hints, 0, sizeof(hints));
|
||||||
hints.ai_flags = AI_V4MAPPED | AI_ADDRCONFIG | AI_PASSIVE;
|
hints.ai_flags = AI_ADDRCONFIG | AI_PASSIVE | AI_V4MAPPED;
|
||||||
hints.ai_family = family;
|
if (destAddr && destAddr_size){
|
||||||
|
hints.ai_family = ((struct sockaddr_in *)destAddr)->sin_family;
|
||||||
|
}else{
|
||||||
|
hints.ai_family = AF_UNSPEC;
|
||||||
|
}
|
||||||
|
|
||||||
hints.ai_socktype = SOCK_DGRAM;
|
hints.ai_socktype = SOCK_DGRAM;
|
||||||
hints.ai_protocol = IPPROTO_UDP;
|
hints.ai_protocol = IPPROTO_UDP;
|
||||||
|
|
||||||
|
@ -1135,11 +1153,34 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
||||||
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
sock = socket(rp->ai_family, rp->ai_socktype, rp->ai_protocol);
|
||||||
if (sock == -1){continue;}
|
if (sock == -1){continue;}
|
||||||
char human_addr[INET6_ADDRSTRLEN];
|
char human_addr[INET6_ADDRSTRLEN];
|
||||||
getnameinfo(rp->ai_addr, rp->ai_addrlen, human_addr, INET6_ADDRSTRLEN, 0, 0, NI_NUMERICHOST);
|
char human_port[16];
|
||||||
MEDIUM_MSG("Attempting bind to %s (%s)", human_addr, rp->ai_family == AF_INET6 ? "IPv6" : "IPv4");
|
getnameinfo(rp->ai_addr, rp->ai_addrlen, human_addr, INET6_ADDRSTRLEN, human_port, 16, NI_NUMERICHOST | NI_NUMERICSERV);
|
||||||
|
MEDIUM_MSG("Attempting bind to %s:%s (%s)", human_addr, human_port, addrFam(rp->ai_family));
|
||||||
|
family = rp->ai_family;
|
||||||
|
hints.ai_family = family;
|
||||||
|
if (family == AF_INET6){
|
||||||
|
sockaddr_in6 *addr6 = (sockaddr_in6 *)(rp->ai_addr);
|
||||||
|
result = ntohs(addr6->sin6_port);
|
||||||
|
if (memcmp((char *)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){
|
||||||
|
// IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte
|
||||||
|
multicast = (((char *)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0;
|
||||||
|
}else{
|
||||||
|
//"normal" IPv6 address - prefix ff00::/8
|
||||||
|
multicast = (((char *)&(addr6->sin6_addr))[0] == 0xFF);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
sockaddr_in *addr4 = (sockaddr_in *)(rp->ai_addr);
|
||||||
|
result = ntohs(addr4->sin_port);
|
||||||
|
// multicast has a "1110" bit prefix
|
||||||
|
multicast = (((char *)&(addr4->sin_addr))[0] & 0xF0) == 0xE0;
|
||||||
|
}
|
||||||
|
if (multicast){
|
||||||
|
const int optval = 1;
|
||||||
|
if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval)) < 0) {
|
||||||
|
WARN_MSG("Could not set multicast UDP socket re-use!");
|
||||||
|
}
|
||||||
|
}
|
||||||
if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0){
|
if (::bind(sock, rp->ai_addr, rp->ai_addrlen) == 0){
|
||||||
family = rp->ai_family;
|
|
||||||
hints.ai_family = family;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (err_str.size()){err_str += ", ";}
|
if (err_str.size()){err_str += ", ";}
|
||||||
|
@ -1148,29 +1189,11 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
||||||
err_str += strerror(errno);
|
err_str += strerror(errno);
|
||||||
close(); // we open a new socket for each attempt
|
close(); // we open a new socket for each attempt
|
||||||
}
|
}
|
||||||
|
freeaddrinfo(addr_result);
|
||||||
if (sock == -1){
|
if (sock == -1){
|
||||||
FAIL_MSG("Could not open %s for UDP: %s", iface.c_str(), err_str.c_str());
|
FAIL_MSG("Could not open %s for UDP: %s", iface.c_str(), err_str.c_str());
|
||||||
freeaddrinfo(addr_result);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
// socket is bound! Let's collect some more data...
|
|
||||||
if (family == AF_INET6){
|
|
||||||
sockaddr_in6 *addr6 = (sockaddr_in6 *)(rp->ai_addr);
|
|
||||||
result = ntohs(addr6->sin6_port);
|
|
||||||
if (memcmp((char *)&(addr6->sin6_addr), "\000\000\000\000\000\000\000\000\000\000\377\377", 12) == 0){
|
|
||||||
// IPv6-mapped IPv4 address - 13th byte ([12]) holds the first IPv4 byte
|
|
||||||
multicast = (((char *)&(addr6->sin6_addr))[12] & 0xF0) == 0xE0;
|
|
||||||
}else{
|
|
||||||
//"normal" IPv6 address - prefix ff00::/8
|
|
||||||
multicast = (((char *)&(addr6->sin6_addr))[0] == 0xFF);
|
|
||||||
}
|
|
||||||
}else{
|
|
||||||
sockaddr_in *addr4 = (sockaddr_in *)(rp->ai_addr);
|
|
||||||
result = ntohs(addr4->sin_port);
|
|
||||||
// multicast has a "1110" bit prefix
|
|
||||||
multicast = (((char *)&(addr4->sin_addr))[0] & 0xF0) == 0xE0;
|
|
||||||
}
|
|
||||||
freeaddrinfo(addr_result);
|
|
||||||
|
|
||||||
// handle multicast membership(s)
|
// handle multicast membership(s)
|
||||||
if (multicast){
|
if (multicast){
|
||||||
|
@ -1182,8 +1205,7 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
||||||
if ((addr_ret = getaddrinfo(iface.c_str(), 0, &hints, &resmulti)) != 0){
|
if ((addr_ret = getaddrinfo(iface.c_str(), 0, &hints, &resmulti)) != 0){
|
||||||
WARN_MSG("Unable to parse multicast address: %s", gai_strerror(addr_ret));
|
WARN_MSG("Unable to parse multicast address: %s", gai_strerror(addr_ret));
|
||||||
close();
|
close();
|
||||||
result = -1;
|
return 0;
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!multicastInterfaces.length()){
|
if (!multicastInterfaces.length()){
|
||||||
|
@ -1254,7 +1276,18 @@ int Socket::UDPConnection::bind(int port, std::string iface, const std::string &
|
||||||
}
|
}
|
||||||
freeaddrinfo(resmulti); // free resolved multicast addr
|
freeaddrinfo(resmulti); // free resolved multicast addr
|
||||||
}
|
}
|
||||||
return result;
|
//get port number
|
||||||
|
struct sockaddr_storage fin_addr;
|
||||||
|
socklen_t alen = sizeof(fin_addr);
|
||||||
|
if (getsockname(sock, (struct sockaddr*)&fin_addr, &alen) == 0){
|
||||||
|
if (family == AF_INET6){
|
||||||
|
return ntohs(((struct sockaddr_in6*)&fin_addr)->sin6_port);
|
||||||
|
}else{
|
||||||
|
return ntohs(((struct sockaddr_in*)&fin_addr)->sin_port);
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempt to receive a UDP packet.
|
/// Attempt to receive a UDP packet.
|
||||||
|
|
|
@ -142,7 +142,7 @@ namespace Socket{
|
||||||
~UDPConnection();
|
~UDPConnection();
|
||||||
void close();
|
void close();
|
||||||
int getSock();
|
int getSock();
|
||||||
int bind(int port, std::string iface = "", const std::string &multicastAddress = "");
|
uint16_t bind(int port, std::string iface = "", const std::string &multicastAddress = "");
|
||||||
void setBlocking(bool blocking);
|
void setBlocking(bool blocking);
|
||||||
void SetDestination(std::string hostname, uint32_t port);
|
void SetDestination(std::string hostname, uint32_t port);
|
||||||
void GetDestination(std::string &hostname, uint32_t &port);
|
void GetDestination(std::string &hostname, uint32_t &port);
|
||||||
|
|
|
@ -787,6 +787,7 @@ namespace TS {
|
||||||
case 0x15: return "meta PES";
|
case 0x15: return "meta PES";
|
||||||
case 0x16: return "meta section";
|
case 0x16: return "meta section";
|
||||||
case 0x1B: return "H264";
|
case 0x1B: return "H264";
|
||||||
|
case 0x24: return "H265";
|
||||||
case 0x81: return "AC3";
|
case 0x81: return "AC3";
|
||||||
default: return "unknown";
|
default: return "unknown";
|
||||||
}
|
}
|
||||||
|
@ -798,6 +799,7 @@ namespace TS {
|
||||||
case 0x02:
|
case 0x02:
|
||||||
case 0x09:
|
case 0x09:
|
||||||
case 0x10:
|
case 0x10:
|
||||||
|
case 0x24:
|
||||||
case 0x1B: return "video";
|
case 0x1B: return "video";
|
||||||
case 0x03:
|
case 0x03:
|
||||||
case 0x04:
|
case 0x04:
|
||||||
|
|
|
@ -36,6 +36,13 @@ namespace Mist{
|
||||||
capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed.";
|
capa["optional"]["debug"]["help"] = "The debug level at which messages need to be printed.";
|
||||||
capa["optional"]["debug"]["option"] = "--debug";
|
capa["optional"]["debug"]["option"] = "--debug";
|
||||||
capa["optional"]["debug"]["type"] = "debug";
|
capa["optional"]["debug"]["type"] = "debug";
|
||||||
|
|
||||||
|
JSON::Value option;
|
||||||
|
option["long"] = "noinput";
|
||||||
|
option["short"] = "N";
|
||||||
|
option["help"] = "Do not start input if not already started";
|
||||||
|
option["value"].append(0ll);
|
||||||
|
cfg->addOption("noinput", option);
|
||||||
}
|
}
|
||||||
|
|
||||||
Output::Output(Socket::Connection & conn) : myConn(conn){
|
Output::Output(Socket::Connection & conn) : myConn(conn){
|
||||||
|
@ -51,6 +58,7 @@ namespace Mist{
|
||||||
maxSkipAhead = 7500;
|
maxSkipAhead = 7500;
|
||||||
minSkipAhead = 5000;
|
minSkipAhead = 5000;
|
||||||
realTime = 1000;
|
realTime = 1000;
|
||||||
|
lastRecv = Util::epoch();
|
||||||
if (myConn){
|
if (myConn){
|
||||||
setBlocking(true);
|
setBlocking(true);
|
||||||
}else{
|
}else{
|
||||||
|
@ -288,10 +296,19 @@ namespace Mist{
|
||||||
/// Finally, calls updateMeta()
|
/// Finally, calls updateMeta()
|
||||||
void Output::reconnect(){
|
void Output::reconnect(){
|
||||||
thisPacket.null();
|
thisPacket.null();
|
||||||
if (!Util::startInput(streamName)){
|
if (config->hasOption("noinput") && config->getBool("noinput")){
|
||||||
FAIL_MSG("Opening stream %s failed - aborting initialization", streamName.c_str());
|
Util::sanitizeName(streamName);
|
||||||
onFail();
|
if (!Util::streamAlive(streamName)){
|
||||||
return;
|
FAIL_MSG("Stream %s not already active - aborting initialization", streamName.c_str());
|
||||||
|
onFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if (!Util::startInput(streamName)){
|
||||||
|
FAIL_MSG("Opening stream %s failed - aborting initialization", streamName.c_str());
|
||||||
|
onFail();
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (statsPage.getData()){
|
if (statsPage.getData()){
|
||||||
statsPage.finish();
|
statsPage.finish();
|
||||||
|
@ -788,11 +805,17 @@ namespace Mist{
|
||||||
static bool firstData = true;//only the first time, we call onRequest if there's data buffered already.
|
static bool firstData = true;//only the first time, we call onRequest if there's data buffered already.
|
||||||
if ((firstData && myConn.Received().size()) || myConn.spool()){
|
if ((firstData && myConn.Received().size()) || myConn.spool()){
|
||||||
firstData = false;
|
firstData = false;
|
||||||
DEBUG_MSG(DLVL_DONTEVEN, "onRequest");
|
DONTEVEN_MSG("onRequest");
|
||||||
onRequest();
|
onRequest();
|
||||||
|
lastRecv = Util::epoch();
|
||||||
}else{
|
}else{
|
||||||
if (!isBlocking && !parseData){
|
if (!isBlocking && !parseData){
|
||||||
Util::sleep(500);
|
if (Util::epoch() - lastRecv > 300){
|
||||||
|
WARN_MSG("Disconnecting 5 minute idle connection");
|
||||||
|
myConn.close();
|
||||||
|
}else{
|
||||||
|
Util::sleep(500);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -99,6 +99,7 @@ namespace Mist {
|
||||||
std::map<unsigned long, unsigned long> nxtKeyNum;///< Contains the number of the next key, for page seeking purposes.
|
std::map<unsigned long, unsigned long> nxtKeyNum;///< Contains the number of the next key, for page seeking purposes.
|
||||||
std::set<sortedPageInfo> buffer;///< A sorted list of next-to-be-loaded packets.
|
std::set<sortedPageInfo> buffer;///< A sorted list of next-to-be-loaded packets.
|
||||||
bool sought;///<If a seek has been done, this is set to true. Used for seeking on prepareNext().
|
bool sought;///<If a seek has been done, this is set to true. Used for seeking on prepareNext().
|
||||||
|
uint64_t lastRecv;
|
||||||
protected://these are to be messed with by child classes
|
protected://these are to be messed with by child classes
|
||||||
virtual std::string getConnectedHost();
|
virtual std::string getConnectedHost();
|
||||||
virtual std::string getConnectedBinHost();
|
virtual std::string getConnectedBinHost();
|
||||||
|
|
|
@ -46,7 +46,7 @@ namespace Mist {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool OutJSON::onFinish(){
|
bool OutJSON::onFinish(){
|
||||||
if (!jsonp.size()){
|
if (!jsonp.size() && !first){
|
||||||
myConn.SendNow("]);\n\n", 5);
|
myConn.SendNow("]);\n\n", 5);
|
||||||
}
|
}
|
||||||
myConn.close();
|
myConn.close();
|
||||||
|
|
Loading…
Add table
Reference in a new issue