From: hyc Date: Tue, 9 Mar 2010 07:02:55 +0000 (+0000) Subject: Preliminary support for SSL X-Git-Tag: v2.4~219 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=82519279186e65a1ba7b5a7ca5a335b8f5484cf8;p=rtmpdump Preliminary support for SSL git-svn-id: svn://svn.mplayerhq.hu/rtmpdump/trunk@316 400ebc74-4327-4243-bc38-086b20814532 --- diff --git a/Makefile b/Makefile index d9bf1f5..dd1fc1e 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ DEF=-DRTMPDUMP_VERSION=\"v2.2\" OPT=-O2 CFLAGS=-Wall $(XCFLAGS) $(INC) $(DEF) $(OPT) LDFLAGS=-Wall $(XLDFLAGS) -LIBS=-lcrypto -lz +LIBS=-lssl -lcrypto -lz THREADLIB=-lpthread LIBRTMP=librtmp/librtmp.a SLIBS=$(THREADLIB) $(LIBS) diff --git a/librtmp/Makefile b/librtmp/Makefile index a714559..234a8a9 100644 --- a/librtmp/Makefile +++ b/librtmp/Makefile @@ -16,5 +16,5 @@ librtmp.a: rtmp.o log.o amf.o hashswf.o parseurl.o log.o: log.c log.h Makefile rtmp.o: rtmp.c rtmp.h handshake.h dh.h log.h amf.h Makefile amf.o: amf.c amf.h bytes.h log.h Makefile -hashswf.o: hashswf.c http.h +hashswf.o: hashswf.c http.h rtmp.h parseurl.o: parseurl.c diff --git a/librtmp/handshake.h b/librtmp/handshake.h index 20ff82e..602c516 100644 --- a/librtmp/handshake.h +++ b/librtmp/handshake.h @@ -312,8 +312,7 @@ HandShake(RTMP * r, bool FP9HandShake) int i; int dhposClient = 0; int digestPosClient = 0; - bool encrypted = r->Link.protocol == RTMP_PROTOCOL_RTMPE - || r->Link.protocol == RTMP_PROTOCOL_RTMPTE; + bool encrypted = r->Link.protocol & RTMP_FEATURE_ENC; RC4_KEY *keyIn = 0; RC4_KEY *keyOut = 0; @@ -711,13 +710,12 @@ SHandShake(RTMP * r) if (type == 3) { encrypted = false; - r->Link.protocol = RTMP_PROTOCOL_RTMP; } else if (type == 6 || type == 8) { encrypted = true; FP9HandShake = true; - r->Link.protocol = RTMP_PROTOCOL_RTMPE; + r->Link.protocol |= RTMP_FEATURE_ENC; } else { diff --git a/librtmp/hashswf.c b/librtmp/hashswf.c index b186fef..886a9c4 100644 --- a/librtmp/hashswf.c +++ b/librtmp/hashswf.c @@ -28,11 +28,13 @@ #include "log.h" #include "http.h" +#include #include #include #include -struct info { +struct info +{ HMAC_CTX *ctx; z_stream *zs; int first; @@ -40,6 +42,9 @@ struct info { int size; }; +extern void RTMP_SSL_Init(); +extern SSL_CTX *RTMP_ssl_ctx; + #define CHUNK 16384 static size_t @@ -54,10 +59,10 @@ swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream) i->first = 0; /* compressed? */ if (!strncmp(p, "CWS", 3)) - { - *p = 'F'; - i->zlib = 1; - } + { + *p = 'F'; + i->zlib = 1; + } HMAC_Update(i->ctx, (unsigned char *)p, 8); p += 8; len -= 8; @@ -70,14 +75,15 @@ swfcrunch(void *ptr, size_t size, size_t nmemb, void *stream) i->zs->next_in = (unsigned char *)p; i->zs->avail_in = len; do - { - i->zs->avail_out = CHUNK; - i->zs->next_out = out; - inflate(i->zs, Z_NO_FLUSH); - len = CHUNK - i->zs->avail_out; - i->size += len; - HMAC_Update(i->ctx, out, len); - } while (i->zs->avail_out == 0); + { + i->zs->avail_out = CHUNK; + i->zs->next_out = out; + inflate(i->zs, Z_NO_FLUSH); + len = CHUNK - i->zs->avail_out; + i->size += len; + HMAC_Update(i->ctx, out, len); + } + while (i->zs->avail_out == 0); } else { @@ -117,13 +123,15 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) { ssl = 1; port = 443; + if (!RTMP_ssl_ctx) + RTMP_SSL_Init(); } - p1 = strchr(url+4, ':'); + p1 = strchr(url + 4, ':'); if (!p1 || strncmp(p1, "://", 3)) return HTTPRES_BAD_REQUEST; - host = p1+3; + host = p1 + 3; path = strchr(host, '/'); hlen = path - host; strncpy(hbuf, host, hlen); @@ -141,34 +149,48 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) { struct hostent *hp = gethostbyname(host); if (!hp || !hp->h_addr) - return HTTPRES_LOST_CONNECTION; + return HTTPRES_LOST_CONNECTION; sa.sin_addr = *(struct in_addr *)hp->h_addr; } sa.sin_port = htons(port); sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (sb.sb_socket < 0) return HTTPRES_LOST_CONNECTION; - i = sprintf(sb.sb_buf, "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n", - path, AGENT, host, (int)(path-url+1), url); + i = + sprintf(sb.sb_buf, + "GET %s HTTP/1.0\r\nUser-Agent: %s\r\nHost: %s\r\nReferrer: %.*s\r\n", + path, AGENT, host, (int)(path - url + 1), url); if (http->date[0]) - i += sprintf(sb.sb_buf+i, "If-Modified-Since: %s\r\n", http->date); - i += sprintf(sb.sb_buf+i, "\r\n"); + i += sprintf(sb.sb_buf + i, "If-Modified-Since: %s\r\n", http->date); + i += sprintf(sb.sb_buf + i, "\r\n"); - if (connect(sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) + if (connect + (sb.sb_socket, (struct sockaddr *)&sa, sizeof(struct sockaddr)) < 0) { ret = HTTPRES_LOST_CONNECTION; goto leave; } - send(sb.sb_socket, sb.sb_buf, i, 0); + if (ssl) + { + sb.sb_ssl = SSL_new(RTMP_ssl_ctx); + SSL_set_fd(sb.sb_ssl, sb.sb_socket); + if (SSL_connect(sb.sb_ssl) < 0) + { + Log(LOGERROR, "%s, SSL_Connect failed", __FUNCTION__); + ret = HTTPRES_LOST_CONNECTION; + goto leave; + } + } + RTMPSockBuf_Send(&sb, sb.sb_buf, i); // set timeout #define HTTP_TIMEOUT 5 SET_RCVTIMEO(tv, HTTP_TIMEOUT); if (setsockopt - (sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv))) + (sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) { Log(LOGERROR, "%s, Setting socket timeout to %ds failed!", - __FUNCTION__, HTTP_TIMEOUT); + __FUNCTION__, HTTP_TIMEOUT); } sb.sb_size = 0; @@ -185,24 +207,25 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) } p1 = strchr(sb.sb_buf, ' '); - rc = atoi(p1+1); + rc = atoi(p1 + 1); http->status = rc; - if (rc >= 300) { - if (rc == 304) - { - ret = HTTPRES_OK_NOT_MODIFIED; - goto leave; - } - else if (rc == 404) - ret = HTTPRES_NOT_FOUND; - else if (rc >= 500) - ret = HTTPRES_SERVER_ERROR; - else if (rc >= 400) - ret = HTTPRES_BAD_REQUEST; - else - ret = HTTPRES_REDIRECTED; - } + if (rc >= 300) + { + if (rc == 304) + { + ret = HTTPRES_OK_NOT_MODIFIED; + goto leave; + } + else if (rc == 404) + ret = HTTPRES_NOT_FOUND; + else if (rc >= 500) + ret = HTTPRES_SERVER_ERROR; + else if (rc >= 400) + ret = HTTPRES_BAD_REQUEST; + else + ret = HTTPRES_REDIRECTED; + } p1 = memchr(sb.sb_buf, '\n', sb.sb_size); if (!p1) @@ -210,46 +233,50 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) ret = HTTPRES_BAD_REQUEST; goto leave; } - sb.sb_start = p1+1; + sb.sb_start = p1 + 1; sb.sb_size -= sb.sb_start - sb.sb_buf; - while((p2=memchr(sb.sb_start, '\r', sb.sb_size))) + while ((p2 = memchr(sb.sb_start, '\r', sb.sb_size))) { if (*sb.sb_start == '\r') - { - sb.sb_start += 2; - sb.sb_size -= 2; - break; - } - else if (!strncasecmp(sb.sb_start, "Content-Length: ", sizeof("Content-Length: ")-1)) - { - flen = atoi(sb.sb_start+sizeof("Content-Length: ")-1); - } - else if (!strncasecmp(sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ")-1)) - { - *p2 = '\0'; - strcpy(http->date, sb.sb_start+sizeof("Last-Modified: ")-1); - } + { + sb.sb_start += 2; + sb.sb_size -= 2; + break; + } + else + if (!strncasecmp + (sb.sb_start, "Content-Length: ", sizeof("Content-Length: ") - 1)) + { + flen = atoi(sb.sb_start + sizeof("Content-Length: ") - 1); + } + else + if (!strncasecmp + (sb.sb_start, "Last-Modified: ", sizeof("Last-Modified: ") - 1)) + { + *p2 = '\0'; + strcpy(http->date, sb.sb_start + sizeof("Last-Modified: ") - 1); + } p2 += 2; - sb.sb_size -= p2-sb.sb_start; + sb.sb_size -= p2 - sb.sb_start; sb.sb_start = p2; if (sb.sb_size < 1) - { - if (RTMPSockBuf_Fill(&sb) < 1) - { - ret = HTTPRES_LOST_CONNECTION; - goto leave; - } - } + { + if (RTMPSockBuf_Fill(&sb) < 1) + { + ret = HTTPRES_LOST_CONNECTION; + goto leave; + } + } } len_known = flen > 0; while ((!len_known || flen > 0) && - (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0)) + (sb.sb_size > 0 || RTMPSockBuf_Fill(&sb) > 0)) { cb(sb.sb_start, 1, sb.sb_size, http->data); if (len_known) - flen -= sb.sb_size; + flen -= sb.sb_size; http->size += sb.sb_size; sb.sb_size = 0; } @@ -258,7 +285,7 @@ HTTP_get(struct HTTP_ctx *http, const char *url, HTTP_read_callback *cb) ret = HTTPRES_LOST_CONNECTION; leave: - closesocket(sb.sb_socket); + RTMPSockBuf_Close(&sb); return ret; } @@ -267,105 +294,111 @@ static int tzchecked; #define JAN02_1980 318340800 -static const char *monthtab[12] = {"Jan", "Feb", "Mar", - "Apr", "May", "Jun", - "Jul", "Aug", "Sep", - "Oct", "Nov", "Dec"}; -static const char *days[] = {"Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"}; +static const char *monthtab[12] = { "Jan", "Feb", "Mar", + "Apr", "May", "Jun", + "Jul", "Aug", "Sep", + "Oct", "Nov", "Dec" +}; +static const char *days[] = + { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; /* Parse an HTTP datestamp into Unix time */ static time_t make_unix_time(char *s) { - struct tm time; - int i, ysub = 1900, fmt = 0; - char *month; - char *n; - time_t res; + struct tm time; + int i, ysub = 1900, fmt = 0; + char *month; + char *n; + time_t res; - if (s[3] != ' ') + if (s[3] != ' ') { - fmt = 1; - if (s[3] != ',') - ysub = 0; + fmt = 1; + if (s[3] != ',') + ysub = 0; } - for (n = s; *n; ++n) - if (*n == '-' || *n == ':') - *n = ' '; + for (n = s; *n; ++n) + if (*n == '-' || *n == ':') + *n = ' '; - time.tm_mon = 0; - n = strchr(s, ' '); - if (fmt) + time.tm_mon = 0; + n = strchr(s, ' '); + if (fmt) { - /* Day, DD-MMM-YYYY HH:MM:SS GMT */ - time.tm_mday = strtol(n+1, &n, 0); - month = n+1; - n = strchr(month, ' '); - time.tm_year = strtol(n+1, &n, 0); - time.tm_hour = strtol(n+1, &n, 0); - time.tm_min = strtol(n+1, &n, 0); - time.tm_sec = strtol(n+1, NULL, 0); - } else + /* Day, DD-MMM-YYYY HH:MM:SS GMT */ + time.tm_mday = strtol(n + 1, &n, 0); + month = n + 1; + n = strchr(month, ' '); + time.tm_year = strtol(n + 1, &n, 0); + time.tm_hour = strtol(n + 1, &n, 0); + time.tm_min = strtol(n + 1, &n, 0); + time.tm_sec = strtol(n + 1, NULL, 0); + } + else { - /* Unix ctime() format. Does not conform to HTTP spec. */ - /* Day MMM DD HH:MM:SS YYYY */ - month = n+1; - n = strchr(month, ' '); - while (isspace(*n)) n++; - time.tm_mday = strtol(n, &n, 0); - time.tm_hour = strtol(n+1, &n, 0); - time.tm_min = strtol(n+1, &n, 0); - time.tm_sec = strtol(n+1, &n, 0); - time.tm_year = strtol(n+1, NULL, 0); + /* Unix ctime() format. Does not conform to HTTP spec. */ + /* Day MMM DD HH:MM:SS YYYY */ + month = n + 1; + n = strchr(month, ' '); + while (isspace(*n)) + n++; + time.tm_mday = strtol(n, &n, 0); + time.tm_hour = strtol(n + 1, &n, 0); + time.tm_min = strtol(n + 1, &n, 0); + time.tm_sec = strtol(n + 1, &n, 0); + time.tm_year = strtol(n + 1, NULL, 0); } - if (time.tm_year > 100) - time.tm_year -= ysub; + if (time.tm_year > 100) + time.tm_year -= ysub; - for (i = 0; i < 12; i++) - if (!strncasecmp(month, monthtab[i], 3)) - { - time.tm_mon = i; - break; - } - time.tm_isdst = 0; /* daylight saving is never in effect in GMT */ + for (i = 0; i < 12; i++) + if (!strncasecmp(month, monthtab[i], 3)) + { + time.tm_mon = i; + break; + } + time.tm_isdst = 0; /* daylight saving is never in effect in GMT */ - /* this is normally the value of extern int timezone, but some - * braindead C libraries don't provide it. - */ - if (!tzchecked) + /* this is normally the value of extern int timezone, but some + * braindead C libraries don't provide it. + */ + if (!tzchecked) { - struct tm *tc; - time_t then = JAN02_1980; - tc = localtime(&then); - tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec; - tzchecked = 1; + struct tm *tc; + time_t then = JAN02_1980; + tc = localtime(&then); + tzoff = (12 - tc->tm_hour) * 3600 + tc->tm_min * 60 + tc->tm_sec; + tzchecked = 1; } - res = mktime(&time); - /* Unfortunately, mktime() assumes the input is in local time, - * not GMT, so we have to correct it here. - */ - if (res != -1) - res += tzoff; - return res; + res = mktime(&time); + /* Unfortunately, mktime() assumes the input is in local time, + * not GMT, so we have to correct it here. + */ + if (res != -1) + res += tzoff; + return res; } /* Convert a Unix time to a network time string * Weekday, DD-MMM-YYYY HH:MM:SS GMT */ -void strtime(time_t *t, char *s) +void +strtime(time_t * t, char *s) { - struct tm *tm; + struct tm *tm; - tm = gmtime((time_t *)t); - sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT", - days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon], - tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); + tm = gmtime((time_t *) t); + sprintf(s, "%s, %02d %s %d %02d:%02d:%02d GMT", + days[tm->tm_wday], tm->tm_mday, monthtab[tm->tm_mon], + tm->tm_year + 1900, tm->tm_hour, tm->tm_min, tm->tm_sec); } #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) int -RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age) +RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, + int age) { FILE *f = NULL; char *path, *home, date[64], cctim[64]; @@ -373,10 +406,10 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age) time_t ctim = -1, cnow; int i, got = 0, ret = 0; unsigned int hlen; - struct info in = {0}; - struct HTTP_ctx http = {0}; + struct info in = { 0 }; + struct HTTP_ctx http = { 0 }; HTTPResult httpres; - z_stream zs = {0}; + z_stream zs = { 0 }; HMAC_CTX ctx; date[0] = '\0'; @@ -394,7 +427,7 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age) * These fields must be present in this order. All fields * besides URL are fixed size. */ - path=malloc(strlen(home)+sizeof("/.swfinfo")); + path = malloc(strlen(home) + sizeof("/.swfinfo")); strcpy(path, home); strcat(path, "/.swfinfo"); @@ -405,67 +438,67 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age) file = strchr(url, '/'); if (!file) - break; + break; file += 2; file = strchr(file, '/'); if (!file) - break; + break; file++; hlen = file - url; p = strrchr(file, '/'); if (p) - file = p; + file = p; else - file--; + file--; while (fgets(buf, sizeof(buf), f)) - { - char *r1; - - got = 0; - - if (strncmp(buf, "url: ", 5)) - continue; - if (strncmp(buf+5, url, hlen)) - continue; - r1 = strrchr(buf, '/'); - i = strlen(r1); - r1[--i] = '\0'; - if (strncmp(r1, file, i)) - continue; - pos = ftell(f); - while (got < 4 && fgets(buf, sizeof(buf), f)) - { - if (!strncmp(buf, "size: ", 6)) - { - *size = strtol(buf+6, NULL, 16); - got++; - } - else if (!strncmp(buf, "hash: ", 6)) - { - unsigned char *ptr = hash, *in = (unsigned char *)buf+6; - int l = strlen((char *)in)-1; - for (i=0; i 0) { ctim = cnow - ctim; - ctim /= 3600 * 24; /* seconds to days */ - if (ctim < age) /* ok, it's new enough */ - goto out; + ctim /= 3600 * 24; /* seconds to days */ + if (ctim < age) /* ok, it's new enough */ + goto out; } in.first = 1; HMAC_CTX_init(&ctx); - HMAC_Init_ex(&ctx, "Genuine Adobe Flash Player 001", 30, EVP_sha256(), NULL); + HMAC_Init_ex(&ctx, "Genuine Adobe Flash Player 001", 30, EVP_sha256(), + NULL); inflateInit(&zs); in.ctx = &ctx; in.zs = &zs; @@ -497,56 +531,56 @@ RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age) { ret = -1; if (httpres == HTTPRES_LOST_CONNECTION) - Log(LOGERROR, "%s: connection lost while downloading swfurl %s", - __FUNCTION__, url); + Log(LOGERROR, "%s: connection lost while downloading swfurl %s", + __FUNCTION__, url); else if (httpres == HTTPRES_NOT_FOUND) - Log(LOGERROR, "%s: swfurl %s not found", - __FUNCTION__, url); + Log(LOGERROR, "%s: swfurl %s not found", __FUNCTION__, url); else - Log(LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)", - __FUNCTION__, url, http.status); + Log(LOGERROR, "%s: couldn't contact swfurl %s (HTTP error %d)", + __FUNCTION__, url, http.status); } else { if (got && pos) - fseek(f, pos, SEEK_SET); + fseek(f, pos, SEEK_SET); else - { - char *q; - if (!f) - f = fopen(path, "w"); - if (!f) - { - int err = errno; - Log(LOGERROR, "%s: couldn't open %s for writing, errno %d (%s)", - __FUNCTION__, path, err, strerror(err)); - ret = -1; - goto out; - } - fseek(f, 0, SEEK_END); - q = strchr(url, '?'); - if (q) - i = q - url; - else - i = strlen(url); - - fprintf(f, "url: %.*s\n", i, url); - } + { + char *q; + if (!f) + f = fopen(path, "w"); + if (!f) + { + int err = errno; + Log(LOGERROR, + "%s: couldn't open %s for writing, errno %d (%s)", + __FUNCTION__, path, err, strerror(err)); + ret = -1; + goto out; + } + fseek(f, 0, SEEK_END); + q = strchr(url, '?'); + if (q) + i = q - url; + else + i = strlen(url); + + fprintf(f, "url: %.*s\n", i, url); + } strtime(&cnow, cctim); fprintf(f, "ctim: %s\n", cctim); if (!in.first) - { - HMAC_Final(&ctx, (unsigned char *)hash, &hlen); - *size = in.size; - - fprintf(f, "date: %s\n", date); - fprintf(f, "size: %08x\n", in.size); - fprintf(f, "hash: "); - for (i=0; i + #ifdef CRYPTO #include #endif @@ -37,6 +39,7 @@ #define RTMP_SIG_SIZE 1536 #define RTMP_LARGE_HEADER_SIZE 12 +SSL_CTX *RTMP_ssl_ctx; static const int packetSize[] = { 12, 8, 4, 1 }; bool RTMP_ctrlC; @@ -44,49 +47,54 @@ bool RTMP_ctrlC; const char RTMPProtocolStrings[][7] = { "RTMP", "RTMPT", - "RTMPS", "RTMPE", "RTMPTE", + "", + "RTMPS", + "", + "", "RTMFP" }; const char RTMPProtocolStringsLower[][7] = { "rtmp", "rtmpt", - "rtmps", "rtmpe", "rtmpte", - "rtmpfp" + "", + "rtmps", + "", + "", + "rtmfp" }; -static bool DumpMetaData(AMFObject * obj); -static bool HandShake(RTMP * r, bool FP9HandShake); -static bool SocksNegotiate(RTMP * r); - -static bool SendConnectPacket(RTMP * r, RTMPPacket *cp); -static bool SendCheckBW(RTMP * r); -static bool SendCheckBWResult(RTMP * r, double txn); -static bool SendDeleteStream(RTMP * r, double dStreamId); -static bool SendFCSubscribe(RTMP * r, AVal * subscribepath); -static bool SendPlay(RTMP * r); -static bool SendBytesReceived(RTMP * r); - -#if 0 /* unused */ -static bool SendBGHasStream(RTMP * r, double dId, AVal * playpath); -static bool SendSeek(RTMP * r, double dTime); +static bool DumpMetaData(AMFObject *obj); +static bool HandShake(RTMP *r, bool FP9HandShake); +static bool SocksNegotiate(RTMP *r); + +static bool SendConnectPacket(RTMP *r, RTMPPacket *cp); +static bool SendCheckBW(RTMP *r); +static bool SendCheckBWResult(RTMP *r, double txn); +static bool SendDeleteStream(RTMP *r, double dStreamId); +static bool SendFCSubscribe(RTMP *r, AVal *subscribepath); +static bool SendPlay(RTMP *r); +static bool SendBytesReceived(RTMP *r); + +#if 0 /* unused */ +static bool SendBGHasStream(RTMP *r, double dId, AVal *playpath); #endif -static int HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize); -static bool HandleMetadata(RTMP * r, char *body, unsigned int len); -static void HandleChangeChunkSize(RTMP * r, const RTMPPacket * packet); -static void HandleAudio(RTMP * r, const RTMPPacket * packet); -static void HandleVideo(RTMP * r, const RTMPPacket * packet); -static void HandleCtrl(RTMP * r, const RTMPPacket * packet); -static void HandleServerBW(RTMP * r, const RTMPPacket * packet); -static void HandleClientBW(RTMP * r, const RTMPPacket * packet); +static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize); +static bool HandleMetadata(RTMP *r, char *body, unsigned int len); +static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet); +static void HandleAudio(RTMP *r, const RTMPPacket *packet); +static void HandleVideo(RTMP *r, const RTMPPacket *packet); +static void HandleCtrl(RTMP *r, const RTMPPacket *packet); +static void HandleServerBW(RTMP *r, const RTMPPacket *packet); +static void HandleClientBW(RTMP *r, const RTMPPacket *packet); -static int ReadN(RTMP * r, char *buffer, int n); -static bool WriteN(RTMP * r, const char *buffer, int n); +static int ReadN(RTMP *r, char *buffer, int n); +static bool WriteN(RTMP *r, const char *buffer, int n); static void DecodeTEA(AVal *key, AVal *text); @@ -104,7 +112,7 @@ RTMP_GetTime() } void -RTMPPacket_Reset(RTMPPacket * p) +RTMPPacket_Reset(RTMPPacket *p) { p->m_headerType = 0; p->m_packetType = 0; @@ -117,9 +125,9 @@ RTMPPacket_Reset(RTMPPacket * p) } bool -RTMPPacket_Alloc(RTMPPacket * p, int nSize) +RTMPPacket_Alloc(RTMPPacket *p, int nSize) { - char *ptr = calloc(1, nSize+RTMP_MAX_HEADER_SIZE); + char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE); if (!ptr) return false; p->m_body = ptr + RTMP_MAX_HEADER_SIZE; @@ -128,28 +136,43 @@ RTMPPacket_Alloc(RTMPPacket * p, int nSize) } void -RTMPPacket_Free(RTMPPacket * p) +RTMPPacket_Free(RTMPPacket *p) { if (p->m_body) { - free(p->m_body-RTMP_MAX_HEADER_SIZE); + free(p->m_body - RTMP_MAX_HEADER_SIZE); p->m_body = NULL; } } void -RTMPPacket_Dump(RTMPPacket * p) +RTMPPacket_Dump(RTMPPacket *p) { Log(LOGDEBUG, "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %lu. body: 0x%02x", p->m_packetType, p->m_nChannel, p->m_nInfoField1, p->m_nInfoField2, - p->m_nBodySize, p->m_body ? (unsigned char) p->m_body[0] : 0); + p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0); +} + +void +RTMP_SSL_Init() +{ + SSL_load_error_strings(); + SSL_library_init(); + OpenSSL_add_all_digests(); + RTMP_ssl_ctx = SSL_CTX_new(SSLv23_method()); + SSL_CTX_set_options(RTMP_ssl_ctx, SSL_OP_ALL); + SSL_CTX_set_default_verify_paths(RTMP_ssl_ctx); } void -RTMP_Init(RTMP * r) +RTMP_Init(RTMP *r) { int i; + + if (!RTMP_ssl_ctx) + RTMP_SSL_Init(); + for (i = 0; i < RTMP_CHANNELS; i++) { r->m_vecChannelsIn[i] = NULL; @@ -169,31 +192,31 @@ RTMP_Init(RTMP * r) } double -RTMP_GetDuration(RTMP * r) +RTMP_GetDuration(RTMP *r) { return r->m_fDuration; } bool -RTMP_IsConnected(RTMP * r) +RTMP_IsConnected(RTMP *r) { return r->m_sb.sb_socket != -1; } bool -RTMP_IsTimedout(RTMP * r) +RTMP_IsTimedout(RTMP *r) { return r->m_sb.sb_timedout; } void -RTMP_SetBufferMS(RTMP * r, int size) +RTMP_SetBufferMS(RTMP *r, int size) { r->m_nBufferMS = size; } void -RTMP_UpdateBufferMS(RTMP * r) +RTMP_UpdateBufferMS(RTMP *r) { RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); } @@ -211,28 +234,29 @@ RTMP_UpdateBufferMS(RTMP * r) #define OSS "GNU" #endif static const char DEFAULT_FLASH_VER[] = OSS " 10,0,32,18"; -const AVal RTMP_DefaultFlashVer = {(char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER)-1}; +const AVal RTMP_DefaultFlashVer = + { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 }; void -RTMP_SetupStream(RTMP * r, +RTMP_SetupStream(RTMP *r, int protocol, const char *hostname, unsigned int port, const char *sockshost, - AVal * playpath, - AVal * tcUrl, - AVal * swfUrl, - AVal * pageUrl, - AVal * app, - AVal * auth, - AVal * swfSHA256Hash, + AVal *playpath, + AVal *tcUrl, + AVal *swfUrl, + AVal *pageUrl, + AVal *app, + AVal *auth, + AVal *swfSHA256Hash, uint32_t swfSize, - AVal * flashVer, - AVal * subscribepath, + AVal *flashVer, + AVal *subscribepath, double dTime, uint32_t dLength, bool bLiveStream, long int timeout) { - assert(protocol < 6); + assert(protocol < 9); Log(LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol]); Log(LOGDEBUG, "Hostname : %s", hostname); @@ -254,9 +278,9 @@ RTMP_SetupStream(RTMP * r, if (flashVer && flashVer->av_val) Log(LOGDEBUG, "flashVer : %s", flashVer->av_val); if (dTime > 0) - Log(LOGDEBUG, "SeekTime : %.3f sec", (double) dTime / 1000.0); + Log(LOGDEBUG, "SeekTime : %.3f sec", (double)dTime / 1000.0); if (dLength > 0) - Log(LOGDEBUG, "playLength : %.3f sec", (double) dLength / 1000.0); + Log(LOGDEBUG, "playLength : %.3f sec", (double)dLength / 1000.0); Log(LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no"); Log(LOGDEBUG, "timeout : %d sec", timeout); @@ -339,7 +363,7 @@ add_addr_info(struct sockaddr_in *service, const char *hostname, int port) Log(LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname); return false; } - service->sin_addr = *(struct in_addr *) host->h_addr; + service->sin_addr = *(struct in_addr *)host->h_addr; } service->sin_port = htons(port); @@ -347,7 +371,7 @@ add_addr_info(struct sockaddr_in *service, const char *hostname, int port) } bool -RTMP_Connect0(RTMP *r, struct sockaddr *service) +RTMP_Connect0(RTMP *r, struct sockaddr * service) { // close any previous connection RTMP_Close(r); @@ -359,12 +383,11 @@ RTMP_Connect0(RTMP *r, struct sockaddr *service) r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); if (r->m_sb.sb_socket != -1) { - if (connect - (r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0) + if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0) { int err = GetSockError(); - Log(LOGERROR, "%s, failed to connect socket. %d (%s)", __FUNCTION__, - err, strerror(err)); + Log(LOGERROR, "%s, failed to connect socket. %d (%s)", + __FUNCTION__, err, strerror(err)); RTMP_Close(r); return false; } @@ -390,10 +413,10 @@ RTMP_Connect0(RTMP *r, struct sockaddr *service) // set timeout SET_RCVTIMEO(tv, r->Link.timeout); if (setsockopt - (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *) &tv, sizeof(tv))) + (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv))) { Log(LOGERROR, "%s, Setting socket timeout to %ds failed!", - __FUNCTION__, r->Link.timeout); + __FUNCTION__, r->Link.timeout); } int on = 1; @@ -405,6 +428,17 @@ RTMP_Connect0(RTMP *r, struct sockaddr *service) bool RTMP_Connect1(RTMP *r, RTMPPacket *cp) { + if (r->Link.protocol & RTMP_FEATURE_SSL) + { + r->m_sb.sb_ssl = SSL_new(RTMP_ssl_ctx); + SSL_set_fd(r->m_sb.sb_ssl, r->m_sb.sb_socket); + if (SSL_connect(r->m_sb.sb_ssl) < 0) + { + Log(LOGERROR, "%s, SSL_Connect failed", __FUNCTION__); + RTMP_Close(r); + return false; + } + } Log(LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__); if (!HandShake(r, true)) { @@ -455,7 +489,7 @@ RTMP_Connect(RTMP *r, RTMPPacket *cp) } static bool -SocksNegotiate(RTMP * r) +SocksNegotiate(RTMP *r) { struct sockaddr_in service; memset(&service, 0, sizeof(struct sockaddr_in)); @@ -467,8 +501,8 @@ SocksNegotiate(RTMP * r) 4, 1, // SOCKS 4, connect (r->Link.port >> 8) & 0xFF, (r->Link.port) & 0xFF, - (char) (addr >> 24) & 0xFF, (char) (addr >> 16) & 0xFF, - (char) (addr >> 8) & 0xFF, (char) addr & 0xFF, + (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF, + (char)(addr >> 8) & 0xFF, (char)addr & 0xFF, 0 }; // NULL terminate @@ -489,7 +523,7 @@ SocksNegotiate(RTMP * r) } bool -RTMP_ConnectStream(RTMP * r, double seekTime, uint32_t dLength) +RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength) { RTMPPacket packet = { 0 }; if (seekTime >= -2.0) @@ -524,7 +558,7 @@ RTMP_ConnectStream(RTMP * r, double seekTime, uint32_t dLength) } bool -RTMP_ReconnectStream(RTMP * r, int bufferTime, double seekTime, +RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime, uint32_t dLength) { RTMP_DeleteStream(r); @@ -537,25 +571,26 @@ RTMP_ReconnectStream(RTMP * r, int bufferTime, double seekTime, } bool -RTMP_ToggleStream(RTMP * r) +RTMP_ToggleStream(RTMP *r) { bool res; - if (!r->m_pausing) { - res = RTMP_SendPause(r, true, r->m_pauseStamp); - if (!res) - return res; + if (!r->m_pausing) + { + res = RTMP_SendPause(r, true, r->m_pauseStamp); + if (!res) + return res; - r->m_pausing = 1; - sleep(1); - } + r->m_pausing = 1; + sleep(1); + } res = RTMP_SendPause(r, false, r->m_pauseStamp); r->m_pausing = 3; return res; } void -RTMP_DeleteStream(RTMP * r) +RTMP_DeleteStream(RTMP *r) { if (r->m_stream_id < 0) return; @@ -566,11 +601,12 @@ RTMP_DeleteStream(RTMP * r) } int -RTMP_GetNextMediaPacket(RTMP * r, RTMPPacket * packet) +RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet) { int bHasMediaPacket = 0; - while (!bHasMediaPacket && RTMP_IsConnected(r) && RTMP_ReadPacket(r, packet)) + while (!bHasMediaPacket && RTMP_IsConnected(r) + && RTMP_ReadPacket(r, packet)) { if (!RTMPPacket_IsReady(packet)) { @@ -610,7 +646,7 @@ RTMP_GetNextMediaPacket(RTMP * r, RTMPPacket * packet) } int -RTMP_ClientPacket(RTMP * r, RTMPPacket * packet) +RTMP_ClientPacket(RTMP *r, RTMPPacket *packet) { int bHasMediaPacket = 0; switch (packet->m_packetType) @@ -676,7 +712,8 @@ RTMP_ClientPacket(RTMP * r, RTMPPacket * packet) case 0x11: // flex message { - Log(LOGDEBUG, "%s, flex message, size %lu bytes, not fully supported", + Log(LOGDEBUG, + "%s, flex message, size %lu bytes, not fully supported", __FUNCTION__, packet->m_nBodySize); //LogHex(packet.m_body, packet.m_nBodySize); @@ -768,7 +805,7 @@ extern FILE *netstackdump_read; #endif static int -ReadN(RTMP * r, char *buffer, int n) +ReadN(RTMP *r, char *buffer, int n) { int nOriginalSize = n; char *ptr; @@ -784,7 +821,7 @@ ReadN(RTMP * r, char *buffer, int n) { int nBytes = 0, nRead; if (r->m_sb.sb_size == 0) - if (RTMPSockBuf_Fill(&r->m_sb)<1) + if (RTMPSockBuf_Fill(&r->m_sb) < 1) { if (!r->m_sb.sb_timedout) RTMP_Close(r); @@ -798,7 +835,8 @@ ReadN(RTMP * r, char *buffer, int n) r->m_sb.sb_size -= nRead; nBytes = nRead; r->m_nBytesIn += nRead; - if (r->m_bSendCounter && r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2) + if (r->m_bSendCounter + && r->m_nBytesIn > r->m_nBytesInSent + r->m_nClientBW / 2) SendBytesReceived(r); } @@ -830,7 +868,7 @@ ReadN(RTMP * r, char *buffer, int n) } static bool -WriteN(RTMP * r, const char *buffer, int n) +WriteN(RTMP *r, const char *buffer, int n) { const char *ptr = buffer; #ifdef CRYPTO @@ -840,9 +878,9 @@ WriteN(RTMP * r, const char *buffer, int n) if (r->Link.rc4keyOut) { if (n > sizeof(buf)) - encrypted = (char *) malloc(n); + encrypted = (char *)malloc(n); else - encrypted = (char *) buf; + encrypted = (char *)buf; ptr = encrypted; RC4(r->Link.rc4keyOut, n, (uint8_t *) buffer, (uint8_t *) ptr); } @@ -850,11 +888,7 @@ WriteN(RTMP * r, const char *buffer, int n) while (n > 0) { -#ifdef _DEBUG - fwrite(ptr, 1, n, netstackdump); -#endif - - int nBytes = send(r->m_sb.sb_socket, ptr, n, 0); + int nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n); //Log(LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); if (nBytes < 0) @@ -907,7 +941,7 @@ static bool SendConnectPacket(RTMP *r, RTMPPacket *cp) { RTMPPacket packet; - char pbuf[4096], *pend = pbuf+sizeof(pbuf); + char pbuf[4096], *pend = pbuf + sizeof(pbuf); if (cp) return RTMP_SendPacket(r, cp, true); @@ -929,25 +963,25 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) { enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app); if (!enc) - return false; + return false; } if (r->Link.flashVer.av_len) { enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer); if (!enc) - return false; + return false; } if (r->Link.swfUrl.av_len) { enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl); if (!enc) - return false; + return false; } if (r->Link.tcUrl.av_len) { enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl); if (!enc) - return false; + return false; } enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, false); if (!enc) @@ -968,15 +1002,15 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) { enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl); if (!enc) - return false; + return false; } if (r->m_fEncoding != 0.0 || r->m_bSendEncoding) { enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding); // AMF0, AMF3 not supported yet if (!enc) - return false; + return false; } - if (enc+3 >= pend) + if (enc + 3 >= pend) return false; *enc++ = 0; *enc++ = 0; // end of object - 0x00 0x00 0x09 @@ -987,34 +1021,34 @@ SendConnectPacket(RTMP *r, RTMPPacket *cp) { enc = AMF_EncodeBoolean(enc, pend, r->Link.authflag); if (!enc) - return false; + return false; enc = AMF_EncodeString(enc, pend, &r->Link.auth); if (!enc) - return false; + return false; } if (r->Link.extras.o_num) { int i; - for (i=0; i < r->Link.extras.o_num; i++) - { - enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend); - if (!enc) - return false; - } + for (i = 0; i < r->Link.extras.o_num; i++) + { + enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend); + if (!enc) + return false; + } } packet.m_nBodySize = enc - packet.m_body; return RTMP_SendPacket(r, &packet, true); } -#if 0 /* unused */ +#if 0 /* unused */ SAVC(bgHasStream); static bool -SendBGHasStream(RTMP * r, double dId, AVal * playpath) +SendBGHasStream(RTMP *r, double dId, AVal *playpath) { RTMPPacket packet; - char pbuf[1024], *pend = pbuf+sizeof(pbuf); + char pbuf[1024], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1042,10 +1076,10 @@ SendBGHasStream(RTMP * r, double dId, AVal * playpath) SAVC(createStream); bool -RTMP_SendCreateStream(RTMP * r, double dCmdID) +RTMP_SendCreateStream(RTMP *r, double dCmdID) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1068,10 +1102,10 @@ RTMP_SendCreateStream(RTMP * r, double dCmdID) SAVC(FCSubscribe); static bool -SendFCSubscribe(RTMP * r, AVal * subscribepath) +SendFCSubscribe(RTMP *r, AVal *subscribepath) { RTMPPacket packet; - char pbuf[512], *pend = pbuf+sizeof(pbuf); + char pbuf[512], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = 0x14; // INVOKE @@ -1098,10 +1132,10 @@ SendFCSubscribe(RTMP * r, AVal * subscribepath) SAVC(deleteStream); static bool -SendDeleteStream(RTMP * r, double dStreamId) +SendDeleteStream(RTMP *r, double dStreamId) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1126,10 +1160,10 @@ SendDeleteStream(RTMP * r, double dStreamId) SAVC(pause); bool -RTMP_SendPause(RTMP * r, bool DoPause, double dTime) +RTMP_SendPause(RTMP *r, bool DoPause, double dTime) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x08; // video channel packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1144,21 +1178,21 @@ RTMP_SendPause(RTMP * r, bool DoPause, double dTime) enc = AMF_EncodeNumber(enc, pend, 0); *enc++ = AMF_NULL; enc = AMF_EncodeBoolean(enc, pend, DoPause); - enc = AMF_EncodeNumber(enc, pend, (double) dTime); + enc = AMF_EncodeNumber(enc, pend, (double)dTime); packet.m_nBodySize = enc - packet.m_body; - Log(LOGDEBUG, "%s, %d, pauseTime=%.2f", - __FUNCTION__, DoPause, dTime); + Log(LOGDEBUG, "%s, %d, pauseTime=%.2f", __FUNCTION__, DoPause, dTime); return RTMP_SendPacket(r, &packet, true); } SAVC(seek); -bool RTMP_SendSeek(RTMP * r, double dTime) +bool +RTMP_SendSeek(RTMP *r, double dTime) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x08; // video channel packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1180,10 +1214,10 @@ bool RTMP_SendSeek(RTMP * r, double dTime) } bool -RTMP_SendServerBW(RTMP * r) +RTMP_SendServerBW(RTMP *r) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x02; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_LARGE; @@ -1200,10 +1234,10 @@ RTMP_SendServerBW(RTMP * r) } static bool -SendBytesReceived(RTMP * r) +SendBytesReceived(RTMP *r) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x02; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1225,15 +1259,15 @@ SendBytesReceived(RTMP * r) SAVC(_checkbw); static bool -SendCheckBW(RTMP * r) +SendCheckBW(RTMP *r) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_LARGE; packet.m_packetType = 0x14; // INVOKE - packet.m_nInfoField1 = 0; /* RTMP_GetTime(); */ + packet.m_nInfoField1 = 0; /* RTMP_GetTime(); */ packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; @@ -1252,10 +1286,10 @@ SendCheckBW(RTMP * r) SAVC(_result); static bool -SendCheckBWResult(RTMP * r, double txn) +SendCheckBWResult(RTMP *r, double txn) { RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; // control channel (invoke) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1269,7 +1303,7 @@ SendCheckBWResult(RTMP * r, double txn) enc = AMF_EncodeString(enc, pend, &av__result); enc = AMF_EncodeNumber(enc, pend, txn); *enc++ = AMF_NULL; - enc = AMF_EncodeNumber(enc, pend, (double) r->m_nBWCheckCounter++); + enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++); packet.m_nBodySize = enc - packet.m_body; @@ -1279,10 +1313,10 @@ SendCheckBWResult(RTMP * r, double txn) SAVC(play); static bool -SendPlay(RTMP * r) +SendPlay(RTMP *r) { RTMPPacket packet; - char pbuf[1024], *pend = pbuf+sizeof(pbuf); + char pbuf[1024], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x08; // we make 8 our stream channel packet.m_headerType = RTMP_PACKET_SIZE_LARGE; @@ -1331,7 +1365,7 @@ SendPlay(RTMP * r) { enc = AMF_EncodeNumber(enc, pend, r->Link.length); // len if (!enc) - return false; + return false; } packet.m_nBodySize = enc - packet.m_body; @@ -1343,7 +1377,7 @@ static bool SendSecureTokenResponse(RTMP *r, AVal *resp) { RTMPPacket packet; - char pbuf[1024], *pend = pbuf+sizeof(pbuf); + char pbuf[1024], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x03; /* control channel (invoke) */ packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; @@ -1383,17 +1417,17 @@ The type of Ping packet is 0x4 and contains two mandatory parameters and two opt * type 27: SWFVerification response */ bool -RTMP_SendCtrl(RTMP * r, short nType, unsigned int nObject, unsigned int nTime) +RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime) { - Log(LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short) nType); + Log(LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType); RTMPPacket packet; - char pbuf[256], *pend = pbuf+sizeof(pbuf); + char pbuf[256], *pend = pbuf + sizeof(pbuf); packet.m_nChannel = 0x02; // control channel (ping) packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM; packet.m_packetType = 0x04; // ctrl - packet.m_nInfoField1 = 0; /* RTMP_GetTime(); */ + packet.m_nInfoField1 = 0; /* RTMP_GetTime(); */ packet.m_nInfoField2 = 0; packet.m_hasAbsTimestamp = 0; packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE; @@ -1428,7 +1462,7 @@ RTMP_SendCtrl(RTMP * r, short nType, unsigned int nObject, unsigned int nTime) } static void -AV_erase(AVal * vals, int *num, int i, bool freeit) +AV_erase(AVal *vals, int *num, int i, bool freeit) { if (freeit) free(vals[i].av_val); @@ -1448,7 +1482,7 @@ RTMP_DropRequest(RTMP *r, int i, bool freeit) } static void -AV_queue(AVal ** vals, int *num, AVal * av) +AV_queue(AVal **vals, int *num, AVal *av) { char *tmp; if (!(*num & 0x0f)) @@ -1461,7 +1495,7 @@ AV_queue(AVal ** vals, int *num, AVal * av) } static void -AV_clear(AVal * vals, int num) +AV_clear(AVal *vals, int num) { int i; for (i = 0; i < num; i++) @@ -1491,7 +1525,7 @@ static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop"); // Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' static int -HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize) +HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize) { int ret = 0, nRes; if (body[0] != 0x02) // make sure it is a string method name we start with @@ -1525,15 +1559,15 @@ HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize) if (AVMATCH(&methodInvoked, &av_connect)) { - if (r->Link.token.av_len) - { - AMFObjectProperty p; - if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p)) - { - DecodeTEA(&r->Link.token, &p.p_vu.p_aval); - SendSecureTokenResponse(r, &p.p_vu.p_aval); - } - } + if (r->Link.token.av_len) + { + AMFObjectProperty p; + if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p)) + { + DecodeTEA(&r->Link.token, &p.p_vu.p_aval); + SendSecureTokenResponse(r, &p.p_vu.p_aval); + } + } RTMP_SendServerBW(r); RTMP_SendCtrl(r, 3, 0, 300); @@ -1547,8 +1581,7 @@ HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize) } else if (AVMATCH(&methodInvoked, &av_createStream)) { - r->m_stream_id = - (int) AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); + r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3)); SendPlay(r); RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS); @@ -1645,7 +1678,7 @@ HandleInvoke(RTMP * r, const char *body, unsigned int nBodySize) } bool -RTMP_FindFirstMatchingProperty(AMFObject * obj, const AVal * name, +RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, AMFObjectProperty * p) { int n; @@ -1663,14 +1696,14 @@ RTMP_FindFirstMatchingProperty(AMFObject * obj, const AVal * name, if (prop->p_type == AMF_OBJECT) { if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p)) - return true; + return true; } } return false; } static bool -DumpMetaData(AMFObject * obj) +DumpMetaData(AMFObject *obj) { AMFObjectProperty *prop; int n; @@ -1698,7 +1731,7 @@ DumpMetaData(AMFObject * obj) break; default: snprintf(str, 255, "INVALID TYPE 0x%02x", - (unsigned char) prop->p_type); + (unsigned char)prop->p_type); } if (prop->p_name.av_len) { @@ -1723,7 +1756,7 @@ SAVC(onMetaData); SAVC(duration); static bool -HandleMetadata(RTMP * r, char *body, unsigned int len) +HandleMetadata(RTMP *r, char *body, unsigned int len) { // allright we get some info here, so parse it and print it // also keep duration or filesize to make a nice progress bar @@ -1760,7 +1793,7 @@ HandleMetadata(RTMP * r, char *body, unsigned int len) } static void -HandleChangeChunkSize(RTMP * r, const RTMPPacket * packet) +HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet) { if (packet->m_nBodySize >= 4) { @@ -1771,17 +1804,17 @@ HandleChangeChunkSize(RTMP * r, const RTMPPacket * packet) } static void -HandleAudio(RTMP * r, const RTMPPacket * packet) +HandleAudio(RTMP *r, const RTMPPacket *packet) { } static void -HandleVideo(RTMP * r, const RTMPPacket * packet) +HandleVideo(RTMP *r, const RTMPPacket *packet) { } static void -HandleCtrl(RTMP * r, const RTMPPacket * packet) +HandleCtrl(RTMP *r, const RTMPPacket *packet) { short nType = -1; unsigned int tmp; @@ -1826,7 +1859,8 @@ HandleCtrl(RTMP * r, const RTMPPacket * packet) case 31: tmp = AMF_DecodeInt32(packet->m_body + 2); Log(LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp); - if (r->Link.bLiveStream) break; + if (r->Link.bLiveStream) + break; if (!r->m_pausing) { r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel]; @@ -1872,21 +1906,21 @@ HandleCtrl(RTMP * r, const RTMPPacket * packet) } #else Log(LOGERROR, - "%s: Ignoring SWFVerification request, no CRYPTO support!", - __FUNCTION__); + "%s: Ignoring SWFVerification request, no CRYPTO support!", + __FUNCTION__); #endif } } static void -HandleServerBW(RTMP * r, const RTMPPacket * packet) +HandleServerBW(RTMP *r, const RTMPPacket *packet) { r->m_nServerBW = AMF_DecodeInt32(packet->m_body); Log(LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW); } static void -HandleClientBW(RTMP * r, const RTMPPacket * packet) +HandleClientBW(RTMP *r, const RTMPPacket *packet) { r->m_nClientBW = AMF_DecodeInt32(packet->m_body); if (packet->m_nBodySize > 4) @@ -1921,7 +1955,7 @@ EncodeInt32LE(char *output, int nVal) } bool -RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) +RTMP_ReadPacket(RTMP *r, RTMPPacket *packet) { char hbuf[RTMP_MAX_HEADER_SIZE] = { 0 }, *header = hbuf; @@ -1944,7 +1978,7 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) __FUNCTION__); return false; } - packet->m_nChannel = (unsigned) hbuf[1]; + packet->m_nChannel = (unsigned)hbuf[1]; packet->m_nChannel += 64; header++; } @@ -1957,7 +1991,7 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) __FUNCTION__); return false; } - tmp = (((unsigned) hbuf[2]) << 8) + (unsigned) hbuf[1]; + tmp = (((unsigned)hbuf[2]) << 8) + (unsigned)hbuf[1]; packet->m_nChannel = tmp + 64; Log(LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel); header += 2; @@ -1980,11 +2014,11 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) if (nSize > 0 && ReadN(r, header, nSize) != nSize) { Log(LOGERROR, "%s, failed to read RTMP packet header. type: %x", - __FUNCTION__, (unsigned int) hbuf[0]); + __FUNCTION__, (unsigned int)hbuf[0]); return false; } - hSize = nSize+(header-hbuf); + hSize = nSize + (header - hbuf); if (nSize >= 3) { @@ -2007,16 +2041,16 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) } } if (packet->m_nInfoField1 == 0xffffff) - { - if (ReadN(r, header+nSize, 4) != 4) - { - Log(LOGERROR, "%s, failed to read extended timestamp", - __FUNCTION__); - return false; - } - packet->m_nInfoField1 = AMF_DecodeInt32(header+nSize); - hSize += 4; - } + { + if (ReadN(r, header + nSize, 4) != 4) + { + Log(LOGERROR, "%s, failed to read extended timestamp", + __FUNCTION__); + return false; + } + packet->m_nInfoField1 = AMF_DecodeInt32(header + nSize); + hSize += 4; + } } LogHexString(LOGDEBUG2, hbuf, hSize); @@ -2043,7 +2077,7 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) { packet->m_chunk->c_headerSize = hSize; memcpy(packet->m_chunk->c_header, hbuf, hSize); - packet->m_chunk->c_chunk = packet->m_body+packet->m_nBytesRead; + packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead; packet->m_chunk->c_chunkSize = nChunk; } @@ -2054,7 +2088,7 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) return false; } - LogHexString(LOGDEBUG2, packet->m_body+packet->m_nBytesRead, nChunk); + LogHexString(LOGDEBUG2, packet->m_body + packet->m_nBytesRead, nChunk); packet->m_nBytesRead += nChunk; @@ -2091,10 +2125,10 @@ RTMP_ReadPacket(RTMP * r, RTMPPacket * packet) #include "handshake.h" #else static bool -HandShake(RTMP * r, bool FP9HandShake) +HandShake(RTMP *r, bool FP9HandShake) { int i; - char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf+1; + char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1; char serversig[RTMP_SIG_SIZE]; clientbuf[0] = 0x03; // not encrypted @@ -2109,7 +2143,7 @@ HandShake(RTMP * r, bool FP9HandShake) clientsig[i] = 0xff; #else for (i = 8; i < RTMP_SIG_SIZE; i++) - clientsig[i] = (char) (rand() % 256); + clientsig[i] = (char)(rand() % 256); #endif if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1)) @@ -2135,8 +2169,8 @@ HandShake(RTMP * r, bool FP9HandShake) suptime = ntohl(suptime); Log(LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime); - Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, serversig[4], - serversig[5], serversig[6], serversig[7]); + Log(LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__, + serversig[4], serversig[5], serversig[6], serversig[7]); // 2nd part of handshake if (!WriteN(r, serversig, RTMP_SIG_SIZE)) @@ -2154,10 +2188,10 @@ HandShake(RTMP * r, bool FP9HandShake) } static bool -SHandShake(RTMP * r) +SHandShake(RTMP *r) { int i; - char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf+1; + char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1; char clientsig[RTMP_SIG_SIZE]; uint32_t uptime; @@ -2182,7 +2216,7 @@ SHandShake(RTMP * r) serversig[i] = 0xff; #else for (i = 8; i < RTMP_SIG_SIZE; i++) - serversig[i] = (char) (rand() % 256); + serversig[i] = (char)(rand() % 256); #endif if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1)) @@ -2197,8 +2231,8 @@ SHandShake(RTMP * r) uptime = ntohl(uptime); Log(LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime); - Log(LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__, clientsig[4], - clientsig[5], clientsig[6], clientsig[7]); + Log(LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__, + clientsig[4], clientsig[5], clientsig[6], clientsig[7]); // 2nd part of handshake if (!WriteN(r, clientsig, RTMP_SIG_SIZE)) @@ -2222,7 +2256,8 @@ RTMP_SendChunk(RTMP *r, RTMPChunk *chunk) bool wrote; char hbuf[RTMP_MAX_HEADER_SIZE]; - Log(LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket, chunk->c_chunkSize); + Log(LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket, + chunk->c_chunkSize); LogHexString(LOGDEBUG2, chunk->c_header, chunk->c_headerSize); if (chunk->c_chunkSize) { @@ -2240,7 +2275,7 @@ RTMP_SendChunk(RTMP *r, RTMPChunk *chunk) } bool -RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) +RTMP_SendPacket(RTMP *r, RTMPPacket *packet, bool queue) { const RTMPPacket *prevPacket = r->m_vecChannelsOut[packet->m_nChannel]; if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE) @@ -2259,7 +2294,7 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) if (packet->m_headerType > 3) // sanity { Log(LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.", - (unsigned char) packet->m_headerType); + (unsigned char)packet->m_headerType); return false; } @@ -2274,8 +2309,8 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) } else { - header = hbuf+6; - hend = hbuf+sizeof(hbuf); + header = hbuf + 6; + hend = hbuf + sizeof(hbuf); } if (packet->m_nChannel > 319) @@ -2296,7 +2331,7 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) hptr = header; c = packet->m_headerType << 6; - switch(cSize) + switch (cSize) { case 0: c |= packet->m_nChannel; @@ -2313,14 +2348,14 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) int tmp = packet->m_nChannel - 64; *hptr++ = tmp & 0xff; if (cSize == 2) - *hptr++ = tmp >> 8; + *hptr++ = tmp >> 8; } if (nSize > 1) { uint32_t t = packet->m_nInfoField1; if (t > 0xffffff) - t = 0xffffff; + t = 0xffffff; hptr = AMF_EncodeInt24(hptr, hend, t); } @@ -2340,8 +2375,9 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) char *buffer = packet->m_body; int nChunkSize = r->m_outChunkSize; - Log(LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket, nSize); - while (nSize+hSize) + Log(LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket, + nSize); + while (nSize + hSize) { int wrote; @@ -2350,15 +2386,15 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) if (header) { - LogHexString(LOGDEBUG2, header, hSize); - LogHexString(LOGDEBUG2, buffer, nChunkSize); + LogHexString(LOGDEBUG2, header, hSize); + LogHexString(LOGDEBUG2, buffer, nChunkSize); wrote = WriteN(r, header, nChunkSize + hSize); header = NULL; - hSize = 0; + hSize = 0; } else { - LogHexString(LOGDEBUG2, buffer, nChunkSize); + LogHexString(LOGDEBUG2, buffer, nChunkSize); wrote = WriteN(r, buffer, nChunkSize); } if (!wrote) @@ -2371,19 +2407,19 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) { header = buffer - 1; hSize = 1; - if (cSize) - { - header -= cSize; - hSize += cSize; - } + if (cSize) + { + header -= cSize; + hSize += cSize; + } *header = (0xc0 | c); - if (cSize) - { - int tmp = packet->m_nChannel - 64; - header[1] = tmp & 0xff; - if (cSize == 2) - header[2] = tmp >> 8; - } + if (cSize) + { + int tmp = packet->m_nChannel - 64; + header[1] = tmp & 0xff; + if (cSize == 2) + header[2] = tmp >> 8; + } } } @@ -2395,7 +2431,7 @@ RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue) Log(LOGDEBUG, "Invoking %s", method.av_val); /* keep it in call queue till result arrives */ if (queue) - AV_queue(&r->m_methodCalls, &r->m_numCalls, &method); + AV_queue(&r->m_methodCalls, &r->m_numCalls, &method); } if (!r->m_vecChannelsOut[packet->m_nChannel]) @@ -2411,12 +2447,12 @@ RTMP_Serve(RTMP *r) } void -RTMP_Close(RTMP * r) +RTMP_Close(RTMP *r) { int i; if (RTMP_IsConnected(r)) - closesocket(r->m_sb.sb_socket); + RTMPSockBuf_Close(&r->m_sb); r->m_stream_id = -1; r->m_sb.sb_socket = -1; @@ -2451,17 +2487,17 @@ RTMP_Close(RTMP * r) r->m_sb.sb_size = 0; #ifdef CRYPTO - if(r->Link.dh) + if (r->Link.dh) { DH_free(r->Link.dh); r->Link.dh = NULL; } - if(r->Link.rc4keyIn) + if (r->Link.rc4keyIn) { free(r->Link.rc4keyIn); r->Link.rc4keyIn = NULL; } - if(r->Link.rc4keyOut) + if (r->Link.rc4keyOut) { free(r->Link.rc4keyOut); r->Link.rc4keyOut = NULL; @@ -2480,71 +2516,118 @@ RTMPSockBuf_Fill(RTMPSockBuf *sb) while (1) { nBytes = sizeof(sb->sb_buf) - sb->sb_size - (sb->sb_start - sb->sb_buf); - nBytes = recv(sb->sb_socket, sb->sb_start+sb->sb_size, nBytes, 0); + if (sb->sb_ssl) + { + nBytes = SSL_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes); + } + else + { + nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0); + } if (nBytes != -1) - { - sb->sb_size += nBytes; - } + { + sb->sb_size += nBytes; + } else - { - int sockerr = GetSockError(); - Log(LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)", + { + int sockerr = GetSockError(); + Log(LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)", __FUNCTION__, nBytes, sockerr, strerror(sockerr)); - if (sockerr == EINTR && !RTMP_ctrlC) + if (sockerr == EINTR && !RTMP_ctrlC) continue; - if (sockerr == EWOULDBLOCK || sockerr == EAGAIN) - { + if (sockerr == EWOULDBLOCK || sockerr == EAGAIN) + { sb->sb_timedout = true; - nBytes = 0; - } - } + nBytes = 0; + } + } break; } return nBytes; } +int +RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len) +{ + int rc; + +#ifdef _DEBUG + fwrite(buf, 1, len, netstackdump); +#endif + + if (sb->sb_ssl) + { + rc = SSL_write(sb->sb_ssl, buf, len); + } + else + { + rc = send(sb->sb_socket, buf, len, 0); + } + return rc; +} + +int +RTMPSockBuf_Close(RTMPSockBuf *sb) +{ + int rc; + + if (sb->sb_ssl) + { + SSL_shutdown(sb->sb_ssl); + SSL_free(sb->sb_ssl); + sb->sb_ssl = NULL; + rc = 0; + } + else + { + rc = closesocket(sb->sb_socket); + } + return rc; +} + #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf)) static void DecodeTEA(AVal *key, AVal *text) { - uint32_t *v, k[4] = {0}, u; - uint32_t z, y, sum=0, e, DELTA=0x9e3779b9; + uint32_t *v, k[4] = { 0 }, u; + uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9; int32_t p, q; int i, n; unsigned char *ptr, *out; /* prep key: pack 1st 16 chars into 4 LittleEndian ints */ ptr = (unsigned char *)key->av_val; - u = 0; n = 0; + u = 0; + n = 0; v = k; - p = key->av_len > 16 ? 16:key->av_len; - for (i=0; iav_len > 16 ? 16 : key->av_len; + for (i = 0; i < p; i++) + { + u |= ptr[i] << (n * 8); + if (n == 3) + { + *v++ = u; + u = 0; + n = 0; + } else - { - n++; - } + { + n++; + } } /* any trailing chars */ if (u) *v = u; /* prep text: hex2bin, multiples of 4 */ - n = (text->av_len+7)/8; - out = malloc(n*8); + n = (text->av_len + 7) / 8; + out = malloc(n * 8); ptr = (unsigned char *)text->av_val; - v = (uint32_t *)out; - for (i=0; i>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z)); - z=v[n-1]; - y=v[0]; - q = 6+52/n ; - sum = q*DELTA ; + z = v[n - 1]; + y = v[0]; + q = 6 + 52 / n; + sum = q * DELTA; while (sum != 0) { - e = sum>>2 & 3; - for (p=n-1; p>0; p--) z = v[p-1], y = v[p] -= MX; - z = v[n-1]; + e = sum >> 2 & 3; + for (p = n - 1; p > 0; p--) + z = v[p - 1], y = v[p] -= MX; + z = v[n - 1]; y = v[0] -= MX; sum -= DELTA; } diff --git a/librtmp/rtmp.h b/librtmp/rtmp.h index 78ec049..8ef747f 100644 --- a/librtmp/rtmp.h +++ b/librtmp/rtmp.h @@ -56,28 +56,34 @@ #include "amf.h" #ifdef __cplusplus -extern "C" { +extern "C" +{ #endif +#define RTMP_FEATURE_HTTP 0x01 // not yet supported +#define RTMP_FEATURE_ENC 0x02 +#define RTMP_FEATURE_SSL 0x04 +#define RTMP_FEATURE_MFP 0x08 // not yet supported + #define RTMP_PROTOCOL_UNDEFINED -1 #define RTMP_PROTOCOL_RTMP 0 -#define RTMP_PROTOCOL_RTMPT 1 // not yet supported -#define RTMP_PROTOCOL_RTMPS 2 // not yet supported -#define RTMP_PROTOCOL_RTMPE 3 -#define RTMP_PROTOCOL_RTMPTE 4 // not yet supported -#define RTMP_PROTOCOL_RTMFP 5 // not yet supported +#define RTMP_PROTOCOL_RTMPE RTMP_FEATURE_ENC +#define RTMP_PROTOCOL_RTMPT RTMP_FEATURE_HTTP +#define RTMP_PROTOCOL_RTMPS (RTMP_FEATURE_HTTP|RTMP_FEATURE_SSL) +#define RTMP_PROTOCOL_RTMPTE (RTMP_FEATURE_HTTP|RTMP_FEATURE_ENC) +#define RTMP_PROTOCOL_RTMFP RTMP_FEATURE_MFP #define RTMP_DEFAULT_CHUNKSIZE 128 -#define RTMP_BUFFER_CACHE_SIZE (16*1024) // needs to fit largest number of bytes recv() may return +#define RTMP_BUFFER_CACHE_SIZE (16*1024) // needs to fit largest number of bytes recv() may return #define RTMP_CHANNELS 65600 -extern const char RTMPProtocolStringsLower[][7]; -extern const AVal RTMP_DefaultFlashVer; -extern bool RTMP_ctrlC; + extern const char RTMPProtocolStringsLower[][7]; + extern const AVal RTMP_DefaultFlashVer; + extern bool RTMP_ctrlC; -uint32_t RTMP_GetTime(); + uint32_t RTMP_GetTime(); #define RTMP_PACKET_TYPE_AUDIO 0x08 #define RTMP_PACKET_TYPE_VIDEO 0x09 @@ -90,185 +96,191 @@ uint32_t RTMP_GetTime(); #define RTMP_PACKET_SIZE_SMALL 2 #define RTMP_PACKET_SIZE_MINIMUM 3 -typedef unsigned char BYTE; - -typedef struct RTMPChunk -{ - int c_headerSize; - int c_chunkSize; - char *c_chunk; - char c_header[RTMP_MAX_HEADER_SIZE]; -} RTMPChunk; - -typedef struct RTMPPacket -{ - BYTE m_headerType; - BYTE m_packetType; - BYTE m_hasAbsTimestamp; // timestamp absolute or relative? - int m_nChannel; - uint32_t m_nInfoField1; // 3 first bytes - int32_t m_nInfoField2; // last 4 bytes in a long header, absolute timestamp for long headers, relative timestamp for short headers - uint32_t m_nTimeStamp; // absolute timestamp - uint32_t m_nBodySize; - uint32_t m_nBytesRead; - RTMPChunk *m_chunk; - char *m_body; -} RTMPPacket; - -typedef struct RTMPSockBuf -{ - int sb_socket; - int sb_size; /* number of unprocessed bytes in buffer */ - char *sb_start; /* pointer into sb_pBuffer of next byte to process */ - char sb_buf[RTMP_BUFFER_CACHE_SIZE]; /* data read from socket */ - bool sb_timedout; -} RTMPSockBuf; - -void RTMPPacket_Reset(RTMPPacket *p); -void RTMPPacket_Dump(RTMPPacket *p); -bool RTMPPacket_Alloc(RTMPPacket *p, int nSize); -void RTMPPacket_Free(RTMPPacket *p); + typedef unsigned char BYTE; + + typedef struct RTMPChunk + { + int c_headerSize; + int c_chunkSize; + char *c_chunk; + char c_header[RTMP_MAX_HEADER_SIZE]; + } RTMPChunk; + + typedef struct RTMPPacket + { + BYTE m_headerType; + BYTE m_packetType; + BYTE m_hasAbsTimestamp; // timestamp absolute or relative? + int m_nChannel; + uint32_t m_nInfoField1; // 3 first bytes + int32_t m_nInfoField2; // last 4 bytes in a long header, absolute timestamp for long headers, relative timestamp for short headers + uint32_t m_nTimeStamp; // absolute timestamp + uint32_t m_nBodySize; + uint32_t m_nBytesRead; + RTMPChunk *m_chunk; + char *m_body; + } RTMPPacket; + + typedef struct RTMPSockBuf + { + int sb_socket; + int sb_size; /* number of unprocessed bytes in buffer */ + char *sb_start; /* pointer into sb_pBuffer of next byte to process */ + char sb_buf[RTMP_BUFFER_CACHE_SIZE]; /* data read from socket */ + bool sb_timedout; + void *sb_ssl; + } RTMPSockBuf; + + void RTMPPacket_Reset(RTMPPacket *p); + void RTMPPacket_Dump(RTMPPacket *p); + bool RTMPPacket_Alloc(RTMPPacket *p, int nSize); + void RTMPPacket_Free(RTMPPacket *p); #define RTMPPacket_IsReady(a) ((a)->m_nBytesRead == (a)->m_nBodySize) -typedef struct RTMP_LNK -{ - const char *hostname; - unsigned int port; - int protocol; - - AVal playpath; - AVal tcUrl; - AVal swfUrl; - AVal pageUrl; - AVal app; - AVal auth; - AVal flashVer; - AVal subscribepath; - AVal token; - AVal playpath0; - AMFObject extras; - - double seekTime; - uint32_t length; - bool authflag; - bool bLiveStream; - - int timeout; // number of seconds before connection times out - - const char *sockshost; - unsigned short socksport; + typedef struct RTMP_LNK + { + const char *hostname; + unsigned int port; + int protocol; + + AVal playpath; + AVal tcUrl; + AVal swfUrl; + AVal pageUrl; + AVal app; + AVal auth; + AVal flashVer; + AVal subscribepath; + AVal token; + AVal playpath0; + AMFObject extras; + + double seekTime; + uint32_t length; + bool authflag; + bool bLiveStream; + + int timeout; // number of seconds before connection times out + + const char *sockshost; + unsigned short socksport; #ifdef CRYPTO - void *dh; // for encryption - void *rc4keyIn; - void *rc4keyOut; + void *dh; // for encryption + void *rc4keyIn; + void *rc4keyOut; - AVal SWFHash; - uint32_t SWFSize; - char SWFVerificationResponse[42]; + AVal SWFHash; + uint32_t SWFSize; + char SWFVerificationResponse[42]; #endif -} RTMP_LNK; - -typedef struct RTMP -{ - int m_inChunkSize; - int m_outChunkSize; - int m_nBWCheckCounter; - int m_nBytesIn; - int m_nBytesInSent; - int m_nBufferMS; - int m_stream_id; // returned in _result from invoking createStream - int m_mediaChannel; - uint32_t m_mediaStamp; - uint32_t m_pauseStamp; - int m_pausing; - int m_nServerBW; - int m_nClientBW; - uint8_t m_nClientBW2; - bool m_bPlaying; - bool m_bSendEncoding; - bool m_bSendCounter; - - AVal *m_methodCalls; /* remote method calls queue */ - int m_numCalls; - - RTMP_LNK Link; - RTMPPacket *m_vecChannelsIn[RTMP_CHANNELS]; - RTMPPacket *m_vecChannelsOut[RTMP_CHANNELS]; - int m_channelTimestamp[RTMP_CHANNELS]; // abs timestamp of last packet - - double m_fAudioCodecs; // audioCodecs for the connect packet - double m_fVideoCodecs; // videoCodecs for the connect packet - double m_fEncoding; /* AMF0 or AMF3 */ - - double m_fDuration; // duration of stream in seconds - - RTMPSockBuf m_sb; -} RTMP; - -bool RTMP_ParseURL(const char *url, int *protocol, char **host, - unsigned int *port, AVal *playpath, AVal *app); -void RTMP_ParsePlaypath(AVal *in, AVal *out); -void RTMP_SetBufferMS(RTMP *r, int size); -void RTMP_UpdateBufferMS(RTMP *r); - -void RTMP_SetupStream(RTMP *r, int protocol, - const char *hostname, - unsigned int port, - const char *sockshost, - AVal *playpath, - AVal *tcUrl, - AVal *swfUrl, - AVal *pageUrl, - AVal *app, - AVal *auth, - AVal *swfSHA256Hash, - uint32_t swfSize, - AVal *flashVer, - AVal *subscribepath, - double dTime, - uint32_t dLength, bool bLiveStream, long int timeout); - -bool RTMP_Connect(RTMP *r, RTMPPacket *cp); -bool RTMP_Connect0(RTMP *r, struct sockaddr *svc); -bool RTMP_Connect1(RTMP *r, RTMPPacket *cp); -bool RTMP_Serve(RTMP *r); - -bool RTMP_ReadPacket(RTMP * r, RTMPPacket * packet); -bool RTMP_SendPacket(RTMP * r, RTMPPacket * packet, bool queue); -bool RTMP_SendChunk(RTMP * r, RTMPChunk *chunk); -bool RTMP_IsConnected(RTMP *r); -bool RTMP_IsTimedout(RTMP *r); -double RTMP_GetDuration(RTMP *r); -bool RTMP_ToggleStream(RTMP *r); - -bool RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength); -bool RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime, uint32_t dLength); -void RTMP_DeleteStream(RTMP *r); -int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet); -int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet); - -void RTMP_Init(RTMP *r); -void RTMP_Close(RTMP *r); - -bool RTMP_SendCtrl(RTMP * r, short nType, unsigned int nObject, unsigned int nTime); -bool RTMP_SendPause(RTMP *r, bool DoPause, double dTime); -bool RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, - AMFObjectProperty *p); - -bool RTMPSockBuf_Fill(RTMPSockBuf *sb); - -bool RTMP_SendCreateStream(RTMP * r, double dCmdID); -bool RTMP_SendSeek(RTMP * r, double dTime); -bool RTMP_SendServerBW(RTMP * r); -void RTMP_DropRequest(RTMP *r, int i, bool freeit); + } RTMP_LNK; + + typedef struct RTMP + { + int m_inChunkSize; + int m_outChunkSize; + int m_nBWCheckCounter; + int m_nBytesIn; + int m_nBytesInSent; + int m_nBufferMS; + int m_stream_id; // returned in _result from invoking createStream + int m_mediaChannel; + uint32_t m_mediaStamp; + uint32_t m_pauseStamp; + int m_pausing; + int m_nServerBW; + int m_nClientBW; + uint8_t m_nClientBW2; + bool m_bPlaying; + bool m_bSendEncoding; + bool m_bSendCounter; + + AVal *m_methodCalls; /* remote method calls queue */ + int m_numCalls; + + RTMP_LNK Link; + RTMPPacket *m_vecChannelsIn[RTMP_CHANNELS]; + RTMPPacket *m_vecChannelsOut[RTMP_CHANNELS]; + int m_channelTimestamp[RTMP_CHANNELS]; // abs timestamp of last packet + + double m_fAudioCodecs; // audioCodecs for the connect packet + double m_fVideoCodecs; // videoCodecs for the connect packet + double m_fEncoding; /* AMF0 or AMF3 */ + + double m_fDuration; // duration of stream in seconds + + RTMPSockBuf m_sb; + } RTMP; + + bool RTMP_ParseURL(const char *url, int *protocol, char **host, + unsigned int *port, AVal *playpath, AVal *app); + void RTMP_ParsePlaypath(AVal *in, AVal *out); + void RTMP_SetBufferMS(RTMP *r, int size); + void RTMP_UpdateBufferMS(RTMP *r); + + void RTMP_SetupStream(RTMP *r, int protocol, + const char *hostname, + unsigned int port, + const char *sockshost, + AVal *playpath, + AVal *tcUrl, + AVal *swfUrl, + AVal *pageUrl, + AVal *app, + AVal *auth, + AVal *swfSHA256Hash, + uint32_t swfSize, + AVal *flashVer, + AVal *subscribepath, + double dTime, + uint32_t dLength, bool bLiveStream, long int timeout); + + bool RTMP_Connect(RTMP *r, RTMPPacket *cp); + bool RTMP_Connect0(RTMP *r, struct sockaddr *svc); + bool RTMP_Connect1(RTMP *r, RTMPPacket *cp); + bool RTMP_Serve(RTMP *r); + + bool RTMP_ReadPacket(RTMP *r, RTMPPacket *packet); + bool RTMP_SendPacket(RTMP *r, RTMPPacket *packet, bool queue); + bool RTMP_SendChunk(RTMP *r, RTMPChunk *chunk); + bool RTMP_IsConnected(RTMP *r); + bool RTMP_IsTimedout(RTMP *r); + double RTMP_GetDuration(RTMP *r); + bool RTMP_ToggleStream(RTMP *r); + + bool RTMP_ConnectStream(RTMP *r, double seekTime, uint32_t dLength); + bool RTMP_ReconnectStream(RTMP *r, int bufferTime, double seekTime, + uint32_t dLength); + void RTMP_DeleteStream(RTMP *r); + int RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet); + int RTMP_ClientPacket(RTMP *r, RTMPPacket *packet); + + void RTMP_Init(RTMP *r); + void RTMP_Close(RTMP *r); + + bool RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, + unsigned int nTime); + bool RTMP_SendPause(RTMP *r, bool DoPause, double dTime); + bool RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name, + AMFObjectProperty * p); + + bool RTMPSockBuf_Fill(RTMPSockBuf *sb); + int RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len); + int RTMPSockBuf_Close(RTMPSockBuf *sb); + + bool RTMP_SendCreateStream(RTMP *r, double dCmdID); + bool RTMP_SendSeek(RTMP *r, double dTime); + bool RTMP_SendServerBW(RTMP *r); + void RTMP_DropRequest(RTMP *r, int i, bool freeit); #ifdef CRYPTO /* hashswf.c */ #define HASHLEN 32 -int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, int age); + int RTMP_HashSWF(const char *url, unsigned int *size, unsigned char *hash, + int age); #endif #ifdef __cplusplus