More backports from Pro edition, among which HTTPS/TLS support
This commit is contained in:
		
							parent
							
								
									2432bbdfc3
								
							
						
					
					
						commit
						cc9e970ea3
					
				
					 26 changed files with 733 additions and 324 deletions
				
			
		| 
						 | 
					@ -363,6 +363,9 @@ makeOutput(TS ts                    ts)
 | 
				
			||||||
makeOutput(HTTPTS httpts       http ts)
 | 
					makeOutput(HTTPTS httpts       http ts)
 | 
				
			||||||
makeOutput(HLS hls             http ts)
 | 
					makeOutput(HLS hls             http ts)
 | 
				
			||||||
makeOutput(EBML ebml)
 | 
					makeOutput(EBML ebml)
 | 
				
			||||||
 | 
					if (NOT DEFINED NOSSL )
 | 
				
			||||||
 | 
					  makeOutput(HTTPS https)#LTS
 | 
				
			||||||
 | 
					endif()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
add_executable(MistOutHTTP 
 | 
					add_executable(MistOutHTTP 
 | 
				
			||||||
  ${BINARY_DIR}/mist/.headers
 | 
					  ${BINARY_DIR}/mist/.headers
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -107,7 +107,7 @@ static inline void show_stackframe(){}
 | 
				
			||||||
#define STATS_INPUT_DELAY 2
 | 
					#define STATS_INPUT_DELAY 2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef INPUT_TIMEOUT
 | 
					#ifndef INPUT_TIMEOUT
 | 
				
			||||||
#define INPUT_TIMEOUT STATS_DELAY
 | 
					#define INPUT_TIMEOUT STATS_DELAY*2
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// The size used for stream headers for live streams
 | 
					/// The size used for stream headers for live streams
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -59,16 +59,10 @@ namespace HTTP{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// Returns a reference to the internal Socket::Connection class instance.
 | 
					  /// Returns a reference to the internal Socket::Connection class instance.
 | 
				
			||||||
  Socket::Connection &Downloader::getSocket(){
 | 
					  Socket::Connection &Downloader::getSocket(){
 | 
				
			||||||
#ifdef SSL
 | 
					 | 
				
			||||||
    if (ssl){return S_SSL;}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    return S;
 | 
					    return S;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  Downloader::~Downloader(){
 | 
					  Downloader::~Downloader(){
 | 
				
			||||||
#ifdef SSL
 | 
					 | 
				
			||||||
    if (ssl){S_SSL.close();}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    S.close();
 | 
					    S.close();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -87,12 +81,12 @@ namespace HTTP{
 | 
				
			||||||
        connectedPort = link.getPort();
 | 
					        connectedPort = link.getPort();
 | 
				
			||||||
#ifdef SSL
 | 
					#ifdef SSL
 | 
				
			||||||
        if (needSSL){
 | 
					        if (needSSL){
 | 
				
			||||||
          S_SSL = Socket::SSLConnection(connectedHost, connectedPort, true);
 | 
					          S.open(connectedHost, connectedPort, true, true);
 | 
				
			||||||
        }else{
 | 
					        }else{
 | 
				
			||||||
          S = Socket::Connection(connectedHost, connectedPort, true);
 | 
					          S.open(connectedHost, connectedPort, true);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
        S = Socket::Connection(connectedHost, connectedPort, true);
 | 
					        S.open(connectedHost, connectedPort, true);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
| 
						 | 
					@ -101,7 +95,7 @@ namespace HTTP{
 | 
				
			||||||
        getSocket().close();
 | 
					        getSocket().close();
 | 
				
			||||||
        connectedHost = proxyUrl.host;
 | 
					        connectedHost = proxyUrl.host;
 | 
				
			||||||
        connectedPort = proxyUrl.getPort();
 | 
					        connectedPort = proxyUrl.getPort();
 | 
				
			||||||
        S = Socket::Connection(connectedHost, connectedPort, true);
 | 
					        S.open(connectedHost, connectedPort, true);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    ssl = needSSL;
 | 
					    ssl = needSSL;
 | 
				
			||||||
| 
						 | 
					@ -218,8 +212,8 @@ namespace HTTP{
 | 
				
			||||||
      MEDIUM_MSG("Posting to %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1,
 | 
					      MEDIUM_MSG("Posting to %s (%zu/%" PRIu32 ")", link.getUrl().c_str(), retryCount - loop + 1,
 | 
				
			||||||
                 retryCount);
 | 
					                 retryCount);
 | 
				
			||||||
      doRequest(link, "POST", payload);
 | 
					      doRequest(link, "POST", payload);
 | 
				
			||||||
      // Not synced? Ignore the response and immediately return false.
 | 
					      // Not synced? Ignore the response and immediately return true.
 | 
				
			||||||
      if (!sync){return false;}
 | 
					      if (!sync){return true;}
 | 
				
			||||||
      uint64_t reqTime = Util::bootSecs();
 | 
					      uint64_t reqTime = Util::bootSecs();
 | 
				
			||||||
      while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){
 | 
					      while (getSocket() && Util::bootSecs() < reqTime + dataTimeout){
 | 
				
			||||||
        // No data? Wait for a second or so.
 | 
					        // No data? Wait for a second or so.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,9 +36,6 @@ namespace HTTP{
 | 
				
			||||||
    uint32_t connectedPort;                          ///< Currently connected port number
 | 
					    uint32_t connectedPort;                          ///< Currently connected port number
 | 
				
			||||||
    Parser H;                                        ///< HTTP parser for downloader
 | 
					    Parser H;                                        ///< HTTP parser for downloader
 | 
				
			||||||
    Socket::Connection S;                            ///< TCP socket for downloader
 | 
					    Socket::Connection S;                            ///< TCP socket for downloader
 | 
				
			||||||
#ifdef SSL
 | 
					 | 
				
			||||||
    Socket::SSLConnection S_SSL; ///< SSL socket for downloader
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    bool ssl;                 ///< True if ssl is currently in use.
 | 
					    bool ssl;                 ///< True if ssl is currently in use.
 | 
				
			||||||
    std::string authStr;      ///< Most recently seen WWW-Authenticate request
 | 
					    std::string authStr;      ///< Most recently seen WWW-Authenticate request
 | 
				
			||||||
    std::string proxyAuthStr; ///< Most recently seen Proxy-Authenticate request
 | 
					    std::string proxyAuthStr; ///< Most recently seen Proxy-Authenticate request
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1513,6 +1513,7 @@ namespace DTSC {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  void Meta::update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size){
 | 
					  void Meta::update(long long packTime, long long packOffset, long long packTrack, long long packDataSize, uint64_t packBytePos, bool isKeyframe, long long packSendSize, unsigned long segment_size){
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("Updating meta with: t=%lld, o=%lld, s=%lld, t=%lld, p=%lld", packTime, packOffset, packDataSize, packTrack, packBytePos);
 | 
				
			||||||
    if (!packSendSize){
 | 
					    if (!packSendSize){
 | 
				
			||||||
      //time and trackID are part of the 20-byte header.
 | 
					      //time and trackID are part of the 20-byte header.
 | 
				
			||||||
      //the container object adds 4 bytes (plus 2+namelen for each content, see below)
 | 
					      //the container object adds 4 bytes (plus 2+namelen for each content, see below)
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -150,6 +150,7 @@ uint32_t HTTP::URL::getDefaultPort() const{
 | 
				
			||||||
  if (protocol == "http"){return 80;}
 | 
					  if (protocol == "http"){return 80;}
 | 
				
			||||||
  if (protocol == "https"){return 443;}
 | 
					  if (protocol == "https"){return 443;}
 | 
				
			||||||
  if (protocol == "rtmp"){return 1935;}
 | 
					  if (protocol == "rtmp"){return 1935;}
 | 
				
			||||||
 | 
					  if (protocol == "rtmps"){return 443;}
 | 
				
			||||||
  if (protocol == "dtsc"){return 4200;}
 | 
					  if (protocol == "dtsc"){return 4200;}
 | 
				
			||||||
  if (protocol == "rtsp"){return 554;}
 | 
					  if (protocol == "rtsp"){return 554;}
 | 
				
			||||||
  return 0;
 | 
					  return 0;
 | 
				
			||||||
| 
						 | 
					@ -418,8 +419,29 @@ std::string &HTTP::Parser::BuildRequest(){
 | 
				
			||||||
/// Creates and sends a valid HTTP 1.0 or 1.1 request.
 | 
					/// Creates and sends a valid HTTP 1.0 or 1.1 request.
 | 
				
			||||||
/// The request is build from internal variables set before this call is made.
 | 
					/// The request is build from internal variables set before this call is made.
 | 
				
			||||||
/// To be precise, method, url, protocol, headers and body are used.
 | 
					/// To be precise, method, url, protocol, headers and body are used.
 | 
				
			||||||
void HTTP::Parser::SendRequest(Socket::Connection &conn, const std::string &reqbody){
 | 
					void HTTP::Parser::SendRequest(Socket::Connection &conn, const std::string &reqbody, bool allAtOnce){
 | 
				
			||||||
  /// \todo Include GET/POST variable parsing?
 | 
					  /// \todo Include GET/POST variable parsing?
 | 
				
			||||||
 | 
					  if (allAtOnce){
 | 
				
			||||||
 | 
					    /// \TODO Make this less duplicated / more pretty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::map<std::string, std::string>::iterator it;
 | 
				
			||||||
 | 
					    if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";}
 | 
				
			||||||
 | 
					    builder = method + " " + url + " " + protocol + "\r\n";
 | 
				
			||||||
 | 
					    if (reqbody.size()){SetHeader("Content-Length", reqbody.length());}
 | 
				
			||||||
 | 
					    for (it = headers.begin(); it != headers.end(); it++){
 | 
				
			||||||
 | 
					      if ((*it).first != "" && (*it).second != ""){
 | 
				
			||||||
 | 
					        builder += (*it).first + ": " + (*it).second + "\r\n";
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    builder += "\r\n";
 | 
				
			||||||
 | 
					    if (reqbody.size()){
 | 
				
			||||||
 | 
					      builder += reqbody;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					      builder += body;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    conn.SendNow(builder);
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  std::map<std::string, std::string>::iterator it;
 | 
					  std::map<std::string, std::string>::iterator it;
 | 
				
			||||||
  if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";}
 | 
					  if (protocol.size() < 5 || protocol[4] != '/'){protocol = "HTTP/1.0";}
 | 
				
			||||||
  builder = method + " " + url + " " + protocol + "\r\n";
 | 
					  builder = method + " " + url + " " + protocol + "\r\n";
 | 
				
			||||||
| 
						 | 
					@ -827,6 +849,10 @@ bool HTTP::Parser::parse(std::string &HTTPbuffer){
 | 
				
			||||||
            length = atoi(GetHeader("Content-Length").c_str());
 | 
					            length = atoi(GetHeader("Content-Length").c_str());
 | 
				
			||||||
            if (body.capacity() < length){body.reserve(length);}
 | 
					            if (body.capacity() < length){body.reserve(length);}
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					          if (GetHeader("Content-length") != ""){
 | 
				
			||||||
 | 
					            length = atoi(GetHeader("Content-length").c_str());
 | 
				
			||||||
 | 
					            if (body.capacity() < length){body.reserve(length);}
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          if (GetHeader("Transfer-Encoding") == "chunked"){
 | 
					          if (GetHeader("Transfer-Encoding") == "chunked"){
 | 
				
			||||||
            getChunks = true;
 | 
					            getChunks = true;
 | 
				
			||||||
            doingChunk = 0;
 | 
					            doingChunk = 0;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,7 +37,7 @@ namespace HTTP{
 | 
				
			||||||
    std::string &BuildRequest();
 | 
					    std::string &BuildRequest();
 | 
				
			||||||
    std::string &BuildResponse();
 | 
					    std::string &BuildResponse();
 | 
				
			||||||
    std::string &BuildResponse(std::string code, std::string message);
 | 
					    std::string &BuildResponse(std::string code, std::string message);
 | 
				
			||||||
    void SendRequest(Socket::Connection &conn, const std::string &reqbody = "");
 | 
					    void SendRequest(Socket::Connection &conn, const std::string &reqbody = "", bool allAtOnce = false);
 | 
				
			||||||
    void SendResponse(std::string code, std::string message, Socket::Connection &conn);
 | 
					    void SendResponse(std::string code, std::string message, Socket::Connection &conn);
 | 
				
			||||||
    void StartResponse(std::string code, std::string message, Parser &request,
 | 
					    void StartResponse(std::string code, std::string message, Parser &request,
 | 
				
			||||||
                       Socket::Connection &conn, bool bufferAllChunks = false);
 | 
					                       Socket::Connection &conn, bool bufferAllChunks = false);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										18
									
								
								lib/ogg.cpp
									
										
									
									
									
								
							
							
						
						
									
										18
									
								
								lib/ogg.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -107,6 +107,7 @@ namespace OGG {
 | 
				
			||||||
  /// Reads an OGG Page from the source and if valid, removes it from source.
 | 
					  /// Reads an OGG Page from the source and if valid, removes it from source.
 | 
				
			||||||
  bool Page::read(std::string & newData){
 | 
					  bool Page::read(std::string & newData){
 | 
				
			||||||
    int len = newData.size();
 | 
					    int len = newData.size();
 | 
				
			||||||
 | 
					    int total = 0;
 | 
				
			||||||
    segments.clear();
 | 
					    segments.clear();
 | 
				
			||||||
    if (newData.size() < 27){
 | 
					    if (newData.size() < 27){
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
| 
						 | 
					@ -119,14 +120,25 @@ namespace OGG {
 | 
				
			||||||
    if (newData.size() < 27u + getPageSegments()){ //check input size
 | 
					    if (newData.size() < 27u + getPageSegments()){ //check input size
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    newData.erase(0, 27);
 | 
					    memcpy(data + 27, newData.data()+27, getPageSegments());
 | 
				
			||||||
    memcpy(data + 27, newData.c_str(), getPageSegments());
 | 
					 | 
				
			||||||
    newData.erase(0, getPageSegments());
 | 
					 | 
				
			||||||
    std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments());
 | 
					    std::deque<unsigned int> segSizes = decodeXiphSize(data + 27, getPageSegments());
 | 
				
			||||||
 | 
					    for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
 | 
				
			||||||
 | 
					      total += *it;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    total += 27;
 | 
				
			||||||
 | 
					    //return false if the segment is not complete
 | 
				
			||||||
 | 
					    total += getPageSegments();
 | 
				
			||||||
 | 
					    if(total >= len){
 | 
				
			||||||
 | 
					      return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    newData.erase(0, getPageSegments()+27);
 | 
				
			||||||
    for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
 | 
					    for (std::deque<unsigned int>::iterator it = segSizes.begin(); it != segSizes.end(); it++){
 | 
				
			||||||
      segments.push_back(std::string(newData.data(), *it));
 | 
					      segments.push_back(std::string(newData.data(), *it));
 | 
				
			||||||
      newData.erase(0, *it);
 | 
					      newData.erase(0, *it);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    INFO_MSG("Erased %lu bytes from the input", len - newData.size());
 | 
					    INFO_MSG("Erased %lu bytes from the input", len - newData.size());
 | 
				
			||||||
    return true;
 | 
					    return true;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -100,30 +100,29 @@ void Util::Procs::exit_handler() {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  WARN_MSG("Sending SIGINT to remaining %d children", (int)listcopy.size());
 | 
					  INFO_MSG("Sending SIGINT and waiting up to 10 seconds for %d children to terminate.", (int)listcopy.size());
 | 
				
			||||||
  //send sigint to all remaining
 | 
					 | 
				
			||||||
  if (!listcopy.empty()) {
 | 
					 | 
				
			||||||
    for (it = listcopy.begin(); it != listcopy.end(); it++) {
 | 
					 | 
				
			||||||
      DEBUG_MSG(DLVL_DEVEL, "SIGINT %d", *it);
 | 
					 | 
				
			||||||
      kill(*it, SIGINT);
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  INFO_MSG("Waiting up to 5 seconds for %d children to terminate.", (int)listcopy.size());
 | 
					 | 
				
			||||||
  waiting = 0;
 | 
					  waiting = 0;
 | 
				
			||||||
  //wait up to 5 seconds for applications to shut down
 | 
					  //wait up to 10 seconds for applications to shut down
 | 
				
			||||||
  while (!listcopy.empty() && waiting <= 250) {
 | 
					  while (!listcopy.empty() && waiting <= 500) {
 | 
				
			||||||
 | 
					    bool doWait = true;
 | 
				
			||||||
    for (it = listcopy.begin(); it != listcopy.end(); it++) {
 | 
					    for (it = listcopy.begin(); it != listcopy.end(); it++) {
 | 
				
			||||||
      if (!childRunning(*it)) {
 | 
					      if (!childRunning(*it)) {
 | 
				
			||||||
        listcopy.erase(it);
 | 
					        listcopy.erase(it);
 | 
				
			||||||
 | 
					        doWait = false;
 | 
				
			||||||
        break;
 | 
					        break;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      if (!listcopy.empty()) {
 | 
					    }
 | 
				
			||||||
 | 
					    if (doWait && !listcopy.empty()) {
 | 
				
			||||||
 | 
					      if ((waiting % 50) == 0){
 | 
				
			||||||
 | 
					        for (it = listcopy.begin(); it != listcopy.end(); it++) {
 | 
				
			||||||
 | 
					          INFO_MSG("SIGINT %d", *it);
 | 
				
			||||||
 | 
					          kill(*it, SIGINT);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
        Util::wait(20);
 | 
					        Util::wait(20);
 | 
				
			||||||
        ++waiting;
 | 
					        ++waiting;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (listcopy.empty()) {
 | 
					  if (listcopy.empty()) {
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1192,8 +1192,6 @@ namespace IPC {
 | 
				
			||||||
  ///\brief The deconstructor
 | 
					  ///\brief The deconstructor
 | 
				
			||||||
  sharedClient::~sharedClient() {
 | 
					  sharedClient::~sharedClient() {
 | 
				
			||||||
    mySemaphore.close();
 | 
					    mySemaphore.close();
 | 
				
			||||||
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ///\brief Writes data to the shared data
 | 
					  ///\brief Writes data to the shared data
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										544
									
								
								lib/socket.cpp
									
										
									
									
									
								
							
							
						
						
									
										544
									
								
								lib/socket.cpp
									
										
									
									
									
								
							| 
						 | 
					@ -402,25 +402,40 @@ void Socket::Connection::setBoundAddr(){
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Cleans up the socket by dropping the connection.
 | 
				
			||||||
 | 
					//Does not call close because it calls shutdown, which would destroy any copies of this socket too.
 | 
				
			||||||
 | 
					Socket::Connection::~Connection(){
 | 
				
			||||||
 | 
					  drop();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create a new base socket. This is a basic constructor for converting any valid socket to a
 | 
					/// Create a new base socket. This is a basic constructor for converting any valid socket to a
 | 
				
			||||||
/// Socket::Connection. \param sockNo Integer representing the socket to convert.
 | 
					/// Socket::Connection. \param sockNo Integer representing the socket to convert.
 | 
				
			||||||
Socket::Connection::Connection(int sockNo){
 | 
					Socket::Connection::Connection(int sockNo){
 | 
				
			||||||
  sSend = sockNo;
 | 
					  clear();
 | 
				
			||||||
  sRecv = -1;
 | 
					  open(sockNo, sockNo);
 | 
				
			||||||
  isTrueSocket = Socket::checkTrueSocket(sSend);
 | 
					 | 
				
			||||||
  setBoundAddr();
 | 
					 | 
				
			||||||
  up = 0;
 | 
					 | 
				
			||||||
  down = 0;
 | 
					 | 
				
			||||||
  conntime = Util::epoch();
 | 
					 | 
				
			||||||
  Error = false;
 | 
					 | 
				
			||||||
  Blocking = false;
 | 
					 | 
				
			||||||
  skipCount = 0;
 | 
					 | 
				
			||||||
}// Socket::Connection basic constructor
 | 
					}// Socket::Connection basic constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Open from existing socket connection.
 | 
				
			||||||
 | 
					/// Closes any existing connections and resets all internal values beforehand.
 | 
				
			||||||
 | 
					/// Simply calls open(sockNo, sockNo) internally.
 | 
				
			||||||
 | 
					void Socket::Connection::open(int sockNo){
 | 
				
			||||||
 | 
					  open(sockNo, sockNo);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Simulate a socket using two file descriptors.
 | 
					/// Simulate a socket using two file descriptors.
 | 
				
			||||||
/// \param write The filedescriptor to write to.
 | 
					/// \param write The filedescriptor to write to.
 | 
				
			||||||
/// \param read The filedescriptor to read from.
 | 
					/// \param read The filedescriptor to read from.
 | 
				
			||||||
Socket::Connection::Connection(int write, int read){
 | 
					Socket::Connection::Connection(int write, int read){
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
 | 
					  open(write, read);
 | 
				
			||||||
 | 
					}// Socket::Connection basic constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Open from two existing file descriptors.
 | 
				
			||||||
 | 
					/// Closes any existing connections and resets all internal values beforehand.
 | 
				
			||||||
 | 
					void Socket::Connection::open(int write, int read){
 | 
				
			||||||
 | 
					  drop();
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
  sSend = write;
 | 
					  sSend = write;
 | 
				
			||||||
  if (write != read){
 | 
					  if (write != read){
 | 
				
			||||||
    sRecv = read;
 | 
					    sRecv = read;
 | 
				
			||||||
| 
						 | 
					@ -429,17 +444,9 @@ Socket::Connection::Connection(int write, int read){
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  isTrueSocket = Socket::checkTrueSocket(sSend);
 | 
					  isTrueSocket = Socket::checkTrueSocket(sSend);
 | 
				
			||||||
  setBoundAddr();
 | 
					  setBoundAddr();
 | 
				
			||||||
  up = 0;
 | 
					}
 | 
				
			||||||
  down = 0;
 | 
					 | 
				
			||||||
  conntime = Util::epoch();
 | 
					 | 
				
			||||||
  Error = false;
 | 
					 | 
				
			||||||
  Blocking = false;
 | 
					 | 
				
			||||||
  skipCount = 0;
 | 
					 | 
				
			||||||
}// Socket::Connection basic constructor
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create a new disconnected base socket. This is a basic constructor for placeholder purposes.
 | 
					void Socket::Connection::clear(){
 | 
				
			||||||
/// A socket created like this is always disconnected and should/could be overwritten at some point.
 | 
					 | 
				
			||||||
Socket::Connection::Connection(){
 | 
					 | 
				
			||||||
  sSend = -1;
 | 
					  sSend = -1;
 | 
				
			||||||
  sRecv = -1;
 | 
					  sRecv = -1;
 | 
				
			||||||
  isTrueSocket = false;
 | 
					  isTrueSocket = false;
 | 
				
			||||||
| 
						 | 
					@ -449,6 +456,20 @@ Socket::Connection::Connection(){
 | 
				
			||||||
  Error = false;
 | 
					  Error = false;
 | 
				
			||||||
  Blocking = false;
 | 
					  Blocking = false;
 | 
				
			||||||
  skipCount = 0;
 | 
					  skipCount = 0;
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  sslConnected = false;
 | 
				
			||||||
 | 
					  server_fd = 0;
 | 
				
			||||||
 | 
					  ssl = 0;
 | 
				
			||||||
 | 
					  conf = 0;
 | 
				
			||||||
 | 
					  ctr_drbg = 0;
 | 
				
			||||||
 | 
					  entropy = 0;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Create a new disconnected base socket. This is a basic constructor for placeholder purposes.
 | 
				
			||||||
 | 
					/// A socket created like this is always disconnected and should/could be overwritten at some point.
 | 
				
			||||||
 | 
					Socket::Connection::Connection(){
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
}// Socket::Connection basic constructor
 | 
					}// Socket::Connection basic constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
void Socket::Connection::resetCounter(){
 | 
					void Socket::Connection::resetCounter(){
 | 
				
			||||||
| 
						 | 
					@ -483,12 +504,28 @@ bool isFDBlocking(int FD){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Set this socket to be blocking (true) or nonblocking (false).
 | 
					/// Set this socket to be blocking (true) or nonblocking (false).
 | 
				
			||||||
void Socket::Connection::setBlocking(bool blocking){
 | 
					void Socket::Connection::setBlocking(bool blocking){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){
 | 
				
			||||||
 | 
					    if (blocking == Blocking){return;}
 | 
				
			||||||
 | 
					    if (blocking){
 | 
				
			||||||
 | 
					      mbedtls_net_set_block(server_fd);
 | 
				
			||||||
 | 
					      Blocking = true;
 | 
				
			||||||
 | 
					    }else{
 | 
				
			||||||
 | 
					      mbedtls_net_set_nonblock(server_fd);
 | 
				
			||||||
 | 
					      Blocking = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  if (sSend >= 0){setFDBlocking(sSend, blocking);}
 | 
					  if (sSend >= 0){setFDBlocking(sSend, blocking);}
 | 
				
			||||||
  if (sRecv >= 0 && sSend != sRecv){setFDBlocking(sRecv, blocking);}
 | 
					  if (sRecv >= 0 && sSend != sRecv){setFDBlocking(sRecv, blocking);}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Set this socket to be blocking (true) or nonblocking (false).
 | 
					/// Set this socket to be blocking (true) or nonblocking (false).
 | 
				
			||||||
bool Socket::Connection::isBlocking(){
 | 
					bool Socket::Connection::isBlocking(){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){return Blocking;}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  if (sSend >= 0){return isFDBlocking(sSend);}
 | 
					  if (sSend >= 0){return isFDBlocking(sSend);}
 | 
				
			||||||
  if (sRecv >= 0){return isFDBlocking(sRecv);}
 | 
					  if (sRecv >= 0){return isFDBlocking(sRecv);}
 | 
				
			||||||
  return false;
 | 
					  return false;
 | 
				
			||||||
| 
						 | 
					@ -508,6 +545,41 @@ void Socket::Connection::close(){
 | 
				
			||||||
/// This function does *not* call shutdown, allowing continued use in other
 | 
					/// This function does *not* call shutdown, allowing continued use in other
 | 
				
			||||||
/// processes.
 | 
					/// processes.
 | 
				
			||||||
void Socket::Connection::drop(){
 | 
					void Socket::Connection::drop(){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL close");
 | 
				
			||||||
 | 
					    if (ssl){
 | 
				
			||||||
 | 
					      mbedtls_ssl_close_notify(ssl);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (server_fd){
 | 
				
			||||||
 | 
					      mbedtls_net_free(server_fd);
 | 
				
			||||||
 | 
					      delete server_fd;
 | 
				
			||||||
 | 
					      server_fd = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ssl){
 | 
				
			||||||
 | 
					      mbedtls_ssl_free(ssl);
 | 
				
			||||||
 | 
					      delete ssl;
 | 
				
			||||||
 | 
					      ssl = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (conf){
 | 
				
			||||||
 | 
					      mbedtls_ssl_config_free(conf);
 | 
				
			||||||
 | 
					      delete conf;
 | 
				
			||||||
 | 
					      conf = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (ctr_drbg){
 | 
				
			||||||
 | 
					      mbedtls_ctr_drbg_free(ctr_drbg);
 | 
				
			||||||
 | 
					      delete ctr_drbg;
 | 
				
			||||||
 | 
					      ctr_drbg = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (entropy){
 | 
				
			||||||
 | 
					      mbedtls_entropy_free(entropy);
 | 
				
			||||||
 | 
					      delete entropy;
 | 
				
			||||||
 | 
					      entropy = 0;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sslConnected = false;
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  if (connected()){
 | 
					  if (connected()){
 | 
				
			||||||
    if (sSend != -1){
 | 
					    if (sSend != -1){
 | 
				
			||||||
      HIGH_MSG("Socket %d closed", sSend);
 | 
					      HIGH_MSG("Socket %d closed", sSend);
 | 
				
			||||||
| 
						 | 
					@ -547,8 +619,15 @@ std::string Socket::Connection::getError(){
 | 
				
			||||||
/// \param address String containing the location of the Unix socket to connect to.
 | 
					/// \param address String containing the location of the Unix socket to connect to.
 | 
				
			||||||
/// \param nonblock Whether the socket should be nonblocking. False by default.
 | 
					/// \param nonblock Whether the socket should be nonblocking. False by default.
 | 
				
			||||||
Socket::Connection::Connection(std::string address, bool nonblock){
 | 
					Socket::Connection::Connection(std::string address, bool nonblock){
 | 
				
			||||||
  skipCount = 0;
 | 
					  clear();
 | 
				
			||||||
  sRecv = -1;
 | 
					  open(address, nonblock);
 | 
				
			||||||
 | 
					}// Socket::Connection Unix Constructor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Open Unix connection.
 | 
				
			||||||
 | 
					/// Closes any existing connections and resets all internal values beforehand.
 | 
				
			||||||
 | 
					void Socket::Connection::open(std::string address, bool nonblock){
 | 
				
			||||||
 | 
					  drop();
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
  isTrueSocket = true;
 | 
					  isTrueSocket = true;
 | 
				
			||||||
  sSend = socket(PF_UNIX, SOCK_STREAM, 0);
 | 
					  sSend = socket(PF_UNIX, SOCK_STREAM, 0);
 | 
				
			||||||
  if (sSend < 0){
 | 
					  if (sSend < 0){
 | 
				
			||||||
| 
						 | 
					@ -556,11 +635,6 @@ Socket::Connection::Connection(std::string address, bool nonblock){
 | 
				
			||||||
    FAIL_MSG("Could not create socket! Error: %s", remotehost.c_str());
 | 
					    FAIL_MSG("Could not create socket! Error: %s", remotehost.c_str());
 | 
				
			||||||
    return;
 | 
					    return;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
  Error = false;
 | 
					 | 
				
			||||||
  Blocking = false;
 | 
					 | 
				
			||||||
  up = 0;
 | 
					 | 
				
			||||||
  down = 0;
 | 
					 | 
				
			||||||
  conntime = Util::epoch();
 | 
					 | 
				
			||||||
  sockaddr_un addr;
 | 
					  sockaddr_un addr;
 | 
				
			||||||
  addr.sun_family = AF_UNIX;
 | 
					  addr.sun_family = AF_UNIX;
 | 
				
			||||||
  strncpy(addr.sun_path, address.c_str(), address.size() + 1);
 | 
					  strncpy(addr.sun_path, address.c_str(), address.size() + 1);
 | 
				
			||||||
| 
						 | 
					@ -576,22 +650,100 @@ Socket::Connection::Connection(std::string address, bool nonblock){
 | 
				
			||||||
    FAIL_MSG("Could not connect to %s! Error: %s", address.c_str(), remotehost.c_str());
 | 
					    FAIL_MSG("Could not connect to %s! Error: %s", address.c_str(), remotehost.c_str());
 | 
				
			||||||
    close();
 | 
					    close();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}// Socket::Connection Unix Constructor
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					///Local-only function for debugging SSL sockets
 | 
				
			||||||
 | 
					static void my_debug(void *ctx, int level, const char *file, int line, const char *str){
 | 
				
			||||||
 | 
					  ((void)level);
 | 
				
			||||||
 | 
					  fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str);
 | 
				
			||||||
 | 
					  fflush((FILE *)ctx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create a new TCP Socket. This socket will (try to) connect to the given host/port right away.
 | 
					/// Create a new TCP Socket. This socket will (try to) connect to the given host/port right away.
 | 
				
			||||||
/// \param host String containing the hostname to connect to.
 | 
					/// \param host String containing the hostname to connect to.
 | 
				
			||||||
/// \param port String containing the port to connect to.
 | 
					/// \param port String containing the port to connect to.
 | 
				
			||||||
/// \param nonblock Whether the socket should be nonblocking.
 | 
					/// \param nonblock Whether the socket should be nonblocking.
 | 
				
			||||||
Socket::Connection::Connection(std::string host, int port, bool nonblock){
 | 
					Socket::Connection::Connection(std::string host, int port, bool nonblock, bool with_ssl){
 | 
				
			||||||
  skipCount = 0;
 | 
					  clear();
 | 
				
			||||||
  sRecv = -1;
 | 
					  open(host, port, nonblock, with_ssl);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/// Open TCP connection.
 | 
				
			||||||
 | 
					/// Closes any existing connections and resets all internal values beforehand.
 | 
				
			||||||
 | 
					void Socket::Connection::open(std::string host, int port, bool nonblock, bool with_ssl){
 | 
				
			||||||
 | 
					  drop();
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
 | 
					  if (with_ssl){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					    mbedtls_debug_set_threshold(0);
 | 
				
			||||||
 | 
					    server_fd = new mbedtls_net_context;
 | 
				
			||||||
 | 
					    ssl = new mbedtls_ssl_context;
 | 
				
			||||||
 | 
					    conf = new mbedtls_ssl_config;
 | 
				
			||||||
 | 
					    ctr_drbg = new mbedtls_ctr_drbg_context;
 | 
				
			||||||
 | 
					    entropy = new mbedtls_entropy_context;
 | 
				
			||||||
 | 
					    mbedtls_net_init(server_fd);
 | 
				
			||||||
 | 
					    mbedtls_ssl_init(ssl);
 | 
				
			||||||
 | 
					    mbedtls_ssl_config_init(conf);
 | 
				
			||||||
 | 
					    mbedtls_ctr_drbg_init(ctr_drbg);
 | 
				
			||||||
 | 
					    mbedtls_entropy_init(entropy);
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL init");
 | 
				
			||||||
 | 
					    if (mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)"meow",
 | 
				
			||||||
 | 
					                              4) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("SSL socket init failed");
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL connect");
 | 
				
			||||||
 | 
					    int ret = 0;
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_net_connect(server_fd, host.c_str(), JSON::Value(port).asString().c_str(), MBEDTLS_NET_PROTO_TCP)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG(" failed\n  ! mbedtls_net_connect returned %d\n\n", ret);
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
 | 
				
			||||||
 | 
					                                           MBEDTLS_SSL_PRESET_DEFAULT)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG(" failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
 | 
				
			||||||
 | 
					    mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, ctr_drbg);
 | 
				
			||||||
 | 
					    mbedtls_ssl_conf_dbg(conf, my_debug, stderr);
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0){
 | 
				
			||||||
 | 
					      char estr[200];
 | 
				
			||||||
 | 
					      mbedtls_strerror(ret, estr, 200);
 | 
				
			||||||
 | 
					      FAIL_MSG("SSL setup error %d: %s", ret, estr);
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_set_hostname(ssl, host.c_str())) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mbedtls_ssl_set_bio(ssl, server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
 | 
				
			||||||
 | 
					    while ((ret = mbedtls_ssl_handshake(ssl)) != 0){
 | 
				
			||||||
 | 
					      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
 | 
				
			||||||
 | 
					        char estr[200];
 | 
				
			||||||
 | 
					        mbedtls_strerror(ret, estr, 200);
 | 
				
			||||||
 | 
					        FAIL_MSG("SSL handshake error %d: %s", ret, estr);
 | 
				
			||||||
 | 
					        close();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    sslConnected = true;
 | 
				
			||||||
 | 
					    Blocking = true;
 | 
				
			||||||
 | 
					    if (nonblock){setBlocking(false);}
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL connect success");
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					    FAIL_MSG("Attempted to open SSL socket without SSL support compiled in!");
 | 
				
			||||||
 | 
					    return;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
  isTrueSocket = true;
 | 
					  isTrueSocket = true;
 | 
				
			||||||
  struct addrinfo *result, *rp, hints;
 | 
					  struct addrinfo *result, *rp, hints;
 | 
				
			||||||
  Error = false;
 | 
					 | 
				
			||||||
  Blocking = false;
 | 
					 | 
				
			||||||
  up = 0;
 | 
					 | 
				
			||||||
  down = 0;
 | 
					 | 
				
			||||||
  conntime = Util::epoch();
 | 
					 | 
				
			||||||
  std::stringstream ss;
 | 
					  std::stringstream ss;
 | 
				
			||||||
  ss << port;
 | 
					  ss << port;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -630,7 +782,7 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
 | 
				
			||||||
    setsockopt(sSend, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
 | 
					    setsockopt(sSend, SOL_SOCKET, SO_KEEPALIVE, &optval, optlen);
 | 
				
			||||||
    setBoundAddr();
 | 
					    setBoundAddr();
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}// Socket::Connection TCP Constructor
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Returns the connected-state for this socket.
 | 
					/// Returns the connected-state for this socket.
 | 
				
			||||||
/// Note that this function might be slightly behind the real situation.
 | 
					/// Note that this function might be slightly behind the real situation.
 | 
				
			||||||
| 
						 | 
					@ -638,6 +790,9 @@ Socket::Connection::Connection(std::string host, int port, bool nonblock){
 | 
				
			||||||
/// and when the socket is closed manually.
 | 
					/// and when the socket is closed manually.
 | 
				
			||||||
/// \returns True if socket is connected, false otherwise.
 | 
					/// \returns True if socket is connected, false otherwise.
 | 
				
			||||||
bool Socket::Connection::connected() const{
 | 
					bool Socket::Connection::connected() const{
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){return true;}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  return (sSend >= 0) || (sRecv >= 0);
 | 
					  return (sSend >= 0) || (sRecv >= 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -721,6 +876,38 @@ void Socket::Connection::skipBytes(uint32_t byteCount){
 | 
				
			||||||
/// \param len Amount of bytes to write.
 | 
					/// \param len Amount of bytes to write.
 | 
				
			||||||
/// \returns The amount of bytes actually written.
 | 
					/// \returns The amount of bytes actually written.
 | 
				
			||||||
unsigned int Socket::Connection::iwrite(const void *buffer, int len){
 | 
					unsigned int Socket::Connection::iwrite(const void *buffer, int len){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL iwrite");
 | 
				
			||||||
 | 
					    if (!connected() || len < 1){return 0;}
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					    r = mbedtls_ssl_write(ssl, (const unsigned char *)buffer, len);
 | 
				
			||||||
 | 
					    if (r < 0){
 | 
				
			||||||
 | 
					      char estr[200];
 | 
				
			||||||
 | 
					      mbedtls_strerror(r, estr, 200);
 | 
				
			||||||
 | 
					      INFO_MSG("Write returns %d: %s", r, estr);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (r < 0){
 | 
				
			||||||
 | 
					      switch (errno){
 | 
				
			||||||
 | 
					      case MBEDTLS_ERR_SSL_WANT_WRITE: return 0; break;
 | 
				
			||||||
 | 
					      case MBEDTLS_ERR_SSL_WANT_READ: return 0; break;
 | 
				
			||||||
 | 
					      case EWOULDBLOCK: return 0; break;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        Error = true;
 | 
				
			||||||
 | 
					        INSANE_MSG("Could not iwrite data! Error: %s", strerror(errno));
 | 
				
			||||||
 | 
					        close();
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (r == 0 && (sSend >= 0)){
 | 
				
			||||||
 | 
					      DONTEVEN_MSG("Socket closed by remote");
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    up += r;
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  if (!connected() || len < 1){return 0;}
 | 
					  if (!connected() || len < 1){return 0;}
 | 
				
			||||||
  if (skipCount){
 | 
					  if (skipCount){
 | 
				
			||||||
    // We have bytes to skip writing.
 | 
					    // We have bytes to skip writing.
 | 
				
			||||||
| 
						 | 
					@ -766,6 +953,38 @@ unsigned int Socket::Connection::iwrite(const void *buffer, int len){
 | 
				
			||||||
/// \param flags Flags to use in the recv call. Ignored on fake sockets.
 | 
					/// \param flags Flags to use in the recv call. Ignored on fake sockets.
 | 
				
			||||||
/// \returns The amount of bytes actually read.
 | 
					/// \returns The amount of bytes actually read.
 | 
				
			||||||
int Socket::Connection::iread(void *buffer, int len, int flags){
 | 
					int Socket::Connection::iread(void *buffer, int len, int flags){
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  if (sslConnected){
 | 
				
			||||||
 | 
					    DONTEVEN_MSG("SSL iread");
 | 
				
			||||||
 | 
					    if (!connected() || len < 1){return 0;}
 | 
				
			||||||
 | 
					    int r;
 | 
				
			||||||
 | 
					    /// \TODO Flags ignored... Bad.
 | 
				
			||||||
 | 
					    r = mbedtls_ssl_read(ssl, (unsigned char *)buffer, len);
 | 
				
			||||||
 | 
					    if (r < 0){
 | 
				
			||||||
 | 
					      switch (errno){
 | 
				
			||||||
 | 
					      case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: close(); return 0; break;
 | 
				
			||||||
 | 
					      case MBEDTLS_ERR_SSL_WANT_WRITE: return 0; break;
 | 
				
			||||||
 | 
					      case MBEDTLS_ERR_SSL_WANT_READ: return 0; break;
 | 
				
			||||||
 | 
					      case EWOULDBLOCK: return 0; break;
 | 
				
			||||||
 | 
					      case EINTR: return 0; break;
 | 
				
			||||||
 | 
					      default:
 | 
				
			||||||
 | 
					        Error = true;
 | 
				
			||||||
 | 
					        char estr[200];
 | 
				
			||||||
 | 
					        mbedtls_strerror(r, estr, 200);
 | 
				
			||||||
 | 
					        INFO_MSG("Read returns %d: %s (%s)", r, estr, strerror(errno));
 | 
				
			||||||
 | 
					        close();
 | 
				
			||||||
 | 
					        return 0;
 | 
				
			||||||
 | 
					        break;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (r == 0){
 | 
				
			||||||
 | 
					      DONTEVEN_MSG("Socket closed by remote");
 | 
				
			||||||
 | 
					      close();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    down += r;
 | 
				
			||||||
 | 
					    return r;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
  if (!connected() || len < 1){return 0;}
 | 
					  if (!connected() || len < 1){return 0;}
 | 
				
			||||||
  int r;
 | 
					  int r;
 | 
				
			||||||
  if (sRecv != -1 || !isTrueSocket){
 | 
					  if (sRecv != -1 || !isTrueSocket){
 | 
				
			||||||
| 
						 | 
					@ -873,6 +1092,56 @@ Socket::Connection::operator bool() const{
 | 
				
			||||||
  return connected();
 | 
					  return connected();
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Copy constructor
 | 
				
			||||||
 | 
					Socket::Connection::Connection(const Connection& rhs){
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
 | 
					  if (!rhs){return;}
 | 
				
			||||||
 | 
					#if DEBUG >= DLVL_DEVEL
 | 
				
			||||||
 | 
					  INFO_MSG("Copying %s socket", rhs.sslConnected?"SSL":"regular");
 | 
				
			||||||
 | 
					  BACKTRACE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  conntime = rhs.conntime;
 | 
				
			||||||
 | 
					  isTrueSocket = rhs.isTrueSocket;
 | 
				
			||||||
 | 
					  remotehost = rhs.remotehost;
 | 
				
			||||||
 | 
					  boundaddr = rhs.boundaddr;
 | 
				
			||||||
 | 
					  up = rhs.up;
 | 
				
			||||||
 | 
					  down = rhs.down;
 | 
				
			||||||
 | 
					  downbuffer = rhs.downbuffer;
 | 
				
			||||||
 | 
					  if (!rhs.sslConnected){
 | 
				
			||||||
 | 
					    if (rhs.sSend >= 0){sSend = dup(rhs.sSend);}
 | 
				
			||||||
 | 
					    if (rhs.sRecv >= 0){sRecv = dup(rhs.sRecv);}
 | 
				
			||||||
 | 
					#if DEBUG >= DLVL_DEVEL
 | 
				
			||||||
 | 
					    INFO_MSG("Socket original = (%d / %d), copy = (%d / %d)", rhs.sSend, rhs.sRecv, sSend, sRecv);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//Assignment constructor
 | 
				
			||||||
 | 
					Socket::Connection& Socket::Connection::operator=(const Socket::Connection& rhs){
 | 
				
			||||||
 | 
					  drop();
 | 
				
			||||||
 | 
					  clear();
 | 
				
			||||||
 | 
					  if (!rhs){return *this;}
 | 
				
			||||||
 | 
					#if DEBUG >= DLVL_DEVEL
 | 
				
			||||||
 | 
					  INFO_MSG("Assigning %s socket", rhs.sslConnected?"SSL":"regular");
 | 
				
			||||||
 | 
					  BACKTRACE;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  conntime = rhs.conntime;
 | 
				
			||||||
 | 
					  isTrueSocket = rhs.isTrueSocket;
 | 
				
			||||||
 | 
					  remotehost = rhs.remotehost;
 | 
				
			||||||
 | 
					  boundaddr = rhs.boundaddr;
 | 
				
			||||||
 | 
					  up = rhs.up;
 | 
				
			||||||
 | 
					  down = rhs.down;
 | 
				
			||||||
 | 
					  downbuffer = rhs.downbuffer;
 | 
				
			||||||
 | 
					  if (!rhs.sslConnected){
 | 
				
			||||||
 | 
					    if (rhs.sSend >= 0){sSend = dup(rhs.sSend);}
 | 
				
			||||||
 | 
					    if (rhs.sRecv >= 0){sRecv = dup(rhs.sRecv);}
 | 
				
			||||||
 | 
					#if DEBUG >= DLVL_DEVEL
 | 
				
			||||||
 | 
					    INFO_MSG("Socket original = (%d / %d), copy = (%d / %d)", rhs.sSend, rhs.sRecv, sSend, sRecv);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  return *this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Returns true if the given address can be matched with the remote host.
 | 
					/// Returns true if the given address can be matched with the remote host.
 | 
				
			||||||
/// Can no longer return true after any socket error have occurred.
 | 
					/// Can no longer return true after any socket error have occurred.
 | 
				
			||||||
bool Socket::Connection::isAddress(const std::string &addr){
 | 
					bool Socket::Connection::isAddress(const std::string &addr){
 | 
				
			||||||
| 
						 | 
					@ -885,207 +1154,6 @@ bool Socket::Connection::isLocal(){
 | 
				
			||||||
  return Socket::isLocal(remotehost);
 | 
					  return Socket::isLocal(remotehost);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SSL
 | 
					 | 
				
			||||||
Socket::SSLConnection::SSLConnection() : Socket::Connection::Connection(){
 | 
					 | 
				
			||||||
  isConnected = false;
 | 
					 | 
				
			||||||
  server_fd = 0;
 | 
					 | 
				
			||||||
  ssl = 0;
 | 
					 | 
				
			||||||
  conf = 0;
 | 
					 | 
				
			||||||
  ctr_drbg = 0;
 | 
					 | 
				
			||||||
  entropy = 0;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static void my_debug(void *ctx, int level, const char *file, int line, const char *str){
 | 
					 | 
				
			||||||
  ((void)level);
 | 
					 | 
				
			||||||
  fprintf((FILE *)ctx, "%s:%04d: %s", file, line, str);
 | 
					 | 
				
			||||||
  fflush((FILE *)ctx);
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
Socket::SSLConnection::SSLConnection(std::string hostname, int port, bool nonblock)
 | 
					 | 
				
			||||||
    : Socket::Connection(){
 | 
					 | 
				
			||||||
  mbedtls_debug_set_threshold(0);
 | 
					 | 
				
			||||||
  isConnected = true;
 | 
					 | 
				
			||||||
  server_fd = new mbedtls_net_context;
 | 
					 | 
				
			||||||
  ssl = new mbedtls_ssl_context;
 | 
					 | 
				
			||||||
  conf = new mbedtls_ssl_config;
 | 
					 | 
				
			||||||
  ctr_drbg = new mbedtls_ctr_drbg_context;
 | 
					 | 
				
			||||||
  entropy = new mbedtls_entropy_context;
 | 
					 | 
				
			||||||
  mbedtls_net_init(server_fd);
 | 
					 | 
				
			||||||
  mbedtls_ssl_init(ssl);
 | 
					 | 
				
			||||||
  mbedtls_ssl_config_init(conf);
 | 
					 | 
				
			||||||
  mbedtls_ctr_drbg_init(ctr_drbg);
 | 
					 | 
				
			||||||
  mbedtls_entropy_init(entropy);
 | 
					 | 
				
			||||||
  DONTEVEN_MSG("SSL init");
 | 
					 | 
				
			||||||
  if (mbedtls_ctr_drbg_seed(ctr_drbg, mbedtls_entropy_func, entropy, (const unsigned char *)"meow",
 | 
					 | 
				
			||||||
                            4) != 0){
 | 
					 | 
				
			||||||
    FAIL_MSG("SSL socket init failed");
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  DONTEVEN_MSG("SSL connect");
 | 
					 | 
				
			||||||
  int ret = 0;
 | 
					 | 
				
			||||||
  if ((ret = mbedtls_net_connect(server_fd, hostname.c_str(), JSON::Value(port).asString().c_str(), MBEDTLS_NET_PROTO_TCP)) != 0){
 | 
					 | 
				
			||||||
    FAIL_MSG(" failed\n  ! mbedtls_net_connect returned %d\n\n", ret);
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ((ret = mbedtls_ssl_config_defaults(conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_STREAM,
 | 
					 | 
				
			||||||
                                         MBEDTLS_SSL_PRESET_DEFAULT)) != 0){
 | 
					 | 
				
			||||||
    FAIL_MSG(" failed\n  ! mbedtls_ssl_config_defaults returned %d\n\n", ret);
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  mbedtls_ssl_conf_authmode(conf, MBEDTLS_SSL_VERIFY_NONE);
 | 
					 | 
				
			||||||
  mbedtls_ssl_conf_rng(conf, mbedtls_ctr_drbg_random, ctr_drbg);
 | 
					 | 
				
			||||||
  mbedtls_ssl_conf_dbg(conf, my_debug, stderr);
 | 
					 | 
				
			||||||
  if ((ret = mbedtls_ssl_setup(ssl, conf)) != 0){
 | 
					 | 
				
			||||||
    char estr[200];
 | 
					 | 
				
			||||||
    mbedtls_strerror(ret, estr, 200);
 | 
					 | 
				
			||||||
    FAIL_MSG("SSL setup error %d: %s", ret, estr);
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if ((ret = mbedtls_ssl_set_hostname(ssl, hostname.c_str())) != 0){
 | 
					 | 
				
			||||||
    FAIL_MSG(" failed\n  ! mbedtls_ssl_set_hostname returned %d\n\n", ret);
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
    return;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  mbedtls_ssl_set_bio(ssl, server_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
 | 
					 | 
				
			||||||
  while ((ret = mbedtls_ssl_handshake(ssl)) != 0){
 | 
					 | 
				
			||||||
    if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
 | 
					 | 
				
			||||||
      char estr[200];
 | 
					 | 
				
			||||||
      mbedtls_strerror(ret, estr, 200);
 | 
					 | 
				
			||||||
      FAIL_MSG("SSL handshake error %d: %s", ret, estr);
 | 
					 | 
				
			||||||
      close();
 | 
					 | 
				
			||||||
      return;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  Blocking = true;
 | 
					 | 
				
			||||||
  if (nonblock){setBlocking(false);}
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Socket::SSLConnection::close(){
 | 
					 | 
				
			||||||
  DONTEVEN_MSG("SSL close");
 | 
					 | 
				
			||||||
  if (server_fd){
 | 
					 | 
				
			||||||
    mbedtls_net_free(server_fd);
 | 
					 | 
				
			||||||
    delete server_fd;
 | 
					 | 
				
			||||||
    server_fd = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (ssl){
 | 
					 | 
				
			||||||
    mbedtls_ssl_free(ssl);
 | 
					 | 
				
			||||||
    delete ssl;
 | 
					 | 
				
			||||||
    ssl = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (conf){
 | 
					 | 
				
			||||||
    mbedtls_ssl_config_free(conf);
 | 
					 | 
				
			||||||
    delete conf;
 | 
					 | 
				
			||||||
    conf = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (ctr_drbg){
 | 
					 | 
				
			||||||
    mbedtls_ctr_drbg_free(ctr_drbg);
 | 
					 | 
				
			||||||
    delete ctr_drbg;
 | 
					 | 
				
			||||||
    ctr_drbg = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (entropy){
 | 
					 | 
				
			||||||
    mbedtls_entropy_free(entropy);
 | 
					 | 
				
			||||||
    delete entropy;
 | 
					 | 
				
			||||||
    entropy = 0;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  isConnected = false;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Incremental read call. This function tries to read len bytes to the buffer from the socket,
 | 
					 | 
				
			||||||
/// returning the amount of bytes it actually read.
 | 
					 | 
				
			||||||
/// \param buffer Location of the buffer to read to.
 | 
					 | 
				
			||||||
/// \param len Amount of bytes to read.
 | 
					 | 
				
			||||||
/// \param flags Flags to use in the recv call. Ignored on fake sockets.
 | 
					 | 
				
			||||||
/// \returns The amount of bytes actually read.
 | 
					 | 
				
			||||||
int Socket::SSLConnection::iread(void *buffer, int len, int flags){
 | 
					 | 
				
			||||||
  DONTEVEN_MSG("SSL iread");
 | 
					 | 
				
			||||||
  if (!connected() || len < 1){return 0;}
 | 
					 | 
				
			||||||
  int r;
 | 
					 | 
				
			||||||
  /// \TODO Flags ignored... Bad.
 | 
					 | 
				
			||||||
  r = mbedtls_ssl_read(ssl, (unsigned char *)buffer, len);
 | 
					 | 
				
			||||||
  if (r < 0){
 | 
					 | 
				
			||||||
    char estr[200];
 | 
					 | 
				
			||||||
    mbedtls_strerror(r, estr, 200);
 | 
					 | 
				
			||||||
    INFO_MSG("Read returns %d: %s", r, estr);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (r < 0){
 | 
					 | 
				
			||||||
    switch (errno){
 | 
					 | 
				
			||||||
    case MBEDTLS_ERR_SSL_PEER_CLOSE_NOTIFY: close(); return 0; break;
 | 
					 | 
				
			||||||
    case MBEDTLS_ERR_SSL_WANT_WRITE: return 0; break;
 | 
					 | 
				
			||||||
    case MBEDTLS_ERR_SSL_WANT_READ: return 0; break;
 | 
					 | 
				
			||||||
    case EWOULDBLOCK: return 0; break;
 | 
					 | 
				
			||||||
    case EINTR: return 0; break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      Error = true;
 | 
					 | 
				
			||||||
      INSANE_MSG("Could not iread data! Error: %s", strerror(errno));
 | 
					 | 
				
			||||||
      close();
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (r == 0){
 | 
					 | 
				
			||||||
    DONTEVEN_MSG("Socket closed by remote");
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  down += r;
 | 
					 | 
				
			||||||
  return r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
/// Incremental write call. This function tries to write len bytes to the socket from the buffer,
 | 
					 | 
				
			||||||
/// returning the amount of bytes it actually wrote.
 | 
					 | 
				
			||||||
/// \param buffer Location of the buffer to write from.
 | 
					 | 
				
			||||||
/// \param len Amount of bytes to write.
 | 
					 | 
				
			||||||
/// \returns The amount of bytes actually written.
 | 
					 | 
				
			||||||
unsigned int Socket::SSLConnection::iwrite(const void *buffer, int len){
 | 
					 | 
				
			||||||
  DONTEVEN_MSG("SSL iwrite");
 | 
					 | 
				
			||||||
  if (!connected() || len < 1){return 0;}
 | 
					 | 
				
			||||||
  int r;
 | 
					 | 
				
			||||||
  r = mbedtls_ssl_write(ssl, (const unsigned char *)buffer, len);
 | 
					 | 
				
			||||||
  if (r < 0){
 | 
					 | 
				
			||||||
    char estr[200];
 | 
					 | 
				
			||||||
    mbedtls_strerror(r, estr, 200);
 | 
					 | 
				
			||||||
    INFO_MSG("Write returns %d: %s", r, estr);
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (r < 0){
 | 
					 | 
				
			||||||
    switch (errno){
 | 
					 | 
				
			||||||
    case MBEDTLS_ERR_SSL_WANT_WRITE: return 0; break;
 | 
					 | 
				
			||||||
    case MBEDTLS_ERR_SSL_WANT_READ: return 0; break;
 | 
					 | 
				
			||||||
    case EWOULDBLOCK: return 0; break;
 | 
					 | 
				
			||||||
    default:
 | 
					 | 
				
			||||||
      Error = true;
 | 
					 | 
				
			||||||
      INSANE_MSG("Could not iwrite data! Error: %s", strerror(errno));
 | 
					 | 
				
			||||||
      close();
 | 
					 | 
				
			||||||
      return 0;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  if (r == 0 && (sSend >= 0)){
 | 
					 | 
				
			||||||
    DONTEVEN_MSG("Socket closed by remote");
 | 
					 | 
				
			||||||
    close();
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
  up += r;
 | 
					 | 
				
			||||||
  return r;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
bool Socket::SSLConnection::connected() const{
 | 
					 | 
				
			||||||
  return isConnected;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
void Socket::SSLConnection::setBlocking(bool blocking){
 | 
					 | 
				
			||||||
  if (blocking != Blocking){return;}
 | 
					 | 
				
			||||||
  if (blocking){
 | 
					 | 
				
			||||||
    mbedtls_net_set_block(server_fd);
 | 
					 | 
				
			||||||
    Blocking = true;
 | 
					 | 
				
			||||||
  }else{
 | 
					 | 
				
			||||||
    mbedtls_net_set_nonblock(server_fd);
 | 
					 | 
				
			||||||
    Blocking = false;
 | 
					 | 
				
			||||||
  }
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
/// Create a new base Server. The socket is never connected, and a placeholder for later
 | 
					/// Create a new base Server. The socket is never connected, and a placeholder for later
 | 
				
			||||||
/// connections.
 | 
					/// connections.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										56
									
								
								lib/socket.h
									
										
									
									
									
								
							
							
						
						
									
										56
									
								
								lib/socket.h
									
										
									
									
									
								
							| 
						 | 
					@ -71,6 +71,7 @@ namespace Socket{
 | 
				
			||||||
  /// If they are not identical and sRecv is closed but sSend still open, reading from sSend will be attempted.
 | 
					  /// If they are not identical and sRecv is closed but sSend still open, reading from sSend will be attempted.
 | 
				
			||||||
  class Connection{
 | 
					  class Connection{
 | 
				
			||||||
  protected:
 | 
					  protected:
 | 
				
			||||||
 | 
					    void clear(); ///< Clears the internal data structure. Meant only for use in constructors.
 | 
				
			||||||
    bool isTrueSocket;
 | 
					    bool isTrueSocket;
 | 
				
			||||||
    int sSend;               ///< Write end of socket.
 | 
					    int sSend;               ///< Write end of socket.
 | 
				
			||||||
    int sRecv;               ///< Read end of socket.
 | 
					    int sRecv;               ///< Read end of socket.
 | 
				
			||||||
| 
						 | 
					@ -81,24 +82,46 @@ namespace Socket{
 | 
				
			||||||
    uint64_t down;
 | 
					    uint64_t down;
 | 
				
			||||||
    long long int conntime;
 | 
					    long long int conntime;
 | 
				
			||||||
    Buffer downbuffer;                                ///< Stores temporary data coming in.
 | 
					    Buffer downbuffer;                                ///< Stores temporary data coming in.
 | 
				
			||||||
    virtual int iread(void *buffer, int len, int flags = 0);  ///< Incremental read call.
 | 
					    int iread(void *buffer, int len, int flags = 0);  ///< Incremental read call.
 | 
				
			||||||
    virtual unsigned int iwrite(const void *buffer, int len); ///< Incremental write call.
 | 
					    unsigned int iwrite(const void *buffer, int len); ///< Incremental write call.
 | 
				
			||||||
    bool iread(Buffer &buffer, int flags = 0);        ///< Incremental write call that is compatible with Socket::Buffer.
 | 
					    bool iread(Buffer &buffer, int flags = 0);        ///< Incremental write call that is compatible with Socket::Buffer.
 | 
				
			||||||
    bool iwrite(std::string &buffer);                 ///< Write call that is compatible with std::string.
 | 
					    bool iwrite(std::string &buffer);                 ///< Write call that is compatible with std::string.
 | 
				
			||||||
    void setBoundAddr();
 | 
					    void setBoundAddr();
 | 
				
			||||||
 | 
					#ifdef SSL
 | 
				
			||||||
 | 
					  /// optional extension that uses mbedtls for SSL
 | 
				
			||||||
 | 
					  protected:
 | 
				
			||||||
 | 
					    bool sslConnected;
 | 
				
			||||||
 | 
					    int ssl_iread(void *buffer, int len, int flags = 0);  ///< Incremental read call.
 | 
				
			||||||
 | 
					    unsigned int ssl_iwrite(const void *buffer, int len); ///< Incremental write call.
 | 
				
			||||||
 | 
					    mbedtls_net_context * server_fd;
 | 
				
			||||||
 | 
					    mbedtls_entropy_context * entropy;
 | 
				
			||||||
 | 
					    mbedtls_ctr_drbg_context * ctr_drbg;
 | 
				
			||||||
 | 
					    mbedtls_ssl_context * ssl;
 | 
				
			||||||
 | 
					    mbedtls_ssl_config * conf;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public:
 | 
					  public:
 | 
				
			||||||
    // friends
 | 
					    // friends
 | 
				
			||||||
    friend class ::Buffer::user;
 | 
					    friend class ::Buffer::user;
 | 
				
			||||||
    // constructors
 | 
					    // constructors
 | 
				
			||||||
    Connection();                                              ///< Create a new disconnected base socket.
 | 
					    Connection();                                              ///< Create a new disconnected base socket.
 | 
				
			||||||
    Connection(int sockNo);                                    ///< Create a new base socket.
 | 
					    Connection(int sockNo);                                    ///< Create a new base socket.
 | 
				
			||||||
    Connection(std::string hostname, int port, bool nonblock); ///< Create a new TCP socket.
 | 
					    Connection(std::string hostname, int port, bool nonblock, bool with_ssl = false); ///< Create a new TCP socket.
 | 
				
			||||||
    Connection(std::string adres, bool nonblock = false);      ///< Create a new Unix Socket.
 | 
					    Connection(std::string adres, bool nonblock = false);      ///< Create a new Unix Socket.
 | 
				
			||||||
    Connection(int write, int read);                           ///< Simulate a socket using two file descriptors.
 | 
					    Connection(int write, int read);                           ///< Simulate a socket using two file descriptors.
 | 
				
			||||||
 | 
					    // copy/assignment constructors
 | 
				
			||||||
 | 
					    Connection(const Connection& rhs);
 | 
				
			||||||
 | 
					    Connection& operator=(const Connection& rhs);
 | 
				
			||||||
 | 
					    // destructor
 | 
				
			||||||
 | 
					    ~Connection();
 | 
				
			||||||
    // generic methods
 | 
					    // generic methods
 | 
				
			||||||
    virtual void close();                    ///< Close connection.
 | 
					    void open(int sockNo);//Open from existing socket connection.
 | 
				
			||||||
 | 
					    void open(std::string hostname, int port, bool nonblock, bool with_ssl = false);//Open TCP connection.
 | 
				
			||||||
 | 
					    void open(std::string adres, bool nonblock = false);//Open Unix connection.
 | 
				
			||||||
 | 
					    void open(int write, int read);//Open from two existing file descriptors.
 | 
				
			||||||
 | 
					    void close();                    ///< Close connection.
 | 
				
			||||||
    void drop();                     ///< Close connection without shutdown.
 | 
					    void drop();                     ///< Close connection without shutdown.
 | 
				
			||||||
    virtual void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
 | 
					    void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
 | 
				
			||||||
    bool isBlocking();               ///< Check if this socket is blocking (true) or nonblocking (false).
 | 
					    bool isBlocking();               ///< Check if this socket is blocking (true) or nonblocking (false).
 | 
				
			||||||
    std::string getHost() const;     ///< Gets hostname for connection, if available.
 | 
					    std::string getHost() const;     ///< Gets hostname for connection, if available.
 | 
				
			||||||
    std::string getBinHost();
 | 
					    std::string getBinHost();
 | 
				
			||||||
| 
						 | 
					@ -107,7 +130,7 @@ namespace Socket{
 | 
				
			||||||
    int getSocket();                ///< Returns internal socket number.
 | 
					    int getSocket();                ///< Returns internal socket number.
 | 
				
			||||||
    int getPureSocket();            ///< Returns non-piped internal socket number.
 | 
					    int getPureSocket();            ///< Returns non-piped internal socket number.
 | 
				
			||||||
    std::string getError();         ///< Returns a string describing the last error that occured.
 | 
					    std::string getError();         ///< Returns a string describing the last error that occured.
 | 
				
			||||||
    virtual bool connected() const;         ///< Returns the connected-state for this socket.
 | 
					    bool connected() const;         ///< Returns the connected-state for this socket.
 | 
				
			||||||
    bool isAddress(const std::string &addr);
 | 
					    bool isAddress(const std::string &addr);
 | 
				
			||||||
    bool isLocal(); ///< Returns true if remote address is a local address.
 | 
					    bool isLocal(); ///< Returns true if remote address is a local address.
 | 
				
			||||||
    // buffered i/o methods
 | 
					    // buffered i/o methods
 | 
				
			||||||
| 
						 | 
					@ -136,27 +159,6 @@ namespace Socket{
 | 
				
			||||||
    operator bool() const;
 | 
					    operator bool() const;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef SSL
 | 
					 | 
				
			||||||
  /// Version of Socket::Connection that uses mbedtls for SSL
 | 
					 | 
				
			||||||
  class SSLConnection : public Connection{
 | 
					 | 
				
			||||||
    public:
 | 
					 | 
				
			||||||
      SSLConnection();
 | 
					 | 
				
			||||||
      SSLConnection(std::string hostname, int port, bool nonblock); ///< Create a new TCP socket.
 | 
					 | 
				
			||||||
      void close();                    ///< Close connection.
 | 
					 | 
				
			||||||
      bool connected() const;         ///< Returns the connected-state for this socket.
 | 
					 | 
				
			||||||
      void setBlocking(bool blocking); ///< Set this socket to be blocking (true) or nonblocking (false).
 | 
					 | 
				
			||||||
    protected:
 | 
					 | 
				
			||||||
      bool isConnected;
 | 
					 | 
				
			||||||
      int iread(void *buffer, int len, int flags = 0);  ///< Incremental read call.
 | 
					 | 
				
			||||||
      unsigned int iwrite(const void *buffer, int len); ///< Incremental write call.
 | 
					 | 
				
			||||||
      mbedtls_net_context * server_fd;
 | 
					 | 
				
			||||||
      mbedtls_entropy_context * entropy;
 | 
					 | 
				
			||||||
      mbedtls_ctr_drbg_context * ctr_drbg;
 | 
					 | 
				
			||||||
      mbedtls_ssl_context * ssl;
 | 
					 | 
				
			||||||
      mbedtls_ssl_config * conf;
 | 
					 | 
				
			||||||
  };
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  /// This class is for easily setting up listening socket, either TCP or Unix.
 | 
					  /// This class is for easily setting up listening socket, either TCP or Unix.
 | 
				
			||||||
  class Server{
 | 
					  class Server{
 | 
				
			||||||
  private:
 | 
					  private:
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -529,9 +529,13 @@ namespace TS {
 | 
				
			||||||
/// \param len The length of this frame.
 | 
					/// \param len The length of this frame.
 | 
				
			||||||
/// \param PTS The timestamp of the frame.
 | 
					/// \param PTS The timestamp of the frame.
 | 
				
			||||||
  std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps) {
 | 
					  std::string & Packet::getPESVideoLeadIn(unsigned int len, unsigned long long PTS, unsigned long long offset, bool isAligned, uint64_t bps) {
 | 
				
			||||||
 | 
					    if (len){
 | 
				
			||||||
    len += (offset ? 13 : 8);
 | 
					    len += (offset ? 13 : 8);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    if (bps >= 50){
 | 
					    if (bps >= 50){
 | 
				
			||||||
 | 
					      if (len){
 | 
				
			||||||
      len += 3;
 | 
					      len += 3;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      bps = 0;
 | 
					      bps = 0;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -828,7 +832,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 0x24: return "HEVC";
 | 
				
			||||||
      case 0x81: return "AC3";
 | 
					      case 0x81: return "AC3";
 | 
				
			||||||
      default: return "unknown";
 | 
					      default: return "unknown";
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1232,6 +1236,7 @@ namespace TS {
 | 
				
			||||||
      }else if (myMeta.tracks[*it].codec == "MP3"){
 | 
					      }else if (myMeta.tracks[*it].codec == "MP3"){
 | 
				
			||||||
        entry.setStreamType(0x03);
 | 
					        entry.setStreamType(0x03);
 | 
				
			||||||
      }else if (myMeta.tracks[*it].codec == "ID3"){
 | 
					      }else if (myMeta.tracks[*it].codec == "ID3"){
 | 
				
			||||||
 | 
					        entry.setStreamType(0x15);
 | 
				
			||||||
        entry.setESInfo(myMeta.tracks[*it].init);
 | 
					        entry.setESInfo(myMeta.tracks[*it].init);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      entry.advance();
 | 
					      entry.advance();
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -14,7 +14,7 @@ void AnalyserDTSC::init(Util::Config &conf){
 | 
				
			||||||
 | 
					
 | 
				
			||||||
bool AnalyserDTSC::open(const std::string &filename){
 | 
					bool AnalyserDTSC::open(const std::string &filename){
 | 
				
			||||||
  if (!Analyser::open(filename)){return false;}
 | 
					  if (!Analyser::open(filename)){return false;}
 | 
				
			||||||
  conn = Socket::Connection(1, 0);
 | 
					  conn.open(1, 0);
 | 
				
			||||||
  totalBytes = 0;
 | 
					  totalBytes = 0;
 | 
				
			||||||
  return true;
 | 
					  return true;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -492,6 +492,7 @@ void Controller::handleAPICommands(JSON::Value & Request, JSON::Value & Response
 | 
				
			||||||
    Response["capabilities"] = capabilities;
 | 
					    Response["capabilities"] = capabilities;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  if(Request.isMember("browse")){                    
 | 
					  if(Request.isMember("browse")){                    
 | 
				
			||||||
    if(Request["browse"] == ""){
 | 
					    if(Request["browse"] == ""){
 | 
				
			||||||
      Request["browse"] = ".";
 | 
					      Request["browse"] = ".";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -37,9 +37,11 @@ namespace Controller {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    memset(f.mapped, 0, 32);
 | 
					    memset(f.mapped, 0, 32);
 | 
				
			||||||
    Util::RelAccX A(f.mapped, false);
 | 
					    Util::RelAccX A(f.mapped, false);
 | 
				
			||||||
 | 
					    if (!A.isReady()){
 | 
				
			||||||
    A.addField("cmd", RAX_128STRING);
 | 
					    A.addField("cmd", RAX_128STRING);
 | 
				
			||||||
    A.addField("pid", RAX_64UINT);
 | 
					    A.addField("pid", RAX_64UINT);
 | 
				
			||||||
    A.setReady();
 | 
					    A.setReady();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    uint32_t count = 0;
 | 
					    uint32_t count = 0;
 | 
				
			||||||
    std::map<std::string, pid_t>::iterator it;
 | 
					    std::map<std::string, pid_t>::iterator it;
 | 
				
			||||||
    for (it = currentConnectors.begin(); it != currentConnectors.end(); ++it){
 | 
					    for (it = currentConnectors.begin(); it != currentConnectors.end(); ++it){
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -581,16 +581,34 @@ namespace Mist {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::string trackIdentifier = trackMeta.tracks.find(value)->second.getIdentifier();
 | 
					        std::string trackIdentifier = trackMeta.tracks.find(value)->second.getIdentifier();
 | 
				
			||||||
        DEBUG_MSG(DLVL_HIGH, "Attempting colision detection for track %s", trackIdentifier.c_str());
 | 
					        DEBUG_MSG(DLVL_HIGH, "Attempting colision detection for track %s", trackIdentifier.c_str());
 | 
				
			||||||
 | 
					        //Get the identifier for the track, and attempt colission detection.
 | 
				
			||||||
 | 
					        int collidesWith = -1;
 | 
				
			||||||
 | 
					        for (std::map<unsigned int, DTSC::Track>::iterator it = myMeta.tracks.begin(); it != myMeta.tracks.end(); it++) {
 | 
				
			||||||
 | 
					          //If the identifier of an existing track and the current track match, assume the are the same track and reject the negotiated one.
 | 
				
			||||||
 | 
					          ///\todo Maybe switch to a new form of detecting collisions, especially with regards to multiple audio languages and camera angles.
 | 
				
			||||||
 | 
					          if (it->second.getIdentifier() == trackIdentifier) {
 | 
				
			||||||
 | 
					            collidesWith = it->first;
 | 
				
			||||||
 | 
					            break;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        //Remove the "negotiate" status in either case
 | 
					        //Remove the "negotiate" status in either case
 | 
				
			||||||
        negotiatingTracks.erase(value);
 | 
					        negotiatingTracks.erase(value);
 | 
				
			||||||
        //Set master to true before erasing the page, because we are responsible for cleaning up unused pages
 | 
					        //Set master to true before erasing the page, because we are responsible for cleaning up unused pages
 | 
				
			||||||
        nProxy.metaPages[value].master = true;
 | 
					        nProxy.metaPages[value].master = true;
 | 
				
			||||||
        nProxy.metaPages.erase(value);
 | 
					        nProxy.metaPages.erase(value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        int finalMap = 3;
 | 
					        //Check if the track collides, and whether the track it collides with is active.
 | 
				
			||||||
        if (trackMeta.tracks.find(value)->second.type == "video"){finalMap = 1;}
 | 
					        if (collidesWith != -1 && activeTracks.count(collidesWith)) { /*LTS*/
 | 
				
			||||||
        if (trackMeta.tracks.find(value)->second.type == "audio"){finalMap = 2;}
 | 
					          //Print a warning message and set the state of the track to rejected.
 | 
				
			||||||
 | 
					          WARN_MSG("Collision of temporary track %lu with existing track %d detected. Handling as a new valid track.", value, collidesWith);
 | 
				
			||||||
 | 
					          collidesWith = -1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        uint64_t finalMap = collidesWith;
 | 
				
			||||||
 | 
					        if (finalMap == -1) {
 | 
				
			||||||
 | 
					          //No collision has been detected, assign a new final number
 | 
				
			||||||
 | 
					          finalMap = (myMeta.tracks.size() ? myMeta.tracks.rbegin()->first : 0) + 1;
 | 
				
			||||||
 | 
					          DEBUG_MSG(DLVL_DEVEL, "No colision detected for temporary track %lu from user %u, assigning final track number %lu", value, id, finalMap);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        //Resume either if we have more than 1 keyframe on the replacement track (assume it was already pushing before the track "dissapeared")
 | 
					        //Resume either if we have more than 1 keyframe on the replacement track (assume it was already pushing before the track "dissapeared")
 | 
				
			||||||
        //or if the firstms of the replacement track is later than the lastms on the existing track
 | 
					        //or if the firstms of the replacement track is later than the lastms on the existing track
 | 
				
			||||||
        if (!myMeta.tracks.count(finalMap) || trackMeta.tracks.find(value)->second.keys.size() > 1 || trackMeta.tracks.find(value)->second.firstms >= myMeta.tracks[finalMap].lastms) {
 | 
					        if (!myMeta.tracks.count(finalMap) || trackMeta.tracks.find(value)->second.keys.size() > 1 || trackMeta.tracks.find(value)->second.firstms >= myMeta.tracks[finalMap].lastms) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -144,7 +144,7 @@ namespace Mist {
 | 
				
			||||||
  bool inputDTSC::openStreamSource() {
 | 
					  bool inputDTSC::openStreamSource() {
 | 
				
			||||||
    std::string source = config->getString("input");
 | 
					    std::string source = config->getString("input");
 | 
				
			||||||
    if (source == "-"){
 | 
					    if (source == "-"){
 | 
				
			||||||
      srcConn = Socket::Connection(fileno(stdout),fileno(stdin));
 | 
					      srcConn.open(fileno(stdout),fileno(stdin));
 | 
				
			||||||
      return true;
 | 
					      return true;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (source.find("dtsc://") == 0) {
 | 
					    if (source.find("dtsc://") == 0) {
 | 
				
			||||||
| 
						 | 
					@ -159,7 +159,7 @@ namespace Mist {
 | 
				
			||||||
    if (streamName == "") {
 | 
					    if (streamName == "") {
 | 
				
			||||||
      streamName = givenStream;
 | 
					      streamName = givenStream;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    srcConn = Socket::Connection(host, port, true);
 | 
					    srcConn.open(host, port, true);
 | 
				
			||||||
    if (!srcConn.connected()){
 | 
					    if (!srcConn.connected()){
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -44,9 +44,9 @@ namespace Mist{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      int fin = -1, fout = -1;
 | 
					      int fin = -1, fout = -1;
 | 
				
			||||||
      inputProcess = Util::Procs::StartPiped(args, &fin, &fout, 0);
 | 
					      inputProcess = Util::Procs::StartPiped(args, &fin, &fout, 0);
 | 
				
			||||||
      myConn = Socket::Connection(-1, fout);
 | 
					      myConn.open(-1, fout);
 | 
				
			||||||
    }else{
 | 
					    }else{
 | 
				
			||||||
      myConn = Socket::Connection(fileno(stdout), fileno(stdin));
 | 
					      myConn.open(fileno(stdout), fileno(stdin));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    myConn.Received().splitter.assign("\000\000\001", 3);
 | 
					    myConn.Received().splitter.assign("\000\000\001", 3);
 | 
				
			||||||
    myMeta.vod = false;
 | 
					    myMeta.vod = false;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -57,16 +57,17 @@ namespace Mist {
 | 
				
			||||||
  bool InOutBase::bufferStart(unsigned long tid, unsigned long pageNumber) {
 | 
					  bool InOutBase::bufferStart(unsigned long tid, unsigned long pageNumber) {
 | 
				
			||||||
    VERYHIGH_MSG("bufferStart for stream %s, track %lu, page %lu", streamName.c_str(), tid, pageNumber);
 | 
					    VERYHIGH_MSG("bufferStart for stream %s, track %lu, page %lu", streamName.c_str(), tid, pageNumber);
 | 
				
			||||||
    //Initialize the stream metadata if it does not yet exist
 | 
					    //Initialize the stream metadata if it does not yet exist
 | 
				
			||||||
 | 
					#ifndef TSLIVE_INPUT
 | 
				
			||||||
    if (!nProxy.metaPages.count(0)) {
 | 
					    if (!nProxy.metaPages.count(0)) {
 | 
				
			||||||
      initiateMeta();
 | 
					      initiateMeta();
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
    //If we are a stand-alone player skip track negotiation, as there will be nothing to negotiate with.
 | 
					    //If we are a stand-alone player skip track negotiation, as there will be nothing to negotiate with.
 | 
				
			||||||
    if (standAlone) {
 | 
					    if (standAlone) {
 | 
				
			||||||
      if (!nProxy.trackMap.count(tid)) {
 | 
					      if (!nProxy.trackMap.count(tid)) {
 | 
				
			||||||
        nProxy.trackMap[tid] = tid;
 | 
					        nProxy.trackMap[tid] = tid;
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    //Negotiate the requested track if needed.
 | 
					 | 
				
			||||||
    return nProxy.bufferStart(tid, pageNumber, myMeta);
 | 
					    return nProxy.bufferStart(tid, pageNumber, myMeta);
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -667,6 +668,10 @@ namespace Mist {
 | 
				
			||||||
          tmpMeta.tracks[newTid] = myMeta.tracks[tid];
 | 
					          tmpMeta.tracks[newTid] = myMeta.tracks[tid];
 | 
				
			||||||
          tmpMeta.tracks[newTid].trackID = newTid;
 | 
					          tmpMeta.tracks[newTid].trackID = newTid;
 | 
				
			||||||
          JSON::Value tmpVal = tmpMeta.toJSON();
 | 
					          JSON::Value tmpVal = tmpMeta.toJSON();
 | 
				
			||||||
 | 
					          if (!myMeta.tracks[tid].type.size() || !myMeta.tracks[tid].codec.size()){
 | 
				
			||||||
 | 
					            FAIL_MSG("Negotiating a track without metadata. This is a serious issue, please report this to the developers.");
 | 
				
			||||||
 | 
					            BACKTRACE;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          std::string tmpStr = tmpVal.toNetPacked();
 | 
					          std::string tmpStr = tmpVal.toNetPacked();
 | 
				
			||||||
          memcpy(metaPages[tid].mapped, tmpStr.data(), tmpStr.size());
 | 
					          memcpy(metaPages[tid].mapped, tmpStr.data(), tmpStr.size());
 | 
				
			||||||
          HIGH_MSG("Temporary metadata written for incoming track %lu, handling as track %lu", tid, newTid);
 | 
					          HIGH_MSG("Temporary metadata written for incoming track %lu, handling as track %lu", tid, newTid);
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1053,7 +1053,7 @@ namespace Mist{
 | 
				
			||||||
      //actually drop what we found.
 | 
					      //actually drop what we found.
 | 
				
			||||||
      //if both of the above cases occur, the next prepareNext iteration will take care of that
 | 
					      //if both of the above cases occur, the next prepareNext iteration will take care of that
 | 
				
			||||||
      for (std::set<uint32_t>::iterator it = dropTracks.begin(); it != dropTracks.end(); ++it){
 | 
					      for (std::set<uint32_t>::iterator it = dropTracks.begin(); it != dropTracks.end(); ++it){
 | 
				
			||||||
        dropTrack(*it, "seek/select mismatch", true);
 | 
					        dropTrack(*it, "seek/select mismatch");
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
| 
						 | 
					@ -1061,7 +1061,7 @@ namespace Mist{
 | 
				
			||||||
    sortedPageInfo nxt = *(buffer.begin());
 | 
					    sortedPageInfo nxt = *(buffer.begin());
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (!myMeta.tracks.count(nxt.tid)){
 | 
					    if (!myMeta.tracks.count(nxt.tid)){
 | 
				
			||||||
      dropTrack(nxt.tid, "disappeared from metadata", true);
 | 
					      dropTrack(nxt.tid, "disappeared from metadata");
 | 
				
			||||||
      return false;
 | 
					      return false;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1105,7 +1105,7 @@ namespace Mist{
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      //for VoD, check if we've reached the end of the track, if so, drop it
 | 
					      //for VoD, check if we've reached the end of the track, if so, drop it
 | 
				
			||||||
      if (myMeta.vod && nxt.time > myMeta.tracks[nxt.tid].lastms){
 | 
					      if (myMeta.vod && nxt.time > myMeta.tracks[nxt.tid].lastms){
 | 
				
			||||||
        dropTrack(nxt.tid, "Reached end of track");
 | 
					        dropTrack(nxt.tid, "Reached end of track", false);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      //if this is a live stream, we might have just reached the live point.
 | 
					      //if this is a live stream, we might have just reached the live point.
 | 
				
			||||||
      //check where the next key is
 | 
					      //check where the next key is
 | 
				
			||||||
| 
						 | 
					@ -1137,9 +1137,9 @@ namespace Mist{
 | 
				
			||||||
      loadPageForKey(nxt.tid, ++nxtKeyNum[nxt.tid]);
 | 
					      loadPageForKey(nxt.tid, ++nxtKeyNum[nxt.tid]);
 | 
				
			||||||
      nxt.offset = 0;
 | 
					      nxt.offset = 0;
 | 
				
			||||||
      if (nProxy.curPage.count(nxt.tid) && nProxy.curPage[nxt.tid].mapped){
 | 
					      if (nProxy.curPage.count(nxt.tid) && nProxy.curPage[nxt.tid].mapped){
 | 
				
			||||||
        unsigned long long nextTime = getDTSCTime(nProxy.curPage[nxt.tid].mapped, nxt.offset);
 | 
					        uint64_t nextTime = getDTSCTime(nProxy.curPage[nxt.tid].mapped, nxt.offset);
 | 
				
			||||||
        if (nextTime && nextTime < nxt.time){
 | 
					        if (nextTime && nextTime < nxt.time){
 | 
				
			||||||
          dropTrack(nxt.tid, "time going backwards");
 | 
					          dropTrack(nxt.tid, "EOP: time going backwards ("+JSON::Value(nextTime).asString()+" < "+JSON::Value(nxt.time).asString()+")");
 | 
				
			||||||
        }else{
 | 
					        }else{
 | 
				
			||||||
          if (nextTime){
 | 
					          if (nextTime){
 | 
				
			||||||
            nxt.time = nextTime;
 | 
					            nxt.time = nextTime;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -22,9 +22,9 @@ namespace Mist {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return (time == rhs.time && tid < rhs.tid);
 | 
					      return (time == rhs.time && tid < rhs.tid);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    unsigned int tid;
 | 
					    uint64_t tid;
 | 
				
			||||||
    long long unsigned int time;
 | 
					    uint64_t time;
 | 
				
			||||||
    unsigned int offset;
 | 
					    uint32_t offset;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /// The output class is intended to be inherited by MistOut process classes.
 | 
					  /// The output class is intended to be inherited by MistOut process classes.
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -41,8 +41,7 @@ namespace Mist {
 | 
				
			||||||
      std::string host = getConnectedHost();
 | 
					      std::string host = getConnectedHost();
 | 
				
			||||||
      dup2(myConn.getSocket(), STDIN_FILENO);
 | 
					      dup2(myConn.getSocket(), STDIN_FILENO);
 | 
				
			||||||
      dup2(myConn.getSocket(), STDOUT_FILENO);
 | 
					      dup2(myConn.getSocket(), STDOUT_FILENO);
 | 
				
			||||||
      myConn.drop();
 | 
					      myConn.open(STDOUT_FILENO, STDIN_FILENO);
 | 
				
			||||||
      myConn = Socket::Connection(STDOUT_FILENO, STDIN_FILENO);
 | 
					 | 
				
			||||||
      myConn.setHost(host);
 | 
					      myConn.setHost(host);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){
 | 
					    if (config->getOption("wrappers",true).size() == 0 || config->getString("wrappers") == ""){
 | 
				
			||||||
| 
						 | 
					@ -279,6 +278,10 @@ namespace Mist {
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    std::string devSkin = "";
 | 
					    std::string devSkin = "";
 | 
				
			||||||
    if (H.GetVar("dev").size()) { devSkin = ",skin:\"dev\""; }
 | 
					    if (H.GetVar("dev").size()) { devSkin = ",skin:\"dev\""; }
 | 
				
			||||||
 | 
					    H.SetVar("stream", "");
 | 
				
			||||||
 | 
					    H.SetVar("dev", "");
 | 
				
			||||||
 | 
					    devSkin += ",urlappend:\"" + H.allVars() + "\"";
 | 
				
			||||||
 | 
					    H.SetVar("stream", streamName);
 | 
				
			||||||
    
 | 
					    
 | 
				
			||||||
    H.Clean();
 | 
					    H.Clean();
 | 
				
			||||||
    H.SetHeader("Content-Type", "text/html");
 | 
					    H.SetHeader("Content-Type", "text/html");
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										241
									
								
								src/output/output_https.cpp
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										241
									
								
								src/output/output_https.cpp
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,241 @@
 | 
				
			||||||
 | 
					#include "output_https.h"
 | 
				
			||||||
 | 
					#include <mist/procs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Mist{
 | 
				
			||||||
 | 
					  mbedtls_entropy_context OutHTTPS::entropy;
 | 
				
			||||||
 | 
					  mbedtls_ctr_drbg_context OutHTTPS::ctr_drbg;
 | 
				
			||||||
 | 
					  mbedtls_ssl_config OutHTTPS::sslConf;
 | 
				
			||||||
 | 
					  mbedtls_x509_crt OutHTTPS::srvcert;
 | 
				
			||||||
 | 
					  mbedtls_pk_context OutHTTPS::pkey;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  void OutHTTPS::init(Util::Config *cfg){
 | 
				
			||||||
 | 
					    Output::init(cfg);
 | 
				
			||||||
 | 
					    capa["name"] = "HTTPS";
 | 
				
			||||||
 | 
					    capa["friendly"] = "HTTPS (HTTP+TLS)";
 | 
				
			||||||
 | 
					    capa["desc"] = "HTTPS connection handler, provides all enabled HTTP-based outputs";
 | 
				
			||||||
 | 
					    capa["provides"] = "HTTP";
 | 
				
			||||||
 | 
					    capa["protocol"] = "https://";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["name"] = "Certificate";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["help"] = "(Root) certificate(s) file(s) to append to chain";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["option"] = "--cert";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["short"] = "C";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["default"] = "";
 | 
				
			||||||
 | 
					    capa["required"]["cert"]["type"] = "str";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["name"] = "Key";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["help"] = "Private key for SSL";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["option"] = "--key";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["short"] = "K";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["default"] = "";
 | 
				
			||||||
 | 
					    capa["required"]["key"]["type"] = "str";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["name"] = "Active players";
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["help"] = "Which players are attempted and in what order.";
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["default"] = "";
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["type"] = "ord_multi_sel";
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("html5");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("videojs");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("dashjs");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("flash_strobe");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("silverlight");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["allowed"].append("img");
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["option"] = "--wrappers";
 | 
				
			||||||
 | 
					    capa["optional"]["wrappers"]["short"] = "w";
 | 
				
			||||||
 | 
					    cfg->addConnectorOptions(4433, capa);
 | 
				
			||||||
 | 
					    config = cfg;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OutHTTPS::OutHTTPS(Socket::Connection &C) : Output(C){
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    mbedtls_net_init(&client_fd);
 | 
				
			||||||
 | 
					    client_fd.fd = C.getSocket();
 | 
				
			||||||
 | 
					    mbedtls_ssl_init(&ssl);
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ctr_drbg_reseed(&ctr_drbg, (const unsigned char *)"child", 5)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not reseed");
 | 
				
			||||||
 | 
					      C.close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Set up the SSL connection
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_setup(&ssl, &sslConf)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not set up SSL connection");
 | 
				
			||||||
 | 
					      C.close();
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Inform mbedtls how we'd like to use the connection (uses default bio handlers)
 | 
				
			||||||
 | 
					    // We tell it to use non-blocking IO here
 | 
				
			||||||
 | 
					    mbedtls_net_set_nonblock(&client_fd);
 | 
				
			||||||
 | 
					    mbedtls_ssl_set_bio(&ssl, &client_fd, mbedtls_net_send, mbedtls_net_recv, NULL);
 | 
				
			||||||
 | 
					    // do the SSL handshake
 | 
				
			||||||
 | 
					    while ((ret = mbedtls_ssl_handshake(&ssl)) != 0){
 | 
				
			||||||
 | 
					      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
 | 
				
			||||||
 | 
					        char error_buf[200];
 | 
				
			||||||
 | 
					        mbedtls_strerror(ret, error_buf, 200);
 | 
				
			||||||
 | 
					        MEDIUM_MSG("Could not handshake, SSL error: %s (%d)", error_buf, ret);
 | 
				
			||||||
 | 
					        C.close();
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					      }else{
 | 
				
			||||||
 | 
					        Util::sleep(100);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    HIGH_MSG("Started SSL connection handler");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  int OutHTTPS::run(){
 | 
				
			||||||
 | 
					    unsigned char buf[1024 * 4]; // 4k internal buffer
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Start a MistOutHTTP process, connected to this SSL connection
 | 
				
			||||||
 | 
					    int fderr = 2;
 | 
				
			||||||
 | 
					    int fd[2];
 | 
				
			||||||
 | 
					    if (socketpair(PF_LOCAL, SOCK_STREAM, 0, fd) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not open anonymous socket for SSL<->HTTP connection!");
 | 
				
			||||||
 | 
					      return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    std::deque<std::string> args;
 | 
				
			||||||
 | 
					    args.push_back(Util::getMyPath() + "MistOutHTTP");
 | 
				
			||||||
 | 
					    args.push_back("--ip");
 | 
				
			||||||
 | 
					    args.push_back(myConn.getHost());
 | 
				
			||||||
 | 
					    if (config->getString("nostreamtext").size()){
 | 
				
			||||||
 | 
					      args.push_back("--nostreamtext");
 | 
				
			||||||
 | 
					      args.push_back(config->getString("nostreamtext"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    if (config->getString("pubaddr").size()){
 | 
				
			||||||
 | 
					      args.push_back("--public-address");
 | 
				
			||||||
 | 
					      args.push_back(config->getString("pubaddr"));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    args.push_back("");
 | 
				
			||||||
 | 
					    Util::Procs::socketList.insert(fd[0]);
 | 
				
			||||||
 | 
					    pid_t http_proc = Util::Procs::StartPiped(args, &(fd[1]), &(fd[1]), &fderr);
 | 
				
			||||||
 | 
					    close(fd[1]);
 | 
				
			||||||
 | 
					    if (http_proc < 2){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not spawn MistOutHTTP process for SSL connection!");
 | 
				
			||||||
 | 
					      return 1;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    Socket::Connection http(fd[0]);
 | 
				
			||||||
 | 
					    http.setBlocking(false);
 | 
				
			||||||
 | 
					    Socket::Buffer &http_buf = http.Received();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pass data back and forth between the SSL connection and HTTP process while connected
 | 
				
			||||||
 | 
					    while (config->is_active && http){
 | 
				
			||||||
 | 
					      bool activity = false;
 | 
				
			||||||
 | 
					      // attempt to read SSL data, pass to HTTP
 | 
				
			||||||
 | 
					      ret = mbedtls_ssl_read(&ssl, buf, sizeof(buf));
 | 
				
			||||||
 | 
					      if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
 | 
				
			||||||
 | 
					        if (ret <= 0){
 | 
				
			||||||
 | 
					          HIGH_MSG("SSL disconnect!");
 | 
				
			||||||
 | 
					          break;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        // we received ret bytes of data to pass on. Do so.
 | 
				
			||||||
 | 
					        activity = true;
 | 
				
			||||||
 | 
					        http.SendNow((const char *)buf, ret);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      // attempt to read HTTP data, pass to SSL
 | 
				
			||||||
 | 
					      if (http.spool() || http_buf.size()){
 | 
				
			||||||
 | 
					        // We have data - pass it on
 | 
				
			||||||
 | 
					        activity = true;
 | 
				
			||||||
 | 
					        while (http_buf.size() && http){
 | 
				
			||||||
 | 
					          int todo = http_buf.get().size();
 | 
				
			||||||
 | 
					          int done = 0;
 | 
				
			||||||
 | 
					          while (done < todo){
 | 
				
			||||||
 | 
					            ret = mbedtls_ssl_write(&ssl, (const unsigned char*)http_buf.get().data() + done, todo - done);
 | 
				
			||||||
 | 
					            if (ret == MBEDTLS_ERR_NET_CONN_RESET || ret == MBEDTLS_ERR_SSL_CLIENT_RECONNECT){
 | 
				
			||||||
 | 
					              HIGH_MSG("SSL disconnect!");
 | 
				
			||||||
 | 
					              http.close();
 | 
				
			||||||
 | 
					              break;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            if (ret != MBEDTLS_ERR_SSL_WANT_READ && ret != MBEDTLS_ERR_SSL_WANT_WRITE){
 | 
				
			||||||
 | 
					              done += ret;
 | 
				
			||||||
 | 
					            }else{
 | 
				
			||||||
 | 
					              Util::sleep(50);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          http_buf.get().clear();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      if (!activity){
 | 
				
			||||||
 | 
					        Util::sleep(50);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // close the HTTP process (close stdio, kill its PID)
 | 
				
			||||||
 | 
					    http.close();
 | 
				
			||||||
 | 
					    Util::Procs::Stop(http_proc);
 | 
				
			||||||
 | 
					    uint16_t waiting = 0;
 | 
				
			||||||
 | 
					    while (++waiting < 100){
 | 
				
			||||||
 | 
					      if (!Util::Procs::isRunning(http_proc)){break;}
 | 
				
			||||||
 | 
					      Util::sleep(100);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  OutHTTPS::~OutHTTPS(){
 | 
				
			||||||
 | 
					    HIGH_MSG("Ending SSL connection handler");
 | 
				
			||||||
 | 
					    // close when we're done
 | 
				
			||||||
 | 
					    mbedtls_ssl_close_notify(&ssl);
 | 
				
			||||||
 | 
					    mbedtls_ssl_free(&ssl);
 | 
				
			||||||
 | 
					    mbedtls_net_free(&client_fd);
 | 
				
			||||||
 | 
					    myConn.close();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Listens for HTTPS requests, accepting them and connecting them to a HTTP socket
 | 
				
			||||||
 | 
					  void OutHTTPS::listener(Util::Config &conf, int (*callback)(Socket::Connection &S)){
 | 
				
			||||||
 | 
					    if (config->getOption("cert", true).size() < 2 || config->getOption("key", true).size() < 2){
 | 
				
			||||||
 | 
					      FAIL_MSG("The cert/key required options were not passed!");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Declare and set up all required mbedtls structures
 | 
				
			||||||
 | 
					    int ret;
 | 
				
			||||||
 | 
					    mbedtls_ssl_config_init(&sslConf);
 | 
				
			||||||
 | 
					    mbedtls_entropy_init(&entropy);
 | 
				
			||||||
 | 
					    mbedtls_pk_init(&pkey);
 | 
				
			||||||
 | 
					    mbedtls_x509_crt_init(&srvcert);
 | 
				
			||||||
 | 
					    mbedtls_ctr_drbg_init(&ctr_drbg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // seed the rng
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)"MistServer", 10)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not seed the random number generator!");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Read certificate chain(s) from cmdline option(s)
 | 
				
			||||||
 | 
					    JSON::Value certs = config->getOption("cert", true);
 | 
				
			||||||
 | 
					    jsonForEach(certs, it){
 | 
				
			||||||
 | 
					      if (it->asStringRef().size()){//Ignore empty entries (default is empty)
 | 
				
			||||||
 | 
					        ret = mbedtls_x509_crt_parse_file(&srvcert, it->asStringRef().c_str());
 | 
				
			||||||
 | 
					        if (ret != 0){
 | 
				
			||||||
 | 
					          WARN_MSG("Could not load any certificates from file: %s", it->asStringRef().c_str());
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Read key from cmdline option
 | 
				
			||||||
 | 
					    ret = mbedtls_pk_parse_keyfile(&pkey, config->getString("key").c_str(), 0);
 | 
				
			||||||
 | 
					    if (ret != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("Could not load any keys from file: %s", config->getString("key").c_str());
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_config_defaults(&sslConf, MBEDTLS_SSL_IS_SERVER, MBEDTLS_SSL_TRANSPORT_STREAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("SSL config defaults failed");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    mbedtls_ssl_conf_rng(&sslConf, mbedtls_ctr_drbg_random, &ctr_drbg);
 | 
				
			||||||
 | 
					    mbedtls_ssl_conf_ca_chain(&sslConf, srvcert.next, NULL);
 | 
				
			||||||
 | 
					    if ((ret = mbedtls_ssl_conf_own_cert(&sslConf, &srvcert, &pkey)) != 0){
 | 
				
			||||||
 | 
					      FAIL_MSG("SSL config own certificate failed");
 | 
				
			||||||
 | 
					      return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Output::listener(conf, callback);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    //Free all the mbedtls structures
 | 
				
			||||||
 | 
					    mbedtls_x509_crt_free(&srvcert);
 | 
				
			||||||
 | 
					    mbedtls_pk_free(&pkey);
 | 
				
			||||||
 | 
					    mbedtls_ssl_config_free(&sslConf);
 | 
				
			||||||
 | 
					    mbedtls_ctr_drbg_free(&ctr_drbg);
 | 
				
			||||||
 | 
					    mbedtls_entropy_free(&entropy);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										34
									
								
								src/output/output_https.h
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/output/output_https.h
									
										
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,34 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					#include <mist/defines.h>
 | 
				
			||||||
 | 
					#include "output.h"
 | 
				
			||||||
 | 
					#include <mbedtls/certs.h>
 | 
				
			||||||
 | 
					#include <mbedtls/ctr_drbg.h>
 | 
				
			||||||
 | 
					#include <mbedtls/entropy.h>
 | 
				
			||||||
 | 
					#include <mbedtls/net.h>
 | 
				
			||||||
 | 
					#include <mbedtls/ssl.h>
 | 
				
			||||||
 | 
					#include <mbedtls/timing.h>
 | 
				
			||||||
 | 
					#include <mbedtls/x509.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Mist {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  class OutHTTPS : public Output {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      OutHTTPS(Socket::Connection & C);
 | 
				
			||||||
 | 
					      virtual ~OutHTTPS();
 | 
				
			||||||
 | 
					      void onRequest(){};
 | 
				
			||||||
 | 
					      int run();
 | 
				
			||||||
 | 
					      static bool listenMode(){return true;}
 | 
				
			||||||
 | 
					      static void init(Util::Config * cfg);
 | 
				
			||||||
 | 
					      static void listener(Util::Config & conf, int (*callback)(Socket::Connection & S));
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					      mbedtls_net_context client_fd;
 | 
				
			||||||
 | 
					      mbedtls_ssl_context ssl;
 | 
				
			||||||
 | 
					      static mbedtls_entropy_context entropy;
 | 
				
			||||||
 | 
					      static mbedtls_ctr_drbg_context ctr_drbg;
 | 
				
			||||||
 | 
					      static mbedtls_ssl_config sslConf;
 | 
				
			||||||
 | 
					      static mbedtls_x509_crt srvcert;
 | 
				
			||||||
 | 
					      static mbedtls_pk_context pkey;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef Mist::OutHTTPS mistOut;
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,7 @@ namespace Mist {
 | 
				
			||||||
    capa["friendly"] = "TS over TCP";
 | 
					    capa["friendly"] = "TS over TCP";
 | 
				
			||||||
    capa["desc"] = "Real time streaming in MPEG2/TS format over raw TCP";
 | 
					    capa["desc"] = "Real time streaming in MPEG2/TS format over raw TCP";
 | 
				
			||||||
    capa["deps"] = "";
 | 
					    capa["deps"] = "";
 | 
				
			||||||
    capa["required"]["streamname"]["name"] = "Stream";
 | 
					    capa["required"]["streamname"]["name"] = "Source stream";
 | 
				
			||||||
    capa["required"]["streamname"]["help"] = "What streamname to serve. For multiple streams, add this protocol multiple times using different ports.";
 | 
					    capa["required"]["streamname"]["help"] = "What streamname to serve. For multiple streams, add this protocol multiple times using different ports.";
 | 
				
			||||||
    capa["required"]["streamname"]["type"] = "str";
 | 
					    capa["required"]["streamname"]["type"] = "str";
 | 
				
			||||||
    capa["required"]["streamname"]["option"] = "--stream";
 | 
					    capa["required"]["streamname"]["option"] = "--stream";
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue