Hi Ross,

I made an attempt at implementing RTSP over HTTPS tunneling on the client side.
I've split the changes into 3 patch sets.
I tried to use tabs and spaces that match the surrounding code. In order to 
keep the tabs,
I attached the patches instead of pasting them into the mail body.

1. The first one fixes a minor issue (or at least it seems to be an issue):
RTSPClient::connectionHandler1 checks the opened socket. In case of HTTP 
tunneling,
it is the fInputSocketNum for the GET connection, but it should be the 
fOutputSocketNum
for the POST one. The simplest fix is to use fOutputSocketNum, since it is 
equal to
fInputSocketNum during opening the GET connection.

2. The second one adds optional TLS handling to the HTTP tunnel of the 
RTSPClient class.
The default is no TLS, so other code parts are not affected.

3. The third one adds a new option to openRTSP, to optionally make use of HTTPS 
tunneling.
Since it was difficult to find a free switch, having no better idea, the new 
option is
-X <https-port>
The options -t, -T and -X are mutually exclusive.

I hope you can incorporate some of the changes into the library!

Thanks,

Laszlo
diff --git a/liveMedia/RTSPClient.cpp b/liveMedia/RTSPClient.cpp
index 3f24143..4c4c423 100644
--- a/liveMedia/RTSPClient.cpp
+++ b/liveMedia/RTSPClient.cpp
@@ -1595,7 +1595,7 @@ void RTSPClient::connectionHandler1() {
   do {
     int err = 0;
     SOCKLEN_T len = sizeof err;
-    if (getsockopt(fInputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {
+    if (getsockopt(fOutputSocketNum, SOL_SOCKET, SO_ERROR, (char*)&err, &len) < 0 || err != 0) {
       envir().setResultErrMsg("Connection to server failed: ", err);
       if (fVerbosityLevel >= 1) envir() << "..." << envir().getResultMsg() << "\n";
       break;
diff --git a/liveMedia/RTSPClient.cpp b/liveMedia/RTSPClient.cpp
index 4c4c423..44172b7 100644
--- a/liveMedia/RTSPClient.cpp
+++ b/liveMedia/RTSPClient.cpp
@@ -29,9 +29,10 @@ RTSPClient* RTSPClient::createNew(UsageEnvironment& env, char const* rtspURL,
 				  int verbosityLevel,
 				  char const* applicationName,
 				  portNumBits tunnelOverHTTPPortNum,
-				  int socketNumToServer) {
+				  int socketNumToServer,
+				  Boolean tunnelOverHTTPS) {
   return new RTSPClient(env, rtspURL,
-			verbosityLevel, applicationName, tunnelOverHTTPPortNum, socketNumToServer);
+			verbosityLevel, applicationName, tunnelOverHTTPPortNum, socketNumToServer, tunnelOverHTTPS);
 }

 unsigned RTSPClient::sendDescribeCommand(responseHandler* responseHandler, Authenticator* authenticator) {
@@ -375,14 +376,14 @@ unsigned RTSPClient::responseBufferSize = 20000; // default value; you can reass

 RTSPClient::RTSPClient(UsageEnvironment& env, char const* rtspURL,
 		       int verbosityLevel, char const* applicationName,
-		       portNumBits tunnelOverHTTPPortNum, int socketNumToServer)
+		       portNumBits tunnelOverHTTPPortNum, int socketNumToServer, Boolean tunnelOverHTTPS)
   : Medium(env),
     desiredMaxIncomingPacketSize(0), fVerbosityLevel(verbosityLevel), fCSeq(1),
-    fAllowBasicAuthentication(True), fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum),
+    fAllowBasicAuthentication(True), fTunnelOverHTTPPortNum(tunnelOverHTTPPortNum), fTunnelOverHTTPS(tunnelOverHTTPS),
     fUserAgentHeaderStr(NULL), fUserAgentHeaderStrLen(0),
     fInputSocketNum(-1), fOutputSocketNum(-1), fBaseURL(NULL), fTCPStreamIdCount(0),
     fLastSessionId(NULL), fSessionTimeoutParameter(0), fSessionCookieCounter(0), fHTTPTunnelingConnectionIsPending(False),
-    fTLS(*this) {
+    fTLS(*this), fTLSPost(*this) {
   setBaseURL(rtspURL);

   fResponseBuffer = new char[responseBufferSize+1];
@@ -887,6 +888,7 @@ int RTSPClient::openConnection() {
     if (!parseRTSPURL(fBaseURL, username, password, destAddress, urlPortNum, &urlSuffix)) break;
     portNumBits destPortNum = fTunnelOverHTTPPortNum == 0 ? urlPortNum : fTunnelOverHTTPPortNum;
     if (destPortNum == 322) useTLS(); // port 322 is a special case: "rtsps"
+    if (fTunnelOverHTTPS) useTLS();

     if (username != NULL || password != NULL) {
       fCurrentAuthenticator.setUsernameAndPassword(username, password);
@@ -1549,6 +1551,21 @@ void RTSPClient::responseHandlerForHTTP_GET1(int responseCode, char* responseStr
     }

     // The connection succeeded.  Continue setting up RTSP-over-HTTP:
+    if (fTunnelOverHTTPS) {
+      fTLSPost.isNeeded = True;
+      // We need to complete an additional TLS connection:
+      connectResult = fTLSPost.connect(fOutputSocketNum);
+      if (connectResult < 0) break;
+      if (connectResult > 0 && fVerbosityLevel >= 1) envir() << "...TLS connection completed\n";
+      if (connectResult == 0) {
+        // The connection is still pending.  Continue deferring...
+        while ((request = fRequestsAwaitingHTTPTunneling.dequeue()) != NULL) {
+          fRequestsAwaitingConnection.enqueue(request);
+        }
+        return;
+      }
+    }
+
     if (!setupHTTPTunneling2()) break;

     // RTSP-over-HTTP tunneling succeeded.  Resume the pending request(s):
@@ -1601,21 +1618,38 @@ void RTSPClient::connectionHandler1() {
       break;
     }

-    // The connection succeeded.  If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now:
-    if (fHTTPTunnelingConnectionIsPending && !setupHTTPTunneling2()) break;
-
-    if (fTLS.isNeeded) {
-      // We need to complete an additional TLS connection:
-      int tlsConnectResult = fTLS.connect(fInputSocketNum);
-      if (tlsConnectResult < 0) break; // error in TLS connection
-      if (tlsConnectResult > 0 && fVerbosityLevel >= 1) envir() << "...TLS connection completed\n";
-      if (tlsConnectResult == 0) {
-	// The connection is still pending.  Continue deferring...
-	while ((request = tmpRequestQueue.dequeue()) != NULL) {
-	  fRequestsAwaitingConnection.enqueue(request);
-	}
-	return;
+    // The connection succeeded.
+    if (!fHTTPTunnelingConnectionIsPending) {
+      if (fTLS.isNeeded) {
+        // We need to complete an additional TLS connection:
+        int tlsConnectResult = fTLS.connect(fInputSocketNum);
+        if (tlsConnectResult < 0) break; // error in TLS connection
+        if (tlsConnectResult > 0 && fVerbosityLevel >= 1) envir() << "...TLS connection completed\n";
+        if (tlsConnectResult == 0) {
+          // The connection is still pending.  Continue deferring...
+          while ((request = tmpRequestQueue.dequeue()) != NULL) {
+            fRequestsAwaitingConnection.enqueue(request);
+          }
+          return;
+        }
       }
+    } else {
+      // If the connection came about from an attempt to set up RTSP-over-HTTP, finish this now:
+      if (fTunnelOverHTTPS) {
+        fTLSPost.isNeeded = True;
+        // We need to complete an additional TLS connection:
+        int tlsConnectResult = fTLSPost.connect(fOutputSocketNum);
+        if (tlsConnectResult < 0) break; // error in TLS connection
+        if (tlsConnectResult > 0 && fVerbosityLevel >= 1) envir() << "...TLS connection completed\n";
+        if (tlsConnectResult == 0) {
+          // The connection is still pending.  Continue deferring...
+          while ((request = tmpRequestQueue.dequeue()) != NULL) {
+            fRequestsAwaitingConnection.enqueue(request);
+          }
+          return;
+        }
+      }
+      if (!setupHTTPTunneling2()) break;
     }

     // The connection is complete.  Resume sending all pending requests:
@@ -1982,11 +2016,13 @@ void RTSPClient::handleResponseBytes(int newBytesRead) {
 }

 int RTSPClient::write(const char* data, unsigned count) {
-      if (fTLS.isNeeded) {
-	return fTLS.write(data, count);
-      } else {
-	return send(fOutputSocketNum, data, count, 0);
-      }
+  if (fTLSPost.isNeeded) {
+    return fTLSPost.write(data, count);
+  } else if (fTLS.isNeeded) {
+    return fTLS.write(data, count);
+  } else {
+    return send(fOutputSocketNum, data, count, 0);
+  }
 }

 int RTSPClient::read(u_int8_t* buffer, unsigned bufferSize) {
diff --git a/liveMedia/include/RTSPClient.hh b/liveMedia/include/RTSPClient.hh
index 7e7dcf4..a71b42f 100644
--- a/liveMedia/include/RTSPClient.hh
+++ b/liveMedia/include/RTSPClient.hh
@@ -45,12 +45,15 @@ public:
 			       int verbosityLevel = 0,
 			       char const* applicationName = NULL,
 			       portNumBits tunnelOverHTTPPortNum = 0,
-			       int socketNumToServer = -1);
+			       int socketNumToServer = -1,
+			       Boolean tunnelOverHTTPS = False);
+  // Since RTSPClient can either be created directly, or by using createNew, the default values are repeated here.
   // If "tunnelOverHTTPPortNum" is non-zero, we tunnel RTSP (and RTP)
   //     over a HTTP connection with the given port number, using the technique
   //     described in Apple's document <http://developer.apple.com/documentation/QuickTime/QTSS/Concepts/chapter_2_section_14.html>
   // If "socketNumToServer" is >= 0, then it is the socket number of an already-existing TCP connection to the server.
   //     (In this case, "rtspURL" must point to the socket's endpoint, so that it can be accessed via the socket.)
+  // If "tunnelOverHTTPS" is True, TLS connections are created.

   typedef void (responseHandler)(RTSPClient* rtspClient,
 				 int resultCode, char* resultString);
@@ -237,8 +240,11 @@ public: // Some compilers complain if this is "private:"

 protected:
   RTSPClient(UsageEnvironment& env, char const* rtspURL,
-	     int verbosityLevel, char const* applicationName, portNumBits tunnelOverHTTPPortNum, int socketNumToServer);
-      // called only by createNew();
+             int verbosityLevel = 0,
+             char const* applicationName = NULL,
+             portNumBits tunnelOverHTTPPortNum = 0,
+             int socketNumToServer = -1,
+             Boolean tunnelOverHTTPS = False);
   virtual ~RTSPClient();

   void reset();
@@ -340,6 +346,7 @@ protected:

 private:
   portNumBits fTunnelOverHTTPPortNum;
+  Boolean fTunnelOverHTTPS;
   char* fUserAgentHeaderStr;
   unsigned fUserAgentHeaderStrLen;
   int fInputSocketNum, fOutputSocketNum;
@@ -357,7 +364,7 @@ private:
   Boolean fHTTPTunnelingConnectionIsPending;

   // Optional support for TLS:
-  ClientTLSState fTLS;
+  ClientTLSState fTLS, fTLSPost;
   friend class ClientTLSState;
 };

diff --git a/testProgs/openRTSP.cpp b/testProgs/openRTSP.cpp
index ac9badd..3034080 100644
--- a/testProgs/openRTSP.cpp
+++ b/testProgs/openRTSP.cpp
@@ -26,7 +26,8 @@ along with this library; if not, write to the Free Software Foundation, Inc.,
 RTSPClient* ourRTSPClient = NULL;
 Medium* createClient(UsageEnvironment& env, char const* url, int verbosityLevel, char const* applicationName) {
   extern portNumBits tunnelOverHTTPPortNum;
-  return ourRTSPClient = RTSPClient::createNew(env, url, verbosityLevel, applicationName, tunnelOverHTTPPortNum);
+  extern Boolean tunnelOverHTTPS;
+  return ourRTSPClient = RTSPClient::createNew(env, url, verbosityLevel, applicationName, tunnelOverHTTPPortNum, -1, tunnelOverHTTPS);
 }

 void assignClient(Medium* client) {
diff --git a/testProgs/playCommon.cpp b/testProgs/playCommon.cpp
index 0316625..9f621b3 100644
--- a/testProgs/playCommon.cpp
+++ b/testProgs/playCommon.cpp
@@ -100,6 +100,8 @@ Boolean streamUsingTCP = False;
 Boolean forceMulticastOnUnspecified = False;
 unsigned short desiredPortNum = 0;
 portNumBits tunnelOverHTTPPortNum = 0;
+Boolean tunnelOverHTTP = False;
+Boolean tunnelOverHTTPS = False;
 char* username = NULL;
 char* password = NULL;
 char* proxyServerName = NULL;
@@ -135,7 +137,7 @@ struct timeval startTime;
 void usage() {
   *env << "Usage: " << progName
        << " [-p <startPortNum>] [-r|-q|-4|-i] [-a|-v] [-V] [-d <duration>] [-D <max-inter-packet-gap-time> [-c] [-S <offset>] [-n] [-O]"
-	   << (controlConnectionUsesTCP ? " [-t|-T <http-port>]" : "")
+	   << (controlConnectionUsesTCP ? " [-t|-T <http-port>|-X <https-port>]" : "")
        << " [-u <username> <password>"
 	   << (allowProxyServers ? " [<proxy-server> [<proxy-server-port>]]" : "")
        << "]" << (supportCodecSelection ? " [-A <audio-codec-rtp-payload-format-code>|-M <mime-subtype-name>]" : "")
@@ -330,6 +332,7 @@ int main(int argc, char** argv) {
 	  if (sscanf(argv[2], "%hu", &tunnelOverHTTPPortNum) == 1
 	      && tunnelOverHTTPPortNum > 0) {
 	    ++argv; --argc;
+	    tunnelOverHTTP = True;
 	    break;
 	  }
 	}
@@ -340,6 +343,25 @@ int main(int argc, char** argv) {
       break;
     }

+    case 'X': {
+      // stream RTP and RTCP over a HTTPS connection
+      if (controlConnectionUsesTCP) {
+        if (argc > 3 && argv[2][0] != '-') {
+          // The next argument is the HTTPS server port number:
+          if (sscanf(argv[2], "%hu", &tunnelOverHTTPPortNum) == 1
+              && tunnelOverHTTPPortNum > 0) {
+            ++argv; --argc;
+            tunnelOverHTTPS = True;
+            break;
+          }
+        }
+      }
+
+      // If we get here, the option was specified incorrectly:
+      usage();
+      break;
+    }
+
     case 'u': { // specify a username and password
       if (argc < 4) usage(); // there's no argv[3] (for the "password")
       username = argv[2];
@@ -593,7 +615,10 @@ int main(int argc, char** argv) {
   }
   if (tunnelOverHTTPPortNum > 0) {
     if (streamUsingTCP) {
-      *env << "The -t and -T options cannot both be used!\n";
+      *env << "The -t and -T/-X options cannot both be used!\n";
+      usage();
+    } else if (tunnelOverHTTP && tunnelOverHTTPS) {
+      *env << "The -T and -X options cannot both be used!\n";
       usage();
     } else {
       streamUsingTCP = True;
_______________________________________________
live-devel mailing list
live-devel@lists.live555.com
http://lists.live555.com/mailman/listinfo/live-devel

Reply via email to