[rtmpdump] branch master updated. 9ecf540 Add support for limelight authentication

gitolite gil at avcodec.org
Tue Oct 30 17:11:13 CET 2012


The branch, master has been updated
       via  9ecf540e4d5bdc85c17668fa7ead93cc375111ca (commit)
       via  630c8db7d1ee2889d0c26a77d95050c01caf5d5a (commit)
      from  a9282329c3be3bb95f31137867fad9920b682d6d (commit)


- Log -----------------------------------------------------------------
commit 9ecf540e4d5bdc85c17668fa7ead93cc375111ca
Author:     Björn Axelsson <bjorn.axelsson at intinor.se>
AuthorDate: Tue Mar 20 19:12:23 2012 +0200
Commit:     Howard Chu <hyc at highlandsun.com>
CommitDate: Tue Oct 30 09:10:20 2012 -0700

    Add support for limelight authentication

diff --git a/librtmp/rtmp.c b/librtmp/rtmp.c
index 391a3b4..5ea1c76 100644
--- a/librtmp/rtmp.c
+++ b/librtmp/rtmp.c
@@ -2511,6 +2511,18 @@ static void md5sum(const unsigned char *data, int len, unsigned char *out)
 #endif
 
 static const AVal av_authmod_adobe = AVC("authmod=adobe");
+static const AVal av_authmod_llnw  = AVC("authmod=llnw");
+
+static char *hexenc(unsigned char *inbuf, int len)
+{
+    char *dst = malloc(len * 2 + 1), *ptr = dst;
+    while(len--) {
+        sprintf(ptr, "%02x", *inbuf++);
+        ptr += 2;
+    }
+    *ptr = '\0';
+    return dst;
+}
 
 static int
 PublisherAuth(RTMP *r, AVal *description)
@@ -2671,6 +2683,178 @@ PublisherAuth(RTMP *r, AVal *description)
               r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
               r->Link.playpath.av_val);
     }
+  else if (strstr(description->av_val, av_authmod_llnw.av_val) != NULL)
+    {
+      if(strstr(description->av_val, "code=403 need auth") != NULL)
+        {
+            /* This part seems to be the same for llnw and adobe */
+
+            if (strstr(r->Link.app.av_val, av_authmod_llnw.av_val) != NULL) {
+              RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
+              pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8);
+              pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
+                      av_authmod_llnw.av_val,
+                      r->Link.pubUser.av_val);
+              RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
+              r->Link.pFlags |= RTMP_PUB_NAME;
+            } else {
+              RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            }
+        }
+      else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
+        {
+          char *orig_ptr;
+          char *par, *val = NULL;
+          char *user = NULL;
+          char *nonce = NULL;
+
+          ptr = orig_ptr = strdup(token_in);
+          /* Extract parameters (we need user and nonce) */
+          while (ptr)
+            {
+              par = ptr;
+              ptr = strchr(par, '&');
+              if(ptr)
+                  *ptr++ = '\0';
+
+              val =  strchr(par, '=');
+              if(val)
+                  *val++ = '\0';
+
+              if (strcmp(par, "user") == 0){
+                  user = val;
+              } else if (strcmp(par, "nonce") == 0){
+                  nonce = val;
+              }
+
+              RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
+            }
+
+          // FIXME: handle case where user==NULL or nonce==NULL
+
+          /* llnw auth method
+           * Seems to be closely based on HTTP Digest Auth:
+           *    http://tools.ietf.org/html/rfc2617
+           *    http://en.wikipedia.org/wiki/Digest_access_authentication
+           */
+
+          const char *authmod = "llnw";
+          const char *realm = "live";
+          const char *method = "publish";
+          const char *qop = "auth";
+          char *tmpbuf;
+
+          /* nc = 1..connection count (or rather, number of times cnonce has been reused) */
+          int nc = 1;
+          /* nchex = hexenc(nc) (8 hex digits according to RFC 2617) */
+          char nchex[9];
+          sprintf(nchex, "%08x", nc);
+          /* cnonce = hexenc(4 random bytes) (initialized on first connection) */
+          char cnonce[9];
+          srand( time(NULL) ); // FIXME: a lib shouldn't call srand()
+          sprintf(cnonce, "%08x", rand());
+
+          /* hash1 = hexenc(md5(user + ":" + realm + ":" + password)) */
+          tmpbuf = malloc(strlen(user) + 1 + strlen(realm) + 1 + r->Link.pubPasswd.av_len + 1);
+          sprintf(tmpbuf, "%s:%s:%s", user, realm, r->Link.pubPasswd.av_val);
+          md5sum((unsigned char*)tmpbuf, strlen(tmpbuf), md5sum_val);
+          RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, tmpbuf);
+          RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+          free(tmpbuf);
+          char *hash1 = hexenc(md5sum_val, MD5_DIGEST_LENGTH);
+
+          /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */
+          /* Extract appname + appinstance without query parameters */
+          char *apptmp = malloc(r->Link.app.av_len + 1), *qpos;
+          memcpy(apptmp, r->Link.app.av_val, r->Link.app.av_len);
+          apptmp[r->Link.app.av_len] = '\0';
+          if((qpos = strchr(apptmp, '?')))
+              *qpos = '\0';
+
+          tmpbuf = malloc(strlen(method) + 2 + strlen(apptmp) + 1);
+          sprintf(tmpbuf, "%s:/%s", method, apptmp);
+          md5sum((unsigned char*)tmpbuf, strlen(tmpbuf), md5sum_val);
+          RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, tmpbuf);
+          RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+          free(tmpbuf);
+          char *hash2 = hexenc(md5sum_val, MD5_DIGEST_LENGTH);
+
+          free(apptmp);
+
+          /* hash3 = hexenc(md5(hash1 + ":" + nonce + ":" + nchex + ":" + cnonce + ":" + qop + ":" + hash2)) */
+          tmpbuf = malloc(strlen(hash1) + 1 + strlen(nonce) + 1 + strlen(nchex) + 1 + strlen(cnonce) + 1 + strlen(qop) + 1 + strlen(hash2) + 1);
+          sprintf(tmpbuf, "%s:%s:%s:%s:%s:%s", hash1, nonce, nchex, cnonce, qop, hash2);
+          md5sum((unsigned char*)tmpbuf, strlen(tmpbuf), md5sum_val);
+          RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, tmpbuf);
+          RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+          free(tmpbuf);
+          char *hash3 = hexenc(md5sum_val, MD5_DIGEST_LENGTH);
+
+          /* pubToken = &authmod=<authmod>&user=<username>&nonce=<nonce>&cnonce=<cnonce>&nc=<nchex>&response=<hash3> */
+          /* Append nonces and response to query string which already contains
+           * user + authmod */
+          pubToken.av_val = malloc(64 + strlen(authmod) + strlen(user) + strlen(nonce) + strlen(cnonce) + strlen(nchex) + strlen(hash3));
+          sprintf(pubToken.av_val,
+                  "&nonce=%s&cnonce=%s&nc=%s&response=%s",
+                  nonce, cnonce, nchex, hash3);
+          pubToken.av_len = strlen(pubToken.av_val);
+          RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
+          r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
+
+          free(hash1);
+          free(hash2);
+          free(hash3);
+          free(orig_ptr);
+        }
+      else if(strstr(description->av_val, "?reason=authfail") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
+                  __FUNCTION__, description->av_val);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+
+      ptr = malloc(r->Link.app.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
+      strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.app.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.app.av_val);
+      r->Link.app.av_val = ptr;
+
+      ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
+      strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.tcUrl.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.tcUrl.av_val);
+      r->Link.tcUrl.av_val = ptr;
+
+      free(pubToken.av_val);
+      r->Link.pFlags |= RTMP_PUB_ALLOC;
+
+      RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
+              r->Link.app.av_len, r->Link.app.av_val,
+              r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
+              r->Link.playpath.av_val);
+    }
   else
     {
       return 0;

commit 630c8db7d1ee2889d0c26a77d95050c01caf5d5a
Author:     Martin Storsjo <martin at martin.st>
AuthorDate: Tue Oct 30 09:09:25 2012 -0700
Commit:     Howard Chu <hyc at highlandsun.com>
CommitDate: Tue Oct 30 09:09:25 2012 -0700

    Add adobe authentication support
    
    From: Sergiy <piratfm at gmail.com>
    
    To use this, add flashver=FMLE/3.0\20(compatible;\20FMSc/1.0)
    and pubUser=<username> pubUser=<password> to the RTMP url.
    
    This should both work for generic adobe authentication, and for
    publishing to akamai.

diff --git a/librtmp/rtmp.c b/librtmp/rtmp.c
index 6f6e97b..391a3b4 100644
--- a/librtmp/rtmp.c
+++ b/librtmp/rtmp.c
@@ -27,6 +27,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <assert.h>
+#include <time.h>
 
 #include "rtmp_sys.h"
 #include "log.h"
@@ -35,6 +36,9 @@
 #ifdef USE_POLARSSL
 #include <polarssl/version.h>
 #include <polarssl/havege.h>
+#include <polarssl/md5.h>
+#include <polarssl/base64.h>
+#define MD5_DIGEST_LENGTH 16
 
 static const char *my_dhm_P =
     "E4004C1F94182000103D883A448B3F80" \
@@ -50,9 +54,15 @@ static const char *my_dhm_G = "4";
 
 #elif defined(USE_GNUTLS)
 #include <gnutls/gnutls.h>
+#define MD5_DIGEST_LENGTH 16
+#include <nettle/base64.h>
+#include <nettle/md5.h>
 #else	/* USE_OPENSSL */
 #include <openssl/ssl.h>
 #include <openssl/rc4.h>
+#include <openssl/md5.h>
+#include <openssl/bio.h>
+#include <openssl/buffer.h>
 #endif
 TLS_CTX RTMP_TLS_ctx;
 #endif
@@ -595,6 +605,10 @@ static struct urlopt {
   	"Buffer time in milliseconds" },
   { AVC("timeout"),   OFF(Link.timeout),       OPT_INT, 0,
   	"Session timeout in seconds" },
+  { AVC("pubUser"),   OFF(Link.pubUser),       OPT_STR, 0,
+        "Publisher username" },
+  { AVC("pubPasswd"), OFF(Link.pubPasswd),     OPT_STR, 0,
+        "Publisher password" },
   { {NULL,0}, 0, 0}
 };
 
@@ -2433,6 +2447,239 @@ AV_clear(RTMP_METHOD *vals, int num)
   free(vals);
 }
 
+
+#ifdef CRYPTO
+static int
+b64enc(const unsigned char *input, int length, char *output, int maxsize)
+{
+#ifdef USE_POLARSSL
+  int buf_size = maxsize;
+  if(base64_encode((unsigned char *) output, &buf_size, input, length) == 0)
+    {
+      output[buf_size] = '\0';
+      return 1;
+    }
+  else
+    {
+      RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
+      return 0;
+    }
+#elif defined(USE_GNUTLS)
+  if (BASE64_ENCODE_RAW_LENGTH(length) <= maxsize)
+    base64_encode_raw((uint8_t*) output, length, input);
+  else
+    {
+      RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
+      return 0;
+    }
+#else   /* USE_OPENSSL */
+  BIO *bmem, *b64;
+  BUF_MEM *bptr;
+
+  b64 = BIO_new(BIO_f_base64());
+  bmem = BIO_new(BIO_s_mem());
+  b64 = BIO_push(b64, bmem);
+  BIO_write(b64, input, length);
+  if (BIO_flush(b64) == 1)
+    {
+      BIO_get_mem_ptr(b64, &bptr);
+      memcpy(output, bptr->data, bptr->length-1);
+      output[bptr->length-1] = '\0';
+    }
+  else
+    {
+      RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
+      return 0;
+    }
+  BIO_free_all(b64);
+#endif
+  return 1;
+}
+
+#ifdef USE_POLARSSL
+#define md5sum(x,y,z)  md5(x,y,z);
+#elif defined(USE_GNUTLS)
+static void md5sum(const unsigned char *data, int len, unsigned char *out)
+{
+    struct md5_ctx ctx;
+    md5_init(&ctx);
+    md5_update(&ctx, len, data);
+    md5_digest(&ctx, MD5_DIGEST_LENGTH, out);
+}
+#else
+#define md5sum(x,y,z)  MD5(x,y,z);
+#endif
+
+static const AVal av_authmod_adobe = AVC("authmod=adobe");
+
+static int
+PublisherAuth(RTMP *r, AVal *description)
+{
+  char *token_in = NULL;
+  char *ptr;
+  unsigned char md5sum_val[MD5_DIGEST_LENGTH+1];
+  int challenge2_data;
+#define RESPONSE_LEN 32
+#define CHALLENGE2_LEN 16
+#define SALTED2_LEN (32+8+8+8)
+  char response[RESPONSE_LEN];
+  char challenge2[CHALLENGE2_LEN];
+  char salted2[SALTED2_LEN];
+  AVal pubToken;
+
+  if (strstr(description->av_val, av_authmod_adobe.av_val) != NULL)
+    {
+      if(strstr(description->av_val, "code=403 need auth") != NULL)
+        {
+            if (strstr(r->Link.app.av_val, av_authmod_adobe.av_val) != NULL) {
+              RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
+              pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8);
+              pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
+                      av_authmod_adobe.av_val,
+                      r->Link.pubUser.av_val);
+              RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
+              r->Link.pFlags |= RTMP_PUB_NAME;
+            } else {
+              RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+              return 0;
+            }
+        }
+      else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
+        {
+          char *par, *val = NULL, *orig_ptr;
+          char *user = NULL;
+          char *salt = NULL;
+          char *opaque = NULL;
+          char *challenge = NULL;
+          char *salted1;
+
+          ptr = orig_ptr = strdup(token_in);
+          while (ptr)
+            {
+              par = ptr;
+              ptr = strchr(par, '&');
+              if(ptr)
+                  *ptr++ = '\0';
+
+              val =  strchr(par, '=');
+              if(val)
+                  *val++ = '\0';
+
+              if (strcmp(par, "user") == 0){
+                  user = val;
+              } else if (strcmp(par, "salt") == 0){
+                  salt = val;
+              } else if (strcmp(par, "opaque") == 0){
+                  opaque = val;
+              } else if (strcmp(par, "challenge") == 0){
+                  challenge = val;
+              }
+
+              RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
+            }
+
+            /* hash1 = base64enc(md5(user + _aodbeAuthSalt + password)) */
+            salted1 = malloc(strlen(user)+strlen(salt)+r->Link.pubPasswd.av_len+1);
+            strcpy(salted1, user);
+            strcat(salted1, salt);
+            strcat(salted1, r->Link.pubPasswd.av_val);
+            md5sum((unsigned char*) salted1, strlen(salted1), md5sum_val);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, salted1);
+            free(salted1);
+
+            RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+
+            b64enc(md5sum_val, MD5_DIGEST_LENGTH, salted2, SALTED2_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_1) = %s", __FUNCTION__, salted2);
+
+            srand( time(NULL) );
+            challenge2_data = rand();
+
+            b64enc((unsigned char *) &challenge2_data, sizeof(int), challenge2, CHALLENGE2_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(%d) = %s", __FUNCTION__, challenge2_data, challenge2);
+
+            /* response = base64enc(md5(hash1 + opaque + challenge2)) */
+            if (opaque)
+                strcat(salted2, opaque);
+            if (challenge)
+                strcat(salted2, challenge);
+            strcat(salted2, challenge2);
+
+            md5sum((unsigned char*) salted2, strlen(salted2), md5sum_val);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s) =>", __FUNCTION__, salted2);
+            RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
+
+            b64enc(md5sum_val, MD5_DIGEST_LENGTH, response, RESPONSE_LEN);
+            RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response);
+
+            /* have all hashes, create auth token for the end of app */
+            pubToken.av_val = malloc(32 + strlen(challenge2) + strlen(response) + (opaque ? strlen(opaque) : 0));
+            pubToken.av_len = sprintf(pubToken.av_val,
+                    "&challenge=%s&response=%s&opaque=%s",
+                    challenge2,
+                    response,
+                    opaque ? opaque : "");
+            RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
+            free(orig_ptr);
+            r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
+        }
+      else if(strstr(description->av_val, "?reason=authfailed") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: wrong password", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+      else
+        {
+          RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
+                  __FUNCTION__, description->av_val);
+          r->Link.pFlags |= RTMP_PUB_CLEAN;
+          return 0;
+        }
+
+      ptr = malloc(r->Link.app.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
+      strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.app.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.app.av_val);
+      r->Link.app.av_val = ptr;
+
+      ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
+      strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
+      strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
+      r->Link.tcUrl.av_len += pubToken.av_len;
+      if(r->Link.pFlags & RTMP_PUB_ALLOC)
+          free(r->Link.tcUrl.av_val);
+      r->Link.tcUrl.av_val = ptr;
+
+      free(pubToken.av_val);
+      r->Link.pFlags |= RTMP_PUB_ALLOC;
+
+      RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
+              r->Link.app.av_len, r->Link.app.av_val,
+              r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
+              r->Link.playpath.av_val);
+    }
+  else
+    {
+      return 0;
+    }
+  return 1;
+}
+#endif
+
+
 SAVC(onBWDone);
 SAVC(onFCSubscribe);
 SAVC(onFCUnsubscribe);
@@ -2442,6 +2689,7 @@ SAVC(_error);
 SAVC(close);
 SAVC(code);
 SAVC(level);
+SAVC(description);
 SAVC(onStatus);
 SAVC(playlist_ready);
 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
@@ -2460,6 +2708,8 @@ AVC("NetStream.Play.PublishNotify");
 static const AVal av_NetStream_Play_UnpublishNotify =
 AVC("NetStream.Play.UnpublishNotify");
 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
+static const AVal av_NetConnection_Connect_Rejected =
+AVC("NetConnection.Connect.Rejected");
 
 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
 static int
@@ -2601,12 +2851,73 @@ HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
     }
   else if (AVMATCH(&method, &av__error))
     {
+#ifdef CRYPTO
+      AVal methodInvoked = {0};
+      int i;
+
+      if (r->Link.protocol & RTMP_FEATURE_WRITE)
+        {
+          for (i=0; i<r->m_numCalls; i++)
+            {
+              if (r->m_methodCalls[i].num == txn)
+                {
+                  methodInvoked = r->m_methodCalls[i].name;
+                  AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
+                  break;
+                }
+            }
+          if (!methodInvoked.av_val)
+            {
+              RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
+                    __FUNCTION__, txn);
+              goto leave;
+            }
+
+          RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__,
+          methodInvoked.av_val);
+
+          if (AVMATCH(&methodInvoked, &av_connect))
+            {
+              AMFObject obj2;
+              AVal code, level, description;
+              AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
+              AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
+              RTMP_Log(RTMP_LOGDEBUG, "%s, error description: %s", __FUNCTION__, description.av_val);
+              /* if PublisherAuth returns 1, then reconnect */
+              PublisherAuth(r, &description);
+            }
+        }
+      else
+        {
+          RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+        }
+      free(methodInvoked.av_val);
+#else
       RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
+#endif
     }
   else if (AVMATCH(&method, &av_close))
     {
       RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
       RTMP_Close(r);
+#ifdef CRYPTO
+      if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
+              !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
+              (  !(r->Link.pFlags & RTMP_PUB_NAME) ||
+                 !(r->Link.pFlags & RTMP_PUB_RESP) ||
+                 (r->Link.pFlags & RTMP_PUB_CLATE) ) )
+        {
+          /* clean later */
+          if(r->Link.pFlags & RTMP_PUB_CLATE)
+              r->Link.pFlags |= RTMP_PUB_CLEAN;
+          RTMP_Log(RTMP_LOGERROR, "authenticating publisher");
+
+          if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
+              goto leave;
+       }
+#endif
     }
   else if (AVMATCH(&method, &av_onStatus))
     {
@@ -3695,9 +4006,6 @@ RTMP_Close(RTMP *r)
   r->m_resplen = 0;
   r->m_unackd = 0;
 
-  free(r->Link.playpath0.av_val);
-  r->Link.playpath0.av_val = NULL;
-
   if (r->Link.lFlags & RTMP_LF_FTCU)
     {
       free(r->Link.tcUrl.av_val);
@@ -3706,6 +4014,20 @@ RTMP_Close(RTMP *r)
     }
 
 #ifdef CRYPTO
+  if (!(r->Link.protocol & RTMP_FEATURE_WRITE) || (r->Link.pFlags & RTMP_PUB_CLEAN))
+    {
+      free(r->Link.playpath0.av_val);
+      r->Link.playpath0.av_val = NULL;
+    }
+  if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
+      (r->Link.pFlags & RTMP_PUB_CLEAN) &&
+      (r->Link.pFlags & RTMP_PUB_ALLOC))
+    {
+      free(r->Link.app.av_val);
+      r->Link.app.av_val = NULL;
+      free(r->Link.tcUrl.av_val);
+      r->Link.tcUrl.av_val = NULL;
+    }
   if (r->Link.dh)
     {
       MDH_free(r->Link.dh);
@@ -3721,6 +4043,9 @@ RTMP_Close(RTMP *r)
       RC4_free(r->Link.rc4keyOut);
       r->Link.rc4keyOut = NULL;
     }
+#else
+  free(r->Link.playpath0.av_val);
+  r->Link.playpath0.av_val = NULL;
 #endif
 }
 
diff --git a/librtmp/rtmp.h b/librtmp/rtmp.h
index 8cb6e45..d723070 100644
--- a/librtmp/rtmp.h
+++ b/librtmp/rtmp.h
@@ -157,6 +157,8 @@ extern "C"
     AVal subscribepath;
     AVal usherToken;
     AVal token;
+    AVal pubUser;
+    AVal pubPasswd;
     AMFObject extras;
     int edepth;
 
@@ -176,6 +178,13 @@ extern "C"
     int protocol;
     int timeout;		/* connection timeout in seconds */
 
+#define RTMP_PUB_NAME   0x0001  /* send login to server */
+#define RTMP_PUB_RESP   0x0002  /* send salted password hash */
+#define RTMP_PUB_ALLOC  0x0004  /* allocated data for new tcUrl & app */
+#define RTMP_PUB_CLEAN  0x0008  /* need to free allocated data for newer tcUrl & app at exit */
+#define RTMP_PUB_CLATE  0x0010  /* late clean tcUrl & app at exit */
+    int pFlags;
+
     unsigned short socksport;
     unsigned short port;
 

-----------------------------------------------------------------------

Summary of changes:
 librtmp/rtmp.c |  515 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-
 librtmp/rtmp.h |    9 +
 2 files changed, 521 insertions(+), 3 deletions(-)


hooks/post-receive
-- 



More information about the rtmpdump mailing list