Fix issue 5/7 from LMX of Qihoo 360 Codesafe Team
[rtmpdump.git] / librtmp / rtmp.c
bloba2863b0ed4d03cc85fc9f15097bd687c369a6a13
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
4 * Copyright (C) 2008-2009 Andrej Stepanchuk
5 * Copyright (C) 2009-2010 Howard Chu
7 * This file is part of librtmp.
9 * librtmp is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1,
12 * or (at your option) any later version.
14 * librtmp is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with librtmp see the file COPYING. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/lgpl.html
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <time.h>
32 #include "rtmp_sys.h"
33 #include "log.h"
35 #ifdef CRYPTO
36 #ifdef USE_POLARSSL
37 #include <polarssl/havege.h>
38 #include <polarssl/md5.h>
39 #include <polarssl/base64.h>
40 #define MD5_DIGEST_LENGTH 16
42 static const char *my_dhm_P =
43 "E4004C1F94182000103D883A448B3F80" \
44 "2CE4B44A83301270002C20D0321CFD00" \
45 "11CCEF784C26A400F43DFB901BCA7538" \
46 "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
47 "F6AC8E1DA6BCC3B4E1F96B0564965300" \
48 "FFA1D0B601EB2800F489AA512C4B248C" \
49 "01F76949A60BB7F00A40B1EAB64BDD48" \
50 "E8A700D60B7F1200FA8E77B0A979DABF";
52 static const char *my_dhm_G = "4";
54 #elif defined(USE_GNUTLS)
55 #include <gnutls/gnutls.h>
56 #define MD5_DIGEST_LENGTH 16
57 #include <nettle/base64.h>
58 #include <nettle/md5.h>
59 #else /* USE_OPENSSL */
60 #include <openssl/ssl.h>
61 #include <openssl/rc4.h>
62 #include <openssl/md5.h>
63 #include <openssl/bio.h>
64 #include <openssl/buffer.h>
65 #endif
66 TLS_CTX RTMP_TLS_ctx;
67 #endif
69 #define RTMP_SIG_SIZE 1536
70 #define RTMP_LARGE_HEADER_SIZE 12
72 static const int packetSize[] = { 12, 8, 4, 1 };
74 int RTMP_ctrlC;
76 const char RTMPProtocolStrings[][7] = {
77 "RTMP",
78 "RTMPT",
79 "RTMPE",
80 "RTMPTE",
81 "RTMPS",
82 "RTMPTS",
83 "",
84 "",
85 "RTMFP"
88 const char RTMPProtocolStringsLower[][7] = {
89 "rtmp",
90 "rtmpt",
91 "rtmpe",
92 "rtmpte",
93 "rtmps",
94 "rtmpts",
95 "",
96 "",
97 "rtmfp"
100 static const char *RTMPT_cmds[] = {
101 "open",
102 "send",
103 "idle",
104 "close"
107 typedef enum {
108 RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
109 } RTMPTCmd;
111 static int DumpMetaData(AMFObject *obj);
112 static int HandShake(RTMP *r, int FP9HandShake);
113 static int SocksNegotiate(RTMP *r);
115 static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
116 static int SendCheckBW(RTMP *r);
117 static int SendCheckBWResult(RTMP *r, double txn);
118 static int SendDeleteStream(RTMP *r, double dStreamId);
119 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
120 static int SendPlay(RTMP *r);
121 static int SendBytesReceived(RTMP *r);
122 static int SendUsherToken(RTMP *r, AVal *usherToken);
124 #if 0 /* unused */
125 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
126 #endif
128 static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
129 static int HandleMetadata(RTMP *r, char *body, unsigned int len);
130 static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
131 static void HandleAudio(RTMP *r, const RTMPPacket *packet);
132 static void HandleVideo(RTMP *r, const RTMPPacket *packet);
133 static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
134 static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
135 static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
137 static int ReadN(RTMP *r, char *buffer, int n);
138 static int WriteN(RTMP *r, const char *buffer, int n);
140 static void DecodeTEA(AVal *key, AVal *text);
142 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
143 static int HTTP_read(RTMP *r, int fill);
145 static void CloseInternal(RTMP *r, int reconnect);
147 #ifndef _WIN32
148 static int clk_tck;
149 #endif
151 #ifdef CRYPTO
152 #include "handshake.h"
153 #endif
155 uint32_t
156 RTMP_GetTime()
158 #ifdef _DEBUG
159 return 0;
160 #elif defined(_WIN32)
161 return timeGetTime();
162 #else
163 struct tms t;
164 if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
165 return times(&t) * 1000 / clk_tck;
166 #endif
169 void
170 RTMP_UserInterrupt()
172 RTMP_ctrlC = TRUE;
175 void
176 RTMPPacket_Reset(RTMPPacket *p)
178 p->m_headerType = 0;
179 p->m_packetType = 0;
180 p->m_nChannel = 0;
181 p->m_nTimeStamp = 0;
182 p->m_nInfoField2 = 0;
183 p->m_hasAbsTimestamp = FALSE;
184 p->m_nBodySize = 0;
185 p->m_nBytesRead = 0;
189 RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize)
191 char *ptr;
192 if (nSize > SIZE_MAX - RTMP_MAX_HEADER_SIZE)
193 return FALSE;
194 ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
195 if (!ptr)
196 return FALSE;
197 p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
198 p->m_nBytesRead = 0;
199 return TRUE;
202 void
203 RTMPPacket_Free(RTMPPacket *p)
205 if (p->m_body)
207 free(p->m_body - RTMP_MAX_HEADER_SIZE);
208 p->m_body = NULL;
212 void
213 RTMPPacket_Dump(RTMPPacket *p)
215 RTMP_Log(RTMP_LOGDEBUG,
216 "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %u. body: 0x%02x",
217 p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
218 p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
222 RTMP_LibVersion()
224 return RTMP_LIB_VERSION;
227 void
228 RTMP_TLS_Init()
230 #ifdef CRYPTO
231 #ifdef USE_POLARSSL
232 /* Do this regardless of NO_SSL, we use havege for rtmpe too */
233 RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
234 havege_init(&RTMP_TLS_ctx->hs);
235 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
236 /* Technically we need to initialize libgcrypt ourselves if
237 * we're not going to call gnutls_global_init(). Ignoring this
238 * for now.
240 gnutls_global_init();
241 RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
242 gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
243 gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
244 gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
245 "ca.pem", GNUTLS_X509_FMT_PEM);
246 #elif !defined(NO_SSL) /* USE_OPENSSL */
247 /* libcrypto doesn't need anything special */
248 SSL_load_error_strings();
249 SSL_library_init();
250 OpenSSL_add_all_digests();
251 RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
252 SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
253 SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
254 #endif
255 #endif
258 void *
259 RTMP_TLS_AllocServerContext(const char* cert, const char* key)
261 void *ctx = NULL;
262 #ifdef CRYPTO
263 if (!RTMP_TLS_ctx)
264 RTMP_TLS_Init();
265 #ifdef USE_POLARSSL
266 tls_server_ctx *tc = ctx = calloc(1, sizeof(struct tls_server_ctx));
267 tc->dhm_P = my_dhm_P;
268 tc->dhm_G = my_dhm_G;
269 tc->hs = &RTMP_TLS_ctx->hs;
270 if (x509parse_crtfile(&tc->cert, cert)) {
271 free(tc);
272 return NULL;
274 if (x509parse_keyfile(&tc->key, key, NULL)) {
275 x509_free(&tc->cert);
276 free(tc);
277 return NULL;
279 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
280 gnutls_certificate_allocate_credentials((gnutls_certificate_credentials*) &ctx);
281 if (gnutls_certificate_set_x509_key_file(ctx, cert, key, GNUTLS_X509_FMT_PEM) != 0) {
282 gnutls_certificate_free_credentials(ctx);
283 return NULL;
285 #elif !defined(NO_SSL) /* USE_OPENSSL */
286 ctx = SSL_CTX_new(SSLv23_server_method());
287 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
288 SSL_CTX_free(ctx);
289 return NULL;
291 if (!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
292 SSL_CTX_free(ctx);
293 return NULL;
295 #endif
296 #endif
297 return ctx;
300 void
301 RTMP_TLS_FreeServerContext(void *ctx)
303 #ifdef CRYPTO
304 #ifdef USE_POLARSSL
305 x509_free(&((tls_server_ctx*)ctx)->cert);
306 rsa_free(&((tls_server_ctx*)ctx)->key);
307 free(ctx);
308 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
309 gnutls_certificate_free_credentials(ctx);
310 #elif !defined(NO_SSL) /* USE_OPENSSL */
311 SSL_CTX_free(ctx);
312 #endif
313 #endif
316 RTMP *
317 RTMP_Alloc()
319 return calloc(1, sizeof(RTMP));
322 void
323 RTMP_Free(RTMP *r)
325 free(r);
328 void
329 RTMP_Init(RTMP *r)
331 #ifdef CRYPTO
332 if (!RTMP_TLS_ctx)
333 RTMP_TLS_Init();
334 #endif
336 memset(r, 0, sizeof(RTMP));
337 r->m_sb.sb_socket = -1;
338 r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
339 r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
340 r->m_nBufferMS = 30000;
341 r->m_nClientBW = 2500000;
342 r->m_nClientBW2 = 2;
343 r->m_nServerBW = 2500000;
344 r->m_fAudioCodecs = 3191.0;
345 r->m_fVideoCodecs = 252.0;
346 r->Link.timeout = 30;
347 r->Link.swfAge = 30;
350 void
351 RTMP_EnableWrite(RTMP *r)
353 r->Link.protocol |= RTMP_FEATURE_WRITE;
356 double
357 RTMP_GetDuration(RTMP *r)
359 return r->m_fDuration;
363 RTMP_IsConnected(RTMP *r)
365 return r->m_sb.sb_socket != -1;
369 RTMP_Socket(RTMP *r)
371 return r->m_sb.sb_socket;
375 RTMP_IsTimedout(RTMP *r)
377 return r->m_sb.sb_timedout;
380 void
381 RTMP_SetBufferMS(RTMP *r, int size)
383 r->m_nBufferMS = size;
386 void
387 RTMP_UpdateBufferMS(RTMP *r)
389 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
392 #undef OSS
393 #ifdef _WIN32
394 #define OSS "WIN"
395 #elif defined(__sun__)
396 #define OSS "SOL"
397 #elif defined(__APPLE__)
398 #define OSS "MAC"
399 #elif defined(__linux__)
400 #define OSS "LNX"
401 #else
402 #define OSS "GNU"
403 #endif
404 #define DEF_VERSTR OSS " 10,0,32,18"
405 static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
406 const AVal RTMP_DefaultFlashVer =
407 { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
409 static void
410 SocksSetup(RTMP *r, AVal *sockshost)
412 if (sockshost->av_len)
414 const char *socksport = strchr(sockshost->av_val, ':');
415 char *hostname = strdup(sockshost->av_val);
417 if (socksport)
418 hostname[socksport - sockshost->av_val] = '\0';
419 r->Link.sockshost.av_val = hostname;
420 r->Link.sockshost.av_len = strlen(hostname);
422 r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
423 RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
424 r->Link.socksport);
426 else
428 r->Link.sockshost.av_val = NULL;
429 r->Link.sockshost.av_len = 0;
430 r->Link.socksport = 0;
434 void
435 RTMP_SetupStream(RTMP *r,
436 int protocol,
437 AVal *host,
438 unsigned int port,
439 AVal *sockshost,
440 AVal *playpath,
441 AVal *tcUrl,
442 AVal *swfUrl,
443 AVal *pageUrl,
444 AVal *app,
445 AVal *auth,
446 AVal *swfSHA256Hash,
447 uint32_t swfSize,
448 AVal *flashVer,
449 AVal *subscribepath,
450 AVal *usherToken,
451 int dStart,
452 int dStop, int bLiveStream, long int timeout)
454 RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
455 RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
456 RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
457 RTMP_Log(RTMP_LOGDEBUG, "Playpath : %s", playpath->av_val);
459 if (tcUrl && tcUrl->av_val)
460 RTMP_Log(RTMP_LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
461 if (swfUrl && swfUrl->av_val)
462 RTMP_Log(RTMP_LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
463 if (pageUrl && pageUrl->av_val)
464 RTMP_Log(RTMP_LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
465 if (app && app->av_val)
466 RTMP_Log(RTMP_LOGDEBUG, "app : %.*s", app->av_len, app->av_val);
467 if (auth && auth->av_val)
468 RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
469 if (subscribepath && subscribepath->av_val)
470 RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
471 if (usherToken && usherToken->av_val)
472 RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
473 if (flashVer && flashVer->av_val)
474 RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
475 if (dStart > 0)
476 RTMP_Log(RTMP_LOGDEBUG, "StartTime : %d msec", dStart);
477 if (dStop > 0)
478 RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
480 RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
481 RTMP_Log(RTMP_LOGDEBUG, "timeout : %ld sec", timeout);
483 #ifdef CRYPTO
484 if (swfSHA256Hash != NULL && swfSize > 0)
486 memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
487 r->Link.SWFSize = swfSize;
488 RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
489 RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
490 RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %u", r->Link.SWFSize);
492 else
494 r->Link.SWFSize = 0;
496 #endif
498 SocksSetup(r, sockshost);
500 if (tcUrl && tcUrl->av_len)
501 r->Link.tcUrl = *tcUrl;
502 if (swfUrl && swfUrl->av_len)
503 r->Link.swfUrl = *swfUrl;
504 if (pageUrl && pageUrl->av_len)
505 r->Link.pageUrl = *pageUrl;
506 if (app && app->av_len)
507 r->Link.app = *app;
508 if (auth && auth->av_len)
510 r->Link.auth = *auth;
511 r->Link.lFlags |= RTMP_LF_AUTH;
513 if (flashVer && flashVer->av_len)
514 r->Link.flashVer = *flashVer;
515 else
516 r->Link.flashVer = RTMP_DefaultFlashVer;
517 if (subscribepath && subscribepath->av_len)
518 r->Link.subscribepath = *subscribepath;
519 if (usherToken && usherToken->av_len)
520 r->Link.usherToken = *usherToken;
521 r->Link.seekTime = dStart;
522 r->Link.stopTime = dStop;
523 if (bLiveStream)
524 r->Link.lFlags |= RTMP_LF_LIVE;
525 r->Link.timeout = timeout;
527 r->Link.protocol = protocol;
528 r->Link.hostname = *host;
529 r->Link.port = port;
530 r->Link.playpath = *playpath;
532 if (r->Link.port == 0)
534 if (protocol & RTMP_FEATURE_SSL)
535 r->Link.port = 443;
536 else if (protocol & RTMP_FEATURE_HTTP)
537 r->Link.port = 80;
538 else
539 r->Link.port = 1935;
543 enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
544 static const char *optinfo[] = {
545 "string", "integer", "boolean", "AMF" };
547 #define OFF(x) offsetof(struct RTMP,x)
549 static struct urlopt {
550 AVal name;
551 off_t off;
552 int otype;
553 int omisc;
554 char *use;
555 } options[] = {
556 { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
557 "Use the specified SOCKS proxy" },
558 { AVC("app"), OFF(Link.app), OPT_STR, 0,
559 "Name of target app on server" },
560 { AVC("tcUrl"), OFF(Link.tcUrl), OPT_STR, 0,
561 "URL to played stream" },
562 { AVC("pageUrl"), OFF(Link.pageUrl), OPT_STR, 0,
563 "URL of played media's web page" },
564 { AVC("swfUrl"), OFF(Link.swfUrl), OPT_STR, 0,
565 "URL to player SWF file" },
566 { AVC("flashver"), OFF(Link.flashVer), OPT_STR, 0,
567 "Flash version string (default " DEF_VERSTR ")" },
568 { AVC("conn"), OFF(Link.extras), OPT_CONN, 0,
569 "Append arbitrary AMF data to Connect message" },
570 { AVC("playpath"), OFF(Link.playpath), OPT_STR, 0,
571 "Path to target media on server" },
572 { AVC("playlist"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_PLST,
573 "Set playlist before play command" },
574 { AVC("live"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_LIVE,
575 "Stream is live, no seeking possible" },
576 { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
577 "Stream to subscribe to" },
578 { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
579 "Justin.tv authentication token" },
580 { AVC("token"), OFF(Link.token), OPT_STR, 0,
581 "Key for SecureToken response" },
582 { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
583 "Perform SWF Verification" },
584 { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
585 "Number of days to use cached SWF hash" },
586 { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
587 "Stream start position in milliseconds" },
588 { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
589 "Stream stop position in milliseconds" },
590 { AVC("buffer"), OFF(m_nBufferMS), OPT_INT, 0,
591 "Buffer time in milliseconds" },
592 { AVC("timeout"), OFF(Link.timeout), OPT_INT, 0,
593 "Session timeout in seconds" },
594 { AVC("pubUser"), OFF(Link.pubUser), OPT_STR, 0,
595 "Publisher username" },
596 { AVC("pubPasswd"), OFF(Link.pubPasswd), OPT_STR, 0,
597 "Publisher password" },
598 { {NULL,0}, 0, 0}
601 static const AVal truth[] = {
602 AVC("1"),
603 AVC("on"),
604 AVC("yes"),
605 AVC("true"),
606 {0,0}
609 static void RTMP_OptUsage()
611 int i;
613 RTMP_Log(RTMP_LOGERROR, "Valid RTMP options are:\n");
614 for (i=0; options[i].name.av_len; i++) {
615 RTMP_Log(RTMP_LOGERROR, "%10s %-7s %s\n", options[i].name.av_val,
616 optinfo[options[i].otype], options[i].use);
620 static int
621 parseAMF(AMFObject *obj, AVal *av, int *depth)
623 AMFObjectProperty prop = {{0,0}};
624 int i;
625 char *p, *arg = av->av_val;
627 if (arg[1] == ':')
629 p = (char *)arg+2;
630 switch(arg[0])
632 case 'B':
633 prop.p_type = AMF_BOOLEAN;
634 prop.p_vu.p_number = atoi(p);
635 break;
636 case 'S':
637 prop.p_type = AMF_STRING;
638 prop.p_vu.p_aval.av_val = p;
639 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
640 break;
641 case 'N':
642 prop.p_type = AMF_NUMBER;
643 prop.p_vu.p_number = strtod(p, NULL);
644 break;
645 case 'Z':
646 prop.p_type = AMF_NULL;
647 break;
648 case 'O':
649 i = atoi(p);
650 if (i)
652 prop.p_type = AMF_OBJECT;
654 else
656 (*depth)--;
657 return 0;
659 break;
660 default:
661 return -1;
664 else if (arg[2] == ':' && arg[0] == 'N')
666 p = strchr(arg+3, ':');
667 if (!p || !*depth)
668 return -1;
669 prop.p_name.av_val = (char *)arg+3;
670 prop.p_name.av_len = p - (arg+3);
672 p++;
673 switch(arg[1])
675 case 'B':
676 prop.p_type = AMF_BOOLEAN;
677 prop.p_vu.p_number = atoi(p);
678 break;
679 case 'S':
680 prop.p_type = AMF_STRING;
681 prop.p_vu.p_aval.av_val = p;
682 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
683 break;
684 case 'N':
685 prop.p_type = AMF_NUMBER;
686 prop.p_vu.p_number = strtod(p, NULL);
687 break;
688 case 'O':
689 prop.p_type = AMF_OBJECT;
690 break;
691 default:
692 return -1;
695 else
696 return -1;
698 if (*depth)
700 AMFObject *o2;
701 for (i=0; i<*depth; i++)
703 o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
704 obj = o2;
707 AMF_AddProp(obj, &prop);
708 if (prop.p_type == AMF_OBJECT)
709 (*depth)++;
710 return 0;
713 int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg)
715 int i;
716 void *v;
718 for (i=0; options[i].name.av_len; i++) {
719 if (opt->av_len != options[i].name.av_len) continue;
720 if (strcasecmp(opt->av_val, options[i].name.av_val)) continue;
721 v = (char *)r + options[i].off;
722 switch(options[i].otype) {
723 case OPT_STR: {
724 AVal *aptr = v;
725 *aptr = *arg; }
726 break;
727 case OPT_INT: {
728 long l = strtol(arg->av_val, NULL, 0);
729 *(int *)v = l; }
730 break;
731 case OPT_BOOL: {
732 int j, fl;
733 fl = *(int *)v;
734 for (j=0; truth[j].av_len; j++) {
735 if (arg->av_len != truth[j].av_len) continue;
736 if (strcasecmp(arg->av_val, truth[j].av_val)) continue;
737 fl |= options[i].omisc; break; }
738 *(int *)v = fl;
740 break;
741 case OPT_CONN:
742 if (parseAMF(&r->Link.extras, arg, &r->Link.edepth))
743 return FALSE;
744 break;
746 break;
748 if (!options[i].name.av_len) {
749 RTMP_Log(RTMP_LOGERROR, "Unknown option %s", opt->av_val);
750 RTMP_OptUsage();
751 return FALSE;
754 return TRUE;
757 int RTMP_SetupURL(RTMP *r, char *url)
759 AVal opt, arg;
760 char *p1, *p2, *ptr = strchr(url, ' ');
761 int ret, len;
762 unsigned int port = 0;
764 if (ptr)
765 *ptr = '\0';
767 len = strlen(url);
768 ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
769 &port, &r->Link.playpath0, &r->Link.app);
770 if (!ret)
771 return ret;
772 r->Link.port = port;
773 r->Link.playpath = r->Link.playpath0;
775 while (ptr) {
776 *ptr++ = '\0';
777 p1 = ptr;
778 p2 = strchr(p1, '=');
779 if (!p2)
780 break;
781 opt.av_val = p1;
782 opt.av_len = p2 - p1;
783 *p2++ = '\0';
784 arg.av_val = p2;
785 ptr = strchr(p2, ' ');
786 if (ptr) {
787 *ptr = '\0';
788 arg.av_len = ptr - p2;
789 /* skip repeated spaces */
790 while(ptr[1] == ' ')
791 *ptr++ = '\0';
792 } else {
793 arg.av_len = strlen(p2);
796 /* unescape */
797 port = arg.av_len;
798 for (p1=p2; port >0;) {
799 if (*p1 == '\\') {
800 unsigned int c;
801 if (port < 3)
802 return FALSE;
803 sscanf(p1+1, "%02x", &c);
804 *p2++ = c;
805 port -= 3;
806 p1 += 3;
807 } else {
808 *p2++ = *p1++;
809 port--;
812 arg.av_len = p2 - arg.av_val;
814 ret = RTMP_SetOpt(r, &opt, &arg);
815 if (!ret)
816 return ret;
819 if (!r->Link.tcUrl.av_len)
821 r->Link.tcUrl.av_val = url;
822 if (r->Link.app.av_len)
824 if (r->Link.app.av_val < url + len)
826 /* if app is part of original url, just use it */
827 r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);
829 else
831 len = r->Link.hostname.av_len + r->Link.app.av_len +
832 sizeof("rtmpte://:65535/");
833 r->Link.tcUrl.av_val = malloc(len);
834 r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
835 "%s://%.*s:%d/%.*s",
836 RTMPProtocolStringsLower[r->Link.protocol],
837 r->Link.hostname.av_len, r->Link.hostname.av_val,
838 r->Link.port,
839 r->Link.app.av_len, r->Link.app.av_val);
840 r->Link.lFlags |= RTMP_LF_FTCU;
843 else
845 r->Link.tcUrl.av_len = strlen(url);
849 #ifdef CRYPTO
850 if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
851 RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
852 (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
853 #endif
855 SocksSetup(r, &r->Link.sockshost);
857 if (r->Link.port == 0)
859 if (r->Link.protocol & RTMP_FEATURE_SSL)
860 r->Link.port = 443;
861 else if (r->Link.protocol & RTMP_FEATURE_HTTP)
862 r->Link.port = 80;
863 else
864 r->Link.port = 1935;
866 return TRUE;
869 static int
870 add_addr_info(struct sockaddr_in *service, AVal *host, int port)
872 char *hostname;
873 int ret = TRUE;
874 if (host->av_val[host->av_len])
876 hostname = malloc(host->av_len+1);
877 memcpy(hostname, host->av_val, host->av_len);
878 hostname[host->av_len] = '\0';
880 else
882 hostname = host->av_val;
885 service->sin_addr.s_addr = inet_addr(hostname);
886 if (service->sin_addr.s_addr == INADDR_NONE)
888 struct hostent *host = gethostbyname(hostname);
889 if (host == NULL || host->h_addr == NULL)
891 RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
892 ret = FALSE;
893 goto finish;
895 service->sin_addr = *(struct in_addr *)host->h_addr;
898 service->sin_port = htons(port);
899 finish:
900 if (hostname != host->av_val)
901 free(hostname);
902 return ret;
906 RTMP_Connect0(RTMP *r, struct sockaddr * service)
908 int on = 1;
909 r->m_sb.sb_timedout = FALSE;
910 r->m_pausing = 0;
911 r->m_fDuration = 0.0;
913 r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
914 if (r->m_sb.sb_socket != -1)
916 if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
918 int err = GetSockError();
919 RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)",
920 __FUNCTION__, err, strerror(err));
921 RTMP_Close(r);
922 return FALSE;
925 if (r->Link.socksport)
927 RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
928 if (!SocksNegotiate(r))
930 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
931 RTMP_Close(r);
932 return FALSE;
936 else
938 RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
939 GetSockError());
940 return FALSE;
943 /* set timeout */
945 SET_RCVTIMEO(tv, r->Link.timeout);
946 if (setsockopt
947 (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
949 RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
950 __FUNCTION__, r->Link.timeout);
954 setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
956 return TRUE;
960 RTMP_TLS_Accept(RTMP *r, void *ctx)
962 #if defined(CRYPTO) && !defined(NO_SSL)
963 TLS_server(ctx, r->m_sb.sb_ssl);
964 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
965 if (TLS_accept(r->m_sb.sb_ssl) < 0)
967 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
968 return FALSE;
970 return TRUE;
971 #else
972 return FALSE;
973 #endif
977 RTMP_Connect1(RTMP *r, RTMPPacket *cp)
979 if (r->Link.protocol & RTMP_FEATURE_SSL)
981 #if defined(CRYPTO) && !defined(NO_SSL)
982 TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);
983 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
984 if (TLS_connect(r->m_sb.sb_ssl) < 0)
986 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
987 RTMP_Close(r);
988 return FALSE;
990 #else
991 RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
992 RTMP_Close(r);
993 return FALSE;
995 #endif
997 if (r->Link.protocol & RTMP_FEATURE_HTTP)
999 r->m_msgCounter = 1;
1000 r->m_clientID.av_val = NULL;
1001 r->m_clientID.av_len = 0;
1002 HTTP_Post(r, RTMPT_OPEN, "", 1);
1003 if (HTTP_read(r, 1) != 0)
1005 r->m_msgCounter = 0;
1006 RTMP_Log(RTMP_LOGDEBUG, "%s, Could not connect for handshake", __FUNCTION__);
1007 RTMP_Close(r);
1008 return 0;
1010 r->m_msgCounter = 0;
1012 RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
1013 if (!HandShake(r, TRUE))
1015 RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
1016 RTMP_Close(r);
1017 return FALSE;
1019 RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
1021 if (!SendConnectPacket(r, cp))
1023 RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
1024 RTMP_Close(r);
1025 return FALSE;
1027 return TRUE;
1031 RTMP_Connect(RTMP *r, RTMPPacket *cp)
1033 struct sockaddr_in service;
1034 if (!r->Link.hostname.av_len)
1035 return FALSE;
1037 memset(&service, 0, sizeof(struct sockaddr_in));
1038 service.sin_family = AF_INET;
1040 if (r->Link.socksport)
1042 /* Connect via SOCKS */
1043 if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
1044 return FALSE;
1046 else
1048 /* Connect directly */
1049 if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
1050 return FALSE;
1053 if (!RTMP_Connect0(r, (struct sockaddr *)&service))
1054 return FALSE;
1056 r->m_bSendCounter = TRUE;
1058 return RTMP_Connect1(r, cp);
1061 static int
1062 SocksNegotiate(RTMP *r)
1064 unsigned long addr;
1065 struct sockaddr_in service;
1066 memset(&service, 0, sizeof(struct sockaddr_in));
1068 add_addr_info(&service, &r->Link.hostname, r->Link.port);
1069 addr = htonl(service.sin_addr.s_addr);
1072 char packet[] = {
1073 4, 1, /* SOCKS 4, connect */
1074 (r->Link.port >> 8) & 0xFF,
1075 (r->Link.port) & 0xFF,
1076 (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
1077 (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
1079 }; /* NULL terminate */
1081 WriteN(r, packet, sizeof packet);
1083 if (ReadN(r, packet, 8) != 8)
1084 return FALSE;
1086 if (packet[0] == 0 && packet[1] == 90)
1088 return TRUE;
1090 else
1092 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
1093 return FALSE;
1099 RTMP_ConnectStream(RTMP *r, int seekTime)
1101 RTMPPacket packet = { 0 };
1103 /* seekTime was already set by SetupStream / SetupURL.
1104 * This is only needed by ReconnectStream.
1106 if (seekTime > 0)
1107 r->Link.seekTime = seekTime;
1109 r->m_mediaChannel = 0;
1111 while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
1113 if (RTMPPacket_IsReady(&packet))
1115 if (!packet.m_nBodySize)
1116 continue;
1117 if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
1118 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
1119 (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
1121 RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
1122 RTMPPacket_Free(&packet);
1123 continue;
1126 RTMP_ClientPacket(r, &packet);
1127 RTMPPacket_Free(&packet);
1131 return r->m_bPlaying;
1135 RTMP_ReconnectStream(RTMP *r, int seekTime)
1137 RTMP_DeleteStream(r);
1139 RTMP_SendCreateStream(r);
1141 return RTMP_ConnectStream(r, seekTime);
1145 RTMP_ToggleStream(RTMP *r)
1147 int res;
1149 if (!r->m_pausing)
1151 if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
1152 r->m_read.status = 0;
1154 res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
1155 if (!res)
1156 return res;
1158 r->m_pausing = 1;
1159 sleep(1);
1161 res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
1162 r->m_pausing = 3;
1163 return res;
1166 void
1167 RTMP_DeleteStream(RTMP *r)
1169 if (r->m_stream_id < 0)
1170 return;
1172 r->m_bPlaying = FALSE;
1174 SendDeleteStream(r, r->m_stream_id);
1175 r->m_stream_id = -1;
1179 RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
1181 int bHasMediaPacket = 0;
1183 while (!bHasMediaPacket && RTMP_IsConnected(r)
1184 && RTMP_ReadPacket(r, packet))
1186 if (!RTMPPacket_IsReady(packet) || !packet->m_nBodySize)
1188 continue;
1191 bHasMediaPacket = RTMP_ClientPacket(r, packet);
1193 if (!bHasMediaPacket)
1195 RTMPPacket_Free(packet);
1197 else if (r->m_pausing == 3)
1199 if (packet->m_nTimeStamp <= r->m_mediaStamp)
1201 bHasMediaPacket = 0;
1202 #ifdef _DEBUG
1203 RTMP_Log(RTMP_LOGDEBUG,
1204 "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
1205 packet->m_packetType, packet->m_nBodySize,
1206 packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
1207 r->m_mediaStamp);
1208 #endif
1209 RTMPPacket_Free(packet);
1210 continue;
1212 r->m_pausing = 0;
1216 if (bHasMediaPacket)
1217 r->m_bPlaying = TRUE;
1218 else if (r->m_sb.sb_timedout && !r->m_pausing)
1219 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
1220 r->m_channelTimestamp[r->m_mediaChannel] : 0;
1222 return bHasMediaPacket;
1226 RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
1228 int bHasMediaPacket = 0;
1229 switch (packet->m_packetType)
1231 case RTMP_PACKET_TYPE_CHUNK_SIZE:
1232 /* chunk size */
1233 HandleChangeChunkSize(r, packet);
1234 break;
1236 case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
1237 /* bytes read report */
1238 RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
1239 break;
1241 case RTMP_PACKET_TYPE_CONTROL:
1242 /* ctrl */
1243 HandleCtrl(r, packet);
1244 break;
1246 case RTMP_PACKET_TYPE_SERVER_BW:
1247 /* server bw */
1248 HandleServerBW(r, packet);
1249 break;
1251 case RTMP_PACKET_TYPE_CLIENT_BW:
1252 /* client bw */
1253 HandleClientBW(r, packet);
1254 break;
1256 case RTMP_PACKET_TYPE_AUDIO:
1257 /* audio data */
1258 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1259 HandleAudio(r, packet);
1260 bHasMediaPacket = 1;
1261 if (!r->m_mediaChannel)
1262 r->m_mediaChannel = packet->m_nChannel;
1263 if (!r->m_pausing)
1264 r->m_mediaStamp = packet->m_nTimeStamp;
1265 break;
1267 case RTMP_PACKET_TYPE_VIDEO:
1268 /* video data */
1269 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1270 HandleVideo(r, packet);
1271 bHasMediaPacket = 1;
1272 if (!r->m_mediaChannel)
1273 r->m_mediaChannel = packet->m_nChannel;
1274 if (!r->m_pausing)
1275 r->m_mediaStamp = packet->m_nTimeStamp;
1276 break;
1278 case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
1279 /* flex stream send */
1280 RTMP_Log(RTMP_LOGDEBUG,
1281 "%s, flex stream send, size %u bytes, not supported, ignoring",
1282 __FUNCTION__, packet->m_nBodySize);
1283 break;
1285 case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
1286 /* flex shared object */
1287 RTMP_Log(RTMP_LOGDEBUG,
1288 "%s, flex shared object, size %u bytes, not supported, ignoring",
1289 __FUNCTION__, packet->m_nBodySize);
1290 break;
1292 case RTMP_PACKET_TYPE_FLEX_MESSAGE:
1293 /* flex message */
1295 RTMP_Log(RTMP_LOGDEBUG,
1296 "%s, flex message, size %u bytes, not fully supported",
1297 __FUNCTION__, packet->m_nBodySize);
1298 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1300 /* some DEBUG code */
1301 #if 0
1302 RTMP_LIB_AMFObject obj;
1303 int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
1304 if(nRes < 0) {
1305 RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
1306 /*return; */
1309 obj.Dump();
1310 #endif
1312 if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
1313 bHasMediaPacket = 2;
1314 break;
1316 case RTMP_PACKET_TYPE_INFO:
1317 /* metadata (notify) */
1318 RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
1319 packet->m_nBodySize);
1320 if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
1321 bHasMediaPacket = 1;
1322 break;
1324 case RTMP_PACKET_TYPE_SHARED_OBJECT:
1325 RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
1326 __FUNCTION__);
1327 break;
1329 case RTMP_PACKET_TYPE_INVOKE:
1330 /* invoke */
1331 RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
1332 packet->m_nBodySize);
1333 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1335 if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
1336 bHasMediaPacket = 2;
1337 break;
1339 case RTMP_PACKET_TYPE_FLASH_VIDEO:
1341 /* go through FLV packets and handle metadata packets */
1342 unsigned int pos = 0;
1343 uint32_t nTimeStamp = packet->m_nTimeStamp;
1345 while (pos + 11 < packet->m_nBodySize)
1347 uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
1349 if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
1351 RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
1352 break;
1354 if (packet->m_body[pos] == 0x12)
1356 HandleMetadata(r, packet->m_body + pos + 11, dataSize);
1358 else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
1360 nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
1361 nTimeStamp |= (packet->m_body[pos + 7] << 24);
1363 pos += (11 + dataSize + 4);
1365 if (!r->m_pausing)
1366 r->m_mediaStamp = nTimeStamp;
1368 /* FLV tag(s) */
1369 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1370 bHasMediaPacket = 1;
1371 break;
1373 default:
1374 RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
1375 packet->m_packetType);
1376 #ifdef _DEBUG
1377 RTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize);
1378 #endif
1381 return bHasMediaPacket;
1384 #ifdef _DEBUG
1385 extern FILE *netstackdump;
1386 extern FILE *netstackdump_read;
1387 #endif
1389 static int
1390 ReadN(RTMP *r, char *buffer, int n)
1392 int nOriginalSize = n;
1393 int avail;
1394 char *ptr;
1396 r->m_sb.sb_timedout = FALSE;
1398 #ifdef _DEBUG
1399 memset(buffer, 0, n);
1400 #endif
1402 ptr = buffer;
1403 while (n > 0)
1405 int nBytes = 0, nRead;
1406 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1408 int refill = 0;
1409 while (!r->m_resplen)
1411 int ret;
1412 if (r->m_sb.sb_size < 13 || refill)
1414 if (!r->m_unackd)
1415 HTTP_Post(r, RTMPT_IDLE, "", 1);
1416 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1418 if (!r->m_sb.sb_timedout)
1419 RTMP_Close(r);
1420 return 0;
1423 if ((ret = HTTP_read(r, 0)) == -1)
1425 RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__);
1426 RTMP_Close(r);
1427 return 0;
1429 else if (ret == -2)
1431 refill = 1;
1433 else
1435 refill = 0;
1438 if (r->m_resplen && !r->m_sb.sb_size)
1439 RTMPSockBuf_Fill(&r->m_sb);
1440 avail = r->m_sb.sb_size;
1441 if (avail > r->m_resplen)
1442 avail = r->m_resplen;
1444 else
1446 avail = r->m_sb.sb_size;
1447 if (avail == 0)
1449 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1451 if (!r->m_sb.sb_timedout)
1452 RTMP_Close(r);
1453 return 0;
1455 avail = r->m_sb.sb_size;
1458 nRead = ((n < avail) ? n : avail);
1459 if (nRead > 0)
1461 memcpy(ptr, r->m_sb.sb_start, nRead);
1462 r->m_sb.sb_start += nRead;
1463 r->m_sb.sb_size -= nRead;
1464 nBytes = nRead;
1465 r->m_nBytesIn += nRead;
1466 if (r->m_bSendCounter
1467 && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
1468 if (!SendBytesReceived(r))
1469 return FALSE;
1471 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
1472 #ifdef _DEBUG
1473 fwrite(ptr, 1, nBytes, netstackdump_read);
1474 #endif
1476 if (nBytes == 0)
1478 RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
1479 /*goto again; */
1480 RTMP_Close(r);
1481 break;
1484 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1485 r->m_resplen -= nBytes;
1487 #ifdef CRYPTO
1488 if (r->Link.rc4keyIn)
1490 RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
1492 #endif
1494 n -= nBytes;
1495 ptr += nBytes;
1498 return nOriginalSize - n;
1501 static int
1502 WriteN(RTMP *r, const char *buffer, int n)
1504 const char *ptr = buffer;
1505 #ifdef CRYPTO
1506 char *encrypted = 0;
1507 char buf[RTMP_BUFFER_CACHE_SIZE];
1509 if (r->Link.rc4keyOut)
1511 if (n > sizeof(buf))
1512 encrypted = (char *)malloc(n);
1513 else
1514 encrypted = (char *)buf;
1515 ptr = encrypted;
1516 RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
1518 #endif
1520 while (n > 0)
1522 int nBytes;
1524 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1525 nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
1526 else
1527 nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
1528 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
1530 if (nBytes < 0)
1532 int sockerr = GetSockError();
1533 RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
1534 sockerr, n);
1536 if (sockerr == EINTR && !RTMP_ctrlC)
1537 continue;
1539 RTMP_Close(r);
1540 n = 1;
1541 break;
1544 if (nBytes == 0)
1545 break;
1547 n -= nBytes;
1548 ptr += nBytes;
1551 #ifdef CRYPTO
1552 if (encrypted && encrypted != buf)
1553 free(encrypted);
1554 #endif
1556 return n == 0;
1559 #define SAVC(x) static const AVal av_##x = AVC(#x)
1561 SAVC(app);
1562 SAVC(connect);
1563 SAVC(flashVer);
1564 SAVC(swfUrl);
1565 SAVC(pageUrl);
1566 SAVC(tcUrl);
1567 SAVC(fpad);
1568 SAVC(capabilities);
1569 SAVC(audioCodecs);
1570 SAVC(videoCodecs);
1571 SAVC(videoFunction);
1572 SAVC(objectEncoding);
1573 SAVC(secureToken);
1574 SAVC(secureTokenResponse);
1575 SAVC(type);
1576 SAVC(nonprivate);
1578 static int
1579 SendConnectPacket(RTMP *r, RTMPPacket *cp)
1581 RTMPPacket packet;
1582 char pbuf[4096], *pend = pbuf + sizeof(pbuf);
1583 char *enc;
1585 if (cp)
1586 return RTMP_SendPacket(r, cp, TRUE);
1588 packet.m_nChannel = 0x03; /* control channel (invoke) */
1589 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1590 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1591 packet.m_nTimeStamp = 0;
1592 packet.m_nInfoField2 = 0;
1593 packet.m_hasAbsTimestamp = 0;
1594 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1596 enc = packet.m_body;
1597 enc = AMF_EncodeString(enc, pend, &av_connect);
1598 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1599 *enc++ = AMF_OBJECT;
1601 enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
1602 if (!enc)
1603 return FALSE;
1604 if (r->Link.protocol & RTMP_FEATURE_WRITE)
1606 enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
1607 if (!enc)
1608 return FALSE;
1610 if (r->Link.flashVer.av_len)
1612 enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
1613 if (!enc)
1614 return FALSE;
1616 if (r->Link.swfUrl.av_len)
1618 enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
1619 if (!enc)
1620 return FALSE;
1622 if (r->Link.tcUrl.av_len)
1624 enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
1625 if (!enc)
1626 return FALSE;
1628 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
1630 enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
1631 if (!enc)
1632 return FALSE;
1633 enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
1634 if (!enc)
1635 return FALSE;
1636 enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
1637 if (!enc)
1638 return FALSE;
1639 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
1640 if (!enc)
1641 return FALSE;
1642 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
1643 if (!enc)
1644 return FALSE;
1645 if (r->Link.pageUrl.av_len)
1647 enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
1648 if (!enc)
1649 return FALSE;
1652 if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
1653 { /* AMF0, AMF3 not fully supported yet */
1654 enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
1655 if (!enc)
1656 return FALSE;
1658 if (enc + 3 >= pend)
1659 return FALSE;
1660 *enc++ = 0;
1661 *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
1662 *enc++ = AMF_OBJECT_END;
1664 /* add auth string */
1665 if (r->Link.auth.av_len)
1667 enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
1668 if (!enc)
1669 return FALSE;
1670 enc = AMF_EncodeString(enc, pend, &r->Link.auth);
1671 if (!enc)
1672 return FALSE;
1674 if (r->Link.extras.o_num)
1676 int i;
1677 for (i = 0; i < r->Link.extras.o_num; i++)
1679 enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
1680 if (!enc)
1681 return FALSE;
1684 packet.m_nBodySize = enc - packet.m_body;
1686 return RTMP_SendPacket(r, &packet, TRUE);
1689 #if 0 /* unused */
1690 SAVC(bgHasStream);
1692 static int
1693 SendBGHasStream(RTMP *r, double dId, AVal *playpath)
1695 RTMPPacket packet;
1696 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1697 char *enc;
1699 packet.m_nChannel = 0x03; /* control channel (invoke) */
1700 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1701 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1702 packet.m_nTimeStamp = 0;
1703 packet.m_nInfoField2 = 0;
1704 packet.m_hasAbsTimestamp = 0;
1705 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1707 enc = packet.m_body;
1708 enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
1709 enc = AMF_EncodeNumber(enc, pend, dId);
1710 *enc++ = AMF_NULL;
1712 enc = AMF_EncodeString(enc, pend, playpath);
1713 if (enc == NULL)
1714 return FALSE;
1716 packet.m_nBodySize = enc - packet.m_body;
1718 return RTMP_SendPacket(r, &packet, TRUE);
1720 #endif
1722 SAVC(createStream);
1725 RTMP_SendCreateStream(RTMP *r)
1727 RTMPPacket packet;
1728 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1729 char *enc;
1731 packet.m_nChannel = 0x03; /* control channel (invoke) */
1732 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1733 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1734 packet.m_nTimeStamp = 0;
1735 packet.m_nInfoField2 = 0;
1736 packet.m_hasAbsTimestamp = 0;
1737 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1739 enc = packet.m_body;
1740 enc = AMF_EncodeString(enc, pend, &av_createStream);
1741 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1742 *enc++ = AMF_NULL; /* NULL */
1744 packet.m_nBodySize = enc - packet.m_body;
1746 return RTMP_SendPacket(r, &packet, TRUE);
1749 SAVC(FCSubscribe);
1751 static int
1752 SendFCSubscribe(RTMP *r, AVal *subscribepath)
1754 RTMPPacket packet;
1755 char pbuf[512], *pend = pbuf + sizeof(pbuf);
1756 char *enc;
1757 packet.m_nChannel = 0x03; /* control channel (invoke) */
1758 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1759 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1760 packet.m_nTimeStamp = 0;
1761 packet.m_nInfoField2 = 0;
1762 packet.m_hasAbsTimestamp = 0;
1763 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1765 RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
1766 enc = packet.m_body;
1767 enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
1768 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1769 *enc++ = AMF_NULL;
1770 enc = AMF_EncodeString(enc, pend, subscribepath);
1772 if (!enc)
1773 return FALSE;
1775 packet.m_nBodySize = enc - packet.m_body;
1777 return RTMP_SendPacket(r, &packet, TRUE);
1780 /* Justin.tv specific authentication */
1781 static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
1783 static int
1784 SendUsherToken(RTMP *r, AVal *usherToken)
1786 RTMPPacket packet;
1787 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1788 char *enc;
1789 packet.m_nChannel = 0x03; /* control channel (invoke) */
1790 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1791 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1792 packet.m_nTimeStamp = 0;
1793 packet.m_nInfoField2 = 0;
1794 packet.m_hasAbsTimestamp = 0;
1795 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1797 RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
1798 enc = packet.m_body;
1799 enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
1800 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1801 *enc++ = AMF_NULL;
1802 enc = AMF_EncodeString(enc, pend, usherToken);
1804 if (!enc)
1805 return FALSE;
1807 packet.m_nBodySize = enc - packet.m_body;
1809 return RTMP_SendPacket(r, &packet, FALSE);
1811 /******************************************/
1813 SAVC(releaseStream);
1815 static int
1816 SendReleaseStream(RTMP *r)
1818 RTMPPacket packet;
1819 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1820 char *enc;
1822 packet.m_nChannel = 0x03; /* control channel (invoke) */
1823 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1824 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1825 packet.m_nTimeStamp = 0;
1826 packet.m_nInfoField2 = 0;
1827 packet.m_hasAbsTimestamp = 0;
1828 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1830 enc = packet.m_body;
1831 enc = AMF_EncodeString(enc, pend, &av_releaseStream);
1832 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1833 *enc++ = AMF_NULL;
1834 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1835 if (!enc)
1836 return FALSE;
1838 packet.m_nBodySize = enc - packet.m_body;
1840 return RTMP_SendPacket(r, &packet, FALSE);
1843 SAVC(FCPublish);
1845 static int
1846 SendFCPublish(RTMP *r)
1848 RTMPPacket packet;
1849 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1850 char *enc;
1852 packet.m_nChannel = 0x03; /* control channel (invoke) */
1853 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1854 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1855 packet.m_nTimeStamp = 0;
1856 packet.m_nInfoField2 = 0;
1857 packet.m_hasAbsTimestamp = 0;
1858 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1860 enc = packet.m_body;
1861 enc = AMF_EncodeString(enc, pend, &av_FCPublish);
1862 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1863 *enc++ = AMF_NULL;
1864 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1865 if (!enc)
1866 return FALSE;
1868 packet.m_nBodySize = enc - packet.m_body;
1870 return RTMP_SendPacket(r, &packet, FALSE);
1873 SAVC(FCUnpublish);
1875 static int
1876 SendFCUnpublish(RTMP *r)
1878 RTMPPacket packet;
1879 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1880 char *enc;
1882 packet.m_nChannel = 0x03; /* control channel (invoke) */
1883 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1884 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1885 packet.m_nTimeStamp = 0;
1886 packet.m_nInfoField2 = 0;
1887 packet.m_hasAbsTimestamp = 0;
1888 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1890 enc = packet.m_body;
1891 enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
1892 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1893 *enc++ = AMF_NULL;
1894 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1895 if (!enc)
1896 return FALSE;
1898 packet.m_nBodySize = enc - packet.m_body;
1900 return RTMP_SendPacket(r, &packet, FALSE);
1903 SAVC(publish);
1904 SAVC(live);
1905 SAVC(record);
1907 static int
1908 SendPublish(RTMP *r)
1910 RTMPPacket packet;
1911 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1912 char *enc;
1914 packet.m_nChannel = 0x04; /* source channel (invoke) */
1915 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1916 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1917 packet.m_nTimeStamp = 0;
1918 packet.m_nInfoField2 = r->m_stream_id;
1919 packet.m_hasAbsTimestamp = 0;
1920 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1922 enc = packet.m_body;
1923 enc = AMF_EncodeString(enc, pend, &av_publish);
1924 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1925 *enc++ = AMF_NULL;
1926 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1927 if (!enc)
1928 return FALSE;
1930 /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
1931 enc = AMF_EncodeString(enc, pend, &av_live);
1932 if (!enc)
1933 return FALSE;
1935 packet.m_nBodySize = enc - packet.m_body;
1937 return RTMP_SendPacket(r, &packet, TRUE);
1940 SAVC(deleteStream);
1942 static int
1943 SendDeleteStream(RTMP *r, double dStreamId)
1945 RTMPPacket packet;
1946 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1947 char *enc;
1949 packet.m_nChannel = 0x03; /* control channel (invoke) */
1950 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1951 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1952 packet.m_nTimeStamp = 0;
1953 packet.m_nInfoField2 = 0;
1954 packet.m_hasAbsTimestamp = 0;
1955 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1957 enc = packet.m_body;
1958 enc = AMF_EncodeString(enc, pend, &av_deleteStream);
1959 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1960 *enc++ = AMF_NULL;
1961 enc = AMF_EncodeNumber(enc, pend, dStreamId);
1963 packet.m_nBodySize = enc - packet.m_body;
1965 /* no response expected */
1966 return RTMP_SendPacket(r, &packet, FALSE);
1969 SAVC(pause);
1972 RTMP_SendPause(RTMP *r, int DoPause, int iTime)
1974 RTMPPacket packet;
1975 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1976 char *enc;
1978 packet.m_nChannel = 0x08; /* video channel */
1979 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1980 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1981 packet.m_nTimeStamp = 0;
1982 packet.m_nInfoField2 = 0;
1983 packet.m_hasAbsTimestamp = 0;
1984 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1986 enc = packet.m_body;
1987 enc = AMF_EncodeString(enc, pend, &av_pause);
1988 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1989 *enc++ = AMF_NULL;
1990 enc = AMF_EncodeBoolean(enc, pend, DoPause);
1991 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
1993 packet.m_nBodySize = enc - packet.m_body;
1995 RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
1996 return RTMP_SendPacket(r, &packet, TRUE);
1999 int RTMP_Pause(RTMP *r, int DoPause)
2001 if (DoPause)
2002 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
2003 r->m_channelTimestamp[r->m_mediaChannel] : 0;
2004 return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
2007 SAVC(seek);
2010 RTMP_SendSeek(RTMP *r, int iTime)
2012 RTMPPacket packet;
2013 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2014 char *enc;
2016 packet.m_nChannel = 0x08; /* video channel */
2017 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2018 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2019 packet.m_nTimeStamp = 0;
2020 packet.m_nInfoField2 = 0;
2021 packet.m_hasAbsTimestamp = 0;
2022 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2024 enc = packet.m_body;
2025 enc = AMF_EncodeString(enc, pend, &av_seek);
2026 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2027 *enc++ = AMF_NULL;
2028 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
2030 packet.m_nBodySize = enc - packet.m_body;
2032 r->m_read.flags |= RTMP_READ_SEEKING;
2033 r->m_read.nResumeTS = 0;
2035 return RTMP_SendPacket(r, &packet, TRUE);
2039 RTMP_SendServerBW(RTMP *r)
2041 RTMPPacket packet;
2042 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2044 packet.m_nChannel = 0x02; /* control channel (invoke) */
2045 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2046 packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
2047 packet.m_nTimeStamp = 0;
2048 packet.m_nInfoField2 = 0;
2049 packet.m_hasAbsTimestamp = 0;
2050 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2052 packet.m_nBodySize = 4;
2054 AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
2055 return RTMP_SendPacket(r, &packet, FALSE);
2059 RTMP_SendClientBW(RTMP *r)
2061 RTMPPacket packet;
2062 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2064 packet.m_nChannel = 0x02; /* control channel (invoke) */
2065 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2066 packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
2067 packet.m_nTimeStamp = 0;
2068 packet.m_nInfoField2 = 0;
2069 packet.m_hasAbsTimestamp = 0;
2070 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2072 packet.m_nBodySize = 5;
2074 AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
2075 packet.m_body[4] = r->m_nClientBW2;
2076 return RTMP_SendPacket(r, &packet, FALSE);
2079 static int
2080 SendBytesReceived(RTMP *r)
2082 RTMPPacket packet;
2083 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2085 packet.m_nChannel = 0x02; /* control channel (invoke) */
2086 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2087 packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
2088 packet.m_nTimeStamp = 0;
2089 packet.m_nInfoField2 = 0;
2090 packet.m_hasAbsTimestamp = 0;
2091 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2093 packet.m_nBodySize = 4;
2095 AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
2096 r->m_nBytesInSent = r->m_nBytesIn;
2098 /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
2099 return RTMP_SendPacket(r, &packet, FALSE);
2102 SAVC(_checkbw);
2104 static int
2105 SendCheckBW(RTMP *r)
2107 RTMPPacket packet;
2108 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2109 char *enc;
2111 packet.m_nChannel = 0x03; /* control channel (invoke) */
2112 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2113 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2114 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2115 packet.m_nInfoField2 = 0;
2116 packet.m_hasAbsTimestamp = 0;
2117 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2119 enc = packet.m_body;
2120 enc = AMF_EncodeString(enc, pend, &av__checkbw);
2121 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2122 *enc++ = AMF_NULL;
2124 packet.m_nBodySize = enc - packet.m_body;
2126 /* triggers _onbwcheck and eventually results in _onbwdone */
2127 return RTMP_SendPacket(r, &packet, FALSE);
2130 SAVC(_result);
2132 static int
2133 SendCheckBWResult(RTMP *r, double txn)
2135 RTMPPacket packet;
2136 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2137 char *enc;
2139 packet.m_nChannel = 0x03; /* control channel (invoke) */
2140 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2141 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2142 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2143 packet.m_nInfoField2 = 0;
2144 packet.m_hasAbsTimestamp = 0;
2145 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2147 enc = packet.m_body;
2148 enc = AMF_EncodeString(enc, pend, &av__result);
2149 enc = AMF_EncodeNumber(enc, pend, txn);
2150 *enc++ = AMF_NULL;
2151 enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
2153 packet.m_nBodySize = enc - packet.m_body;
2155 return RTMP_SendPacket(r, &packet, FALSE);
2158 SAVC(ping);
2159 SAVC(pong);
2161 static int
2162 SendPong(RTMP *r, double txn)
2164 RTMPPacket packet;
2165 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2166 char *enc;
2168 packet.m_nChannel = 0x03; /* control channel (invoke) */
2169 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2170 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2171 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2172 packet.m_nInfoField2 = 0;
2173 packet.m_hasAbsTimestamp = 0;
2174 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2176 enc = packet.m_body;
2177 enc = AMF_EncodeString(enc, pend, &av_pong);
2178 enc = AMF_EncodeNumber(enc, pend, txn);
2179 *enc++ = AMF_NULL;
2181 packet.m_nBodySize = enc - packet.m_body;
2183 return RTMP_SendPacket(r, &packet, FALSE);
2186 SAVC(play);
2188 static int
2189 SendPlay(RTMP *r)
2191 RTMPPacket packet;
2192 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2193 char *enc;
2195 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2196 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2197 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2198 packet.m_nTimeStamp = 0;
2199 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2200 packet.m_hasAbsTimestamp = 0;
2201 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2203 enc = packet.m_body;
2204 enc = AMF_EncodeString(enc, pend, &av_play);
2205 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2206 *enc++ = AMF_NULL;
2208 RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
2209 __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
2210 r->Link.playpath.av_val);
2211 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
2212 if (!enc)
2213 return FALSE;
2215 /* Optional parameters start and len.
2217 * start: -2, -1, 0, positive number
2218 * -2: looks for a live stream, then a recorded stream,
2219 * if not found any open a live stream
2220 * -1: plays a live stream
2221 * >=0: plays a recorded streams from 'start' milliseconds
2223 if (r->Link.lFlags & RTMP_LF_LIVE)
2224 enc = AMF_EncodeNumber(enc, pend, -1000.0);
2225 else
2227 if (r->Link.seekTime > 0.0)
2228 enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
2229 else
2230 enc = AMF_EncodeNumber(enc, pend, 0.0); /*-2000.0);*/ /* recorded as default, -2000.0 is not reliable since that freezes the player if the stream is not found */
2232 if (!enc)
2233 return FALSE;
2235 /* len: -1, 0, positive number
2236 * -1: plays live or recorded stream to the end (default)
2237 * 0: plays a frame 'start' ms away from the beginning
2238 * >0: plays a live or recoded stream for 'len' milliseconds
2240 /*enc += EncodeNumber(enc, -1.0); */ /* len */
2241 if (r->Link.stopTime)
2243 enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
2244 if (!enc)
2245 return FALSE;
2248 packet.m_nBodySize = enc - packet.m_body;
2250 return RTMP_SendPacket(r, &packet, TRUE);
2253 SAVC(set_playlist);
2254 SAVC(0);
2256 static int
2257 SendPlaylist(RTMP *r)
2259 RTMPPacket packet;
2260 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2261 char *enc;
2263 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2264 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2265 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2266 packet.m_nTimeStamp = 0;
2267 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2268 packet.m_hasAbsTimestamp = 0;
2269 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2271 enc = packet.m_body;
2272 enc = AMF_EncodeString(enc, pend, &av_set_playlist);
2273 enc = AMF_EncodeNumber(enc, pend, 0);
2274 *enc++ = AMF_NULL;
2275 *enc++ = AMF_ECMA_ARRAY;
2276 *enc++ = 0;
2277 *enc++ = 0;
2278 *enc++ = 0;
2279 *enc++ = AMF_OBJECT;
2280 enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.playpath);
2281 if (!enc)
2282 return FALSE;
2283 if (enc + 3 >= pend)
2284 return FALSE;
2285 *enc++ = 0;
2286 *enc++ = 0;
2287 *enc++ = AMF_OBJECT_END;
2289 packet.m_nBodySize = enc - packet.m_body;
2291 return RTMP_SendPacket(r, &packet, TRUE);
2294 static int
2295 SendSecureTokenResponse(RTMP *r, AVal *resp)
2297 RTMPPacket packet;
2298 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2299 char *enc;
2301 packet.m_nChannel = 0x03; /* control channel (invoke) */
2302 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2303 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2304 packet.m_nTimeStamp = 0;
2305 packet.m_nInfoField2 = 0;
2306 packet.m_hasAbsTimestamp = 0;
2307 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2309 enc = packet.m_body;
2310 enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
2311 enc = AMF_EncodeNumber(enc, pend, 0.0);
2312 *enc++ = AMF_NULL;
2313 enc = AMF_EncodeString(enc, pend, resp);
2314 if (!enc)
2315 return FALSE;
2317 packet.m_nBodySize = enc - packet.m_body;
2319 return RTMP_SendPacket(r, &packet, FALSE);
2323 from http://jira.red5.org/confluence/display/docs/Ping:
2325 Ping is the most mysterious message in RTMP and till now we haven't fully interpreted it yet. In summary, Ping message is used as a special command that are exchanged between client and server. This page aims to document all known Ping messages. Expect the list to grow.
2327 The type of Ping packet is 0x4 and contains two mandatory parameters and two optional parameters. The first parameter is the type of Ping and in short integer. The second parameter is the target of the ping. As Ping is always sent in Channel 2 (control channel) and the target object in RTMP header is always 0 which means the Connection object, it's necessary to put an extra parameter to indicate the exact target object the Ping is sent to. The second parameter takes this responsibility. The value has the same meaning as the target object field in RTMP header. (The second value could also be used as other purposes, like RTT Ping/Pong. It is used as the timestamp.) The third and fourth parameters are optional and could be looked upon as the parameter of the Ping packet. Below is an unexhausted list of Ping messages.
2329 * type 0: Clear the stream. No third and fourth parameters. The second parameter could be 0. After the connection is established, a Ping 0,0 will be sent from server to client. The message will also be sent to client on the start of Play and in response of a Seek or Pause/Resume request. This Ping tells client to re-calibrate the clock with the timestamp of the next packet server sends.
2330 * type 1: Tell the stream to clear the playing buffer.
2331 * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
2332 * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
2333 * type 6: Ping the client from server. The second parameter is the current time.
2334 * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
2335 * type 26: SWFVerification request
2336 * type 27: SWFVerification response
2339 RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
2341 RTMPPacket packet;
2342 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2343 int nSize;
2344 char *buf;
2346 RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
2348 packet.m_nChannel = 0x02; /* control channel (ping) */
2349 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2350 packet.m_packetType = RTMP_PACKET_TYPE_CONTROL;
2351 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2352 packet.m_nInfoField2 = 0;
2353 packet.m_hasAbsTimestamp = 0;
2354 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2356 switch(nType) {
2357 case 0x03: nSize = 10; break; /* buffer time */
2358 case 0x1A: nSize = 3; break; /* SWF verify request */
2359 case 0x1B: nSize = 44; break; /* SWF verify response */
2360 default: nSize = 6; break;
2363 packet.m_nBodySize = nSize;
2365 buf = packet.m_body;
2366 buf = AMF_EncodeInt16(buf, pend, nType);
2368 if (nType == 0x1B)
2370 #ifdef CRYPTO
2371 memcpy(buf, r->Link.SWFVerificationResponse, 42);
2372 RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
2373 RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
2374 #endif
2376 else if (nType == 0x1A)
2378 *buf = nObject & 0xff;
2380 else
2382 if (nSize > 2)
2383 buf = AMF_EncodeInt32(buf, pend, nObject);
2385 if (nSize > 6)
2386 buf = AMF_EncodeInt32(buf, pend, nTime);
2389 return RTMP_SendPacket(r, &packet, FALSE);
2392 static void
2393 AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
2395 if (freeit)
2396 free(vals[i].name.av_val);
2397 (*num)--;
2398 for (; i < *num; i++)
2400 vals[i] = vals[i + 1];
2402 vals[i].name.av_val = NULL;
2403 vals[i].name.av_len = 0;
2404 vals[i].num = 0;
2407 void
2408 RTMP_DropRequest(RTMP *r, int i, int freeit)
2410 AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
2413 static void
2414 AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
2416 char *tmp;
2417 if (!(*num & 0x0f))
2418 *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
2419 tmp = malloc(av->av_len + 1);
2420 memcpy(tmp, av->av_val, av->av_len);
2421 tmp[av->av_len] = '\0';
2422 (*vals)[*num].num = txn;
2423 (*vals)[*num].name.av_len = av->av_len;
2424 (*vals)[(*num)++].name.av_val = tmp;
2427 static void
2428 AV_clear(RTMP_METHOD *vals, int num)
2430 int i;
2431 for (i = 0; i < num; i++)
2432 free(vals[i].name.av_val);
2433 free(vals);
2437 #ifdef CRYPTO
2438 static int
2439 b64enc(const unsigned char *input, int length, char *output, int maxsize)
2441 #ifdef USE_POLARSSL
2442 size_t buf_size = maxsize;
2443 if(base64_encode((unsigned char *) output, &buf_size, input, length) == 0)
2445 output[buf_size] = '\0';
2446 return 1;
2448 else
2450 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2451 return 0;
2453 #elif defined(USE_GNUTLS)
2454 if (BASE64_ENCODE_RAW_LENGTH(length) <= maxsize)
2455 base64_encode_raw((uint8_t*) output, length, input);
2456 else
2458 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2459 return 0;
2461 #else /* USE_OPENSSL */
2462 BIO *bmem, *b64;
2463 BUF_MEM *bptr;
2465 b64 = BIO_new(BIO_f_base64());
2466 bmem = BIO_new(BIO_s_mem());
2467 b64 = BIO_push(b64, bmem);
2468 BIO_write(b64, input, length);
2469 if (BIO_flush(b64) == 1)
2471 BIO_get_mem_ptr(b64, &bptr);
2472 memcpy(output, bptr->data, bptr->length-1);
2473 output[bptr->length-1] = '\0';
2475 else
2477 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2478 return 0;
2480 BIO_free_all(b64);
2481 #endif
2482 return 1;
2485 #ifdef USE_POLARSSL
2486 #define MD5_CTX md5_context
2487 #define MD5_Init(ctx) md5_starts(ctx)
2488 #define MD5_Update(ctx,data,len) md5_update(ctx,(unsigned char *)data,len)
2489 #define MD5_Final(dig,ctx) md5_finish(ctx,dig)
2490 #elif defined(USE_GNUTLS)
2491 typedef struct md5_ctx MD5_CTX;
2492 #define MD5_Init(ctx) md5_init(ctx)
2493 #define MD5_Update(ctx,data,len) md5_update(ctx,len,data)
2494 #define MD5_Final(dig,ctx) md5_digest(ctx,MD5_DIGEST_LENGTH,dig)
2495 #else
2496 #endif
2498 static const AVal av_authmod_adobe = AVC("authmod=adobe");
2499 static const AVal av_authmod_llnw = AVC("authmod=llnw");
2501 static void hexenc(unsigned char *inbuf, int len, char *dst)
2503 char *ptr = dst;
2504 while(len--) {
2505 sprintf(ptr, "%02x", *inbuf++);
2506 ptr += 2;
2508 *ptr = '\0';
2511 static char *
2512 AValChr(AVal *av, char c)
2514 int i;
2515 for (i = 0; i < av->av_len; i++)
2516 if (av->av_val[i] == c)
2517 return &av->av_val[i];
2518 return NULL;
2521 static int
2522 PublisherAuth(RTMP *r, AVal *description)
2524 char *token_in = NULL;
2525 char *ptr;
2526 unsigned char md5sum_val[MD5_DIGEST_LENGTH+1];
2527 MD5_CTX md5ctx;
2528 int challenge2_data;
2529 #define RESPONSE_LEN 32
2530 #define CHALLENGE2_LEN 16
2531 #define SALTED2_LEN (32+8+8+8)
2532 #define B64DIGEST_LEN 24 /* 16 byte digest => 22 b64 chars + 2 chars padding */
2533 #define B64INT_LEN 8 /* 4 byte int => 6 b64 chars + 2 chars padding */
2534 #define HEXHASH_LEN (2*MD5_DIGEST_LENGTH)
2535 char response[RESPONSE_LEN];
2536 char challenge2[CHALLENGE2_LEN];
2537 char salted2[SALTED2_LEN];
2538 AVal pubToken;
2540 if (strstr(description->av_val, av_authmod_adobe.av_val) != NULL)
2542 if(strstr(description->av_val, "code=403 need auth") != NULL)
2544 if (strstr(r->Link.app.av_val, av_authmod_adobe.av_val) != NULL) {
2545 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2546 return 0;
2547 } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
2548 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8);
2549 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2550 av_authmod_adobe.av_val,
2551 r->Link.pubUser.av_val);
2552 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2553 } else {
2554 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2555 return 0;
2558 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2560 char *par, *val = NULL, *orig_ptr;
2561 AVal user, salt, opaque, challenge, *aptr = NULL;
2562 opaque.av_len = 0;
2563 challenge.av_len = 0;
2565 ptr = orig_ptr = strdup(token_in);
2566 while (ptr)
2568 par = ptr;
2569 ptr = strchr(par, '&');
2570 if(ptr)
2571 *ptr++ = '\0';
2573 val = strchr(par, '=');
2574 if(val)
2575 *val++ = '\0';
2577 if (aptr) {
2578 aptr->av_len = par - aptr->av_val - 1;
2579 aptr = NULL;
2581 if (strcmp(par, "user") == 0){
2582 user.av_val = val;
2583 aptr = &user;
2584 } else if (strcmp(par, "salt") == 0){
2585 salt.av_val = val;
2586 aptr = &salt;
2587 } else if (strcmp(par, "opaque") == 0){
2588 opaque.av_val = val;
2589 aptr = &opaque;
2590 } else if (strcmp(par, "challenge") == 0){
2591 challenge.av_val = val;
2592 aptr = &challenge;
2595 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2597 if (aptr)
2598 aptr->av_len = strlen(aptr->av_val);
2600 /* hash1 = base64enc(md5(user + _aodbeAuthSalt + password)) */
2601 MD5_Init(&md5ctx);
2602 MD5_Update(&md5ctx, user.av_val, user.av_len);
2603 MD5_Update(&md5ctx, salt.av_val, salt.av_len);
2604 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2605 MD5_Final(md5sum_val, &md5ctx);
2606 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2607 user.av_val, salt.av_val, r->Link.pubPasswd.av_val);
2608 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2610 b64enc(md5sum_val, MD5_DIGEST_LENGTH, salted2, SALTED2_LEN);
2611 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_1) = %s", __FUNCTION__, salted2);
2613 challenge2_data = rand();
2615 b64enc((unsigned char *) &challenge2_data, sizeof(int), challenge2, CHALLENGE2_LEN);
2616 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(%d) = %s", __FUNCTION__, challenge2_data, challenge2);
2618 MD5_Init(&md5ctx);
2619 MD5_Update(&md5ctx, salted2, B64DIGEST_LEN);
2620 /* response = base64enc(md5(hash1 + opaque + challenge2)) */
2621 if (opaque.av_len)
2622 MD5_Update(&md5ctx, opaque.av_val, opaque.av_len);
2623 else if (challenge.av_len)
2624 MD5_Update(&md5ctx, challenge.av_val, challenge.av_len);
2625 MD5_Update(&md5ctx, challenge2, B64INT_LEN);
2626 MD5_Final(md5sum_val, &md5ctx);
2628 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2629 salted2, opaque.av_len ? opaque.av_val : "", challenge2);
2630 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2632 b64enc(md5sum_val, MD5_DIGEST_LENGTH, response, RESPONSE_LEN);
2633 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response);
2635 /* have all hashes, create auth token for the end of app */
2636 pubToken.av_val = malloc(32 + B64INT_LEN + B64DIGEST_LEN + opaque.av_len);
2637 pubToken.av_len = sprintf(pubToken.av_val,
2638 "&challenge=%s&response=%s&opaque=%s",
2639 challenge2,
2640 response,
2641 opaque.av_len ? opaque.av_val : "");
2642 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2643 free(orig_ptr);
2645 else if(strstr(description->av_val, "?reason=authfailed") != NULL)
2647 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: wrong password", __FUNCTION__);
2648 return 0;
2650 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
2652 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
2653 return 0;
2655 else
2657 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
2658 __FUNCTION__, description->av_val);
2659 return 0;
2662 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
2663 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
2664 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
2665 r->Link.app.av_len += pubToken.av_len;
2666 if(r->Link.lFlags & RTMP_LF_FAPU)
2667 free(r->Link.app.av_val);
2668 r->Link.app.av_val = ptr;
2670 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
2671 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
2672 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
2673 r->Link.tcUrl.av_len += pubToken.av_len;
2674 if(r->Link.lFlags & RTMP_LF_FTCU)
2675 free(r->Link.tcUrl.av_val);
2676 r->Link.tcUrl.av_val = ptr;
2678 free(pubToken.av_val);
2679 r->Link.lFlags |= RTMP_LF_FTCU | RTMP_LF_FAPU;
2681 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
2682 r->Link.app.av_len, r->Link.app.av_val,
2683 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
2684 r->Link.playpath.av_val);
2686 else if (strstr(description->av_val, av_authmod_llnw.av_val) != NULL)
2688 if(strstr(description->av_val, "code=403 need auth") != NULL)
2690 /* This part seems to be the same for llnw and adobe */
2692 if (strstr(r->Link.app.av_val, av_authmod_llnw.av_val) != NULL) {
2693 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2694 return 0;
2695 } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
2696 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8);
2697 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2698 av_authmod_llnw.av_val,
2699 r->Link.pubUser.av_val);
2700 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2701 } else {
2702 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2703 return 0;
2706 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2708 char *orig_ptr;
2709 char *par, *val = NULL;
2710 char hash1[HEXHASH_LEN+1], hash2[HEXHASH_LEN+1], hash3[HEXHASH_LEN+1];
2711 AVal user, nonce, *aptr = NULL;
2712 AVal apptmp;
2714 /* llnw auth method
2715 * Seems to be closely based on HTTP Digest Auth:
2716 * http://tools.ietf.org/html/rfc2617
2717 * http://en.wikipedia.org/wiki/Digest_access_authentication
2720 const char authmod[] = "llnw";
2721 const char realm[] = "live";
2722 const char method[] = "publish";
2723 const char qop[] = "auth";
2724 /* nc = 1..connection count (or rather, number of times cnonce has been reused) */
2725 int nc = 1;
2726 /* nchex = hexenc(nc) (8 hex digits according to RFC 2617) */
2727 char nchex[9];
2728 /* cnonce = hexenc(4 random bytes) (initialized on first connection) */
2729 char cnonce[9];
2731 ptr = orig_ptr = strdup(token_in);
2732 /* Extract parameters (we need user and nonce) */
2733 while (ptr)
2735 par = ptr;
2736 ptr = strchr(par, '&');
2737 if(ptr)
2738 *ptr++ = '\0';
2740 val = strchr(par, '=');
2741 if(val)
2742 *val++ = '\0';
2744 if (aptr) {
2745 aptr->av_len = par - aptr->av_val - 1;
2746 aptr = NULL;
2748 if (strcmp(par, "user") == 0){
2749 user.av_val = val;
2750 aptr = &user;
2751 } else if (strcmp(par, "nonce") == 0){
2752 nonce.av_val = val;
2753 aptr = &nonce;
2756 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2758 if (aptr)
2759 aptr->av_len = strlen(aptr->av_val);
2761 /* FIXME: handle case where user==NULL or nonce==NULL */
2763 sprintf(nchex, "%08x", nc);
2764 sprintf(cnonce, "%08x", rand());
2766 /* hash1 = hexenc(md5(user + ":" + realm + ":" + password)) */
2767 MD5_Init(&md5ctx);
2768 MD5_Update(&md5ctx, user.av_val, user.av_len);
2769 MD5_Update(&md5ctx, ":", 1);
2770 MD5_Update(&md5ctx, realm, sizeof(realm)-1);
2771 MD5_Update(&md5ctx, ":", 1);
2772 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2773 MD5_Final(md5sum_val, &md5ctx);
2774 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s) =>", __FUNCTION__,
2775 user.av_val, realm, r->Link.pubPasswd.av_val);
2776 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2777 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash1);
2779 /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */
2780 /* Extract appname + appinstance without query parameters */
2781 apptmp = r->Link.app;
2782 ptr = AValChr(&apptmp, '?');
2783 if (ptr)
2784 apptmp.av_len = ptr - apptmp.av_val;
2786 MD5_Init(&md5ctx);
2787 MD5_Update(&md5ctx, method, sizeof(method)-1);
2788 MD5_Update(&md5ctx, ":/", 2);
2789 MD5_Update(&md5ctx, apptmp.av_val, apptmp.av_len);
2790 if (!AValChr(&apptmp, '/'))
2791 MD5_Update(&md5ctx, "/_definst_", sizeof("/_definst_") - 1);
2792 MD5_Final(md5sum_val, &md5ctx);
2793 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:/%.*s) =>", __FUNCTION__,
2794 method, apptmp.av_len, apptmp.av_val);
2795 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2796 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash2);
2798 /* hash3 = hexenc(md5(hash1 + ":" + nonce + ":" + nchex + ":" + cnonce + ":" + qop + ":" + hash2)) */
2799 MD5_Init(&md5ctx);
2800 MD5_Update(&md5ctx, hash1, HEXHASH_LEN);
2801 MD5_Update(&md5ctx, ":", 1);
2802 MD5_Update(&md5ctx, nonce.av_val, nonce.av_len);
2803 MD5_Update(&md5ctx, ":", 1);
2804 MD5_Update(&md5ctx, nchex, sizeof(nchex)-1);
2805 MD5_Update(&md5ctx, ":", 1);
2806 MD5_Update(&md5ctx, cnonce, sizeof(cnonce)-1);
2807 MD5_Update(&md5ctx, ":", 1);
2808 MD5_Update(&md5ctx, qop, sizeof(qop)-1);
2809 MD5_Update(&md5ctx, ":", 1);
2810 MD5_Update(&md5ctx, hash2, HEXHASH_LEN);
2811 MD5_Final(md5sum_val, &md5ctx);
2812 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s:%s:%s:%s) =>", __FUNCTION__,
2813 hash1, nonce.av_val, nchex, cnonce, qop, hash2);
2814 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2815 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash3);
2817 /* pubToken = &authmod=<authmod>&user=<username>&nonce=<nonce>&cnonce=<cnonce>&nc=<nchex>&response=<hash3> */
2818 /* Append nonces and response to query string which already contains
2819 * user + authmod */
2820 pubToken.av_val = malloc(64 + sizeof(authmod)-1 + user.av_len + nonce.av_len + sizeof(cnonce)-1 + sizeof(nchex)-1 + HEXHASH_LEN);
2821 sprintf(pubToken.av_val,
2822 "&nonce=%s&cnonce=%s&nc=%s&response=%s",
2823 nonce.av_val, cnonce, nchex, hash3);
2824 pubToken.av_len = strlen(pubToken.av_val);
2825 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2827 free(orig_ptr);
2829 else if(strstr(description->av_val, "?reason=authfail") != NULL)
2831 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed", __FUNCTION__);
2832 return 0;
2834 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
2836 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
2837 return 0;
2839 else
2841 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
2842 __FUNCTION__, description->av_val);
2843 return 0;
2846 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
2847 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
2848 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
2849 r->Link.app.av_len += pubToken.av_len;
2850 if(r->Link.lFlags & RTMP_LF_FAPU)
2851 free(r->Link.app.av_val);
2852 r->Link.app.av_val = ptr;
2854 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
2855 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
2856 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
2857 r->Link.tcUrl.av_len += pubToken.av_len;
2858 if(r->Link.lFlags & RTMP_LF_FTCU)
2859 free(r->Link.tcUrl.av_val);
2860 r->Link.tcUrl.av_val = ptr;
2862 free(pubToken.av_val);
2863 r->Link.lFlags |= RTMP_LF_FTCU | RTMP_LF_FAPU;
2865 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
2866 r->Link.app.av_len, r->Link.app.av_val,
2867 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
2868 r->Link.playpath.av_val);
2870 else
2872 return 0;
2874 return 1;
2876 #endif
2879 SAVC(onBWDone);
2880 SAVC(onFCSubscribe);
2881 SAVC(onFCUnsubscribe);
2882 SAVC(_onbwcheck);
2883 SAVC(_onbwdone);
2884 SAVC(_error);
2885 SAVC(close);
2886 SAVC(code);
2887 SAVC(level);
2888 SAVC(description);
2889 SAVC(onStatus);
2890 SAVC(playlist_ready);
2891 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
2892 static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
2893 static const AVal av_NetStream_Play_StreamNotFound =
2894 AVC("NetStream.Play.StreamNotFound");
2895 static const AVal av_NetConnection_Connect_InvalidApp =
2896 AVC("NetConnection.Connect.InvalidApp");
2897 static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
2898 static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
2899 static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
2900 static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
2901 static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
2902 static const AVal av_NetStream_Play_PublishNotify =
2903 AVC("NetStream.Play.PublishNotify");
2904 static const AVal av_NetStream_Play_UnpublishNotify =
2905 AVC("NetStream.Play.UnpublishNotify");
2906 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
2907 static const AVal av_NetConnection_Connect_Rejected =
2908 AVC("NetConnection.Connect.Rejected");
2910 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
2911 static int
2912 HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
2914 AMFObject obj;
2915 AVal method;
2916 double txn;
2917 int ret = 0, nRes;
2918 if (body[0] != 0x02) /* make sure it is a string method name we start with */
2920 RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
2921 __FUNCTION__);
2922 return 0;
2925 nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
2926 if (nRes < 0)
2928 RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
2929 return 0;
2932 AMF_Dump(&obj);
2933 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
2934 txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
2935 RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
2937 if (AVMATCH(&method, &av__result))
2939 AVal methodInvoked = {0};
2940 int i;
2942 for (i=0; i<r->m_numCalls; i++) {
2943 if (r->m_methodCalls[i].num == (int)txn) {
2944 methodInvoked = r->m_methodCalls[i].name;
2945 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
2946 break;
2949 if (!methodInvoked.av_val) {
2950 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
2951 __FUNCTION__, txn);
2952 goto leave;
2955 RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
2956 methodInvoked.av_val);
2958 if (AVMATCH(&methodInvoked, &av_connect))
2960 if (r->Link.token.av_len)
2962 AMFObjectProperty p;
2963 if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
2965 DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
2966 SendSecureTokenResponse(r, &p.p_vu.p_aval);
2969 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2971 SendReleaseStream(r);
2972 SendFCPublish(r);
2974 else
2976 RTMP_SendServerBW(r);
2977 RTMP_SendCtrl(r, 3, 0, 300);
2979 RTMP_SendCreateStream(r);
2981 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
2983 /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
2984 if (r->Link.usherToken.av_len)
2985 SendUsherToken(r, &r->Link.usherToken);
2986 /* Send the FCSubscribe if live stream or if subscribepath is set */
2987 if (r->Link.subscribepath.av_len)
2988 SendFCSubscribe(r, &r->Link.subscribepath);
2989 else if (r->Link.lFlags & RTMP_LF_LIVE)
2990 SendFCSubscribe(r, &r->Link.playpath);
2993 else if (AVMATCH(&methodInvoked, &av_createStream))
2995 r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
2997 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2999 SendPublish(r);
3001 else
3003 if (r->Link.lFlags & RTMP_LF_PLST)
3004 SendPlaylist(r);
3005 SendPlay(r);
3006 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
3009 else if (AVMATCH(&methodInvoked, &av_play) ||
3010 AVMATCH(&methodInvoked, &av_publish))
3012 r->m_bPlaying = TRUE;
3014 free(methodInvoked.av_val);
3016 else if (AVMATCH(&method, &av_onBWDone))
3018 if (!r->m_nBWCheckCounter)
3019 SendCheckBW(r);
3021 else if (AVMATCH(&method, &av_onFCSubscribe))
3023 /* SendOnFCSubscribe(); */
3025 else if (AVMATCH(&method, &av_onFCUnsubscribe))
3027 RTMP_Close(r);
3028 ret = 1;
3030 else if (AVMATCH(&method, &av_ping))
3032 SendPong(r, txn);
3034 else if (AVMATCH(&method, &av__onbwcheck))
3036 SendCheckBWResult(r, txn);
3038 else if (AVMATCH(&method, &av__onbwdone))
3040 int i;
3041 for (i = 0; i < r->m_numCalls; i++)
3042 if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
3044 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3045 break;
3048 else if (AVMATCH(&method, &av__error))
3050 #ifdef CRYPTO
3051 AVal methodInvoked = {0};
3052 int i;
3054 if (r->Link.protocol & RTMP_FEATURE_WRITE)
3056 for (i=0; i<r->m_numCalls; i++)
3058 if (r->m_methodCalls[i].num == txn)
3060 methodInvoked = r->m_methodCalls[i].name;
3061 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
3062 break;
3065 if (!methodInvoked.av_val)
3067 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
3068 __FUNCTION__, txn);
3069 goto leave;
3072 RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__,
3073 methodInvoked.av_val);
3075 if (AVMATCH(&methodInvoked, &av_connect))
3077 AMFObject obj2;
3078 AVal code, level, description;
3079 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3080 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3081 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3082 AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
3083 RTMP_Log(RTMP_LOGDEBUG, "%s, error description: %s", __FUNCTION__, description.av_val);
3084 /* if PublisherAuth returns 1, then reconnect */
3085 if (PublisherAuth(r, &description) == 1)
3087 CloseInternal(r, 1);
3088 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
3089 goto leave;
3093 else
3095 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3097 free(methodInvoked.av_val);
3098 #else
3099 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3100 #endif
3102 else if (AVMATCH(&method, &av_close))
3104 RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
3105 RTMP_Close(r);
3107 else if (AVMATCH(&method, &av_onStatus))
3109 AMFObject obj2;
3110 AVal code, level;
3111 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3112 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3113 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3115 RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
3116 if (AVMATCH(&code, &av_NetStream_Failed)
3117 || AVMATCH(&code, &av_NetStream_Play_Failed)
3118 || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
3119 || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
3121 r->m_stream_id = -1;
3122 RTMP_Close(r);
3123 RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val);
3126 else if (AVMATCH(&code, &av_NetStream_Play_Start)
3127 || AVMATCH(&code, &av_NetStream_Play_PublishNotify))
3129 int i;
3130 r->m_bPlaying = TRUE;
3131 for (i = 0; i < r->m_numCalls; i++)
3133 if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
3135 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3136 break;
3141 else if (AVMATCH(&code, &av_NetStream_Publish_Start))
3143 int i;
3144 r->m_bPlaying = TRUE;
3145 for (i = 0; i < r->m_numCalls; i++)
3147 if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
3149 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3150 break;
3155 /* Return 1 if this is a Play.Complete or Play.Stop */
3156 else if (AVMATCH(&code, &av_NetStream_Play_Complete)
3157 || AVMATCH(&code, &av_NetStream_Play_Stop)
3158 || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
3160 RTMP_Close(r);
3161 ret = 1;
3164 else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
3166 r->m_read.flags &= ~RTMP_READ_SEEKING;
3169 else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
3171 if (r->m_pausing == 1 || r->m_pausing == 2)
3173 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3174 r->m_pausing = 3;
3178 else if (AVMATCH(&method, &av_playlist_ready))
3180 int i;
3181 for (i = 0; i < r->m_numCalls; i++)
3183 if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
3185 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3186 break;
3190 else
3194 leave:
3195 AMF_Reset(&obj);
3196 return ret;
3200 RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
3201 AMFObjectProperty * p)
3203 int n;
3204 /* this is a small object search to locate the "duration" property */
3205 for (n = 0; n < obj->o_num; n++)
3207 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3209 if (AVMATCH(&prop->p_name, name))
3211 memcpy(p, prop, sizeof(*prop));
3212 return TRUE;
3215 if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY)
3217 if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
3218 return TRUE;
3221 return FALSE;
3224 /* Like above, but only check if name is a prefix of property */
3226 RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
3227 AMFObjectProperty * p)
3229 int n;
3230 for (n = 0; n < obj->o_num; n++)
3232 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3234 if (prop->p_name.av_len > name->av_len &&
3235 !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
3237 memcpy(p, prop, sizeof(*prop));
3238 return TRUE;
3241 if (prop->p_type == AMF_OBJECT)
3243 if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
3244 return TRUE;
3247 return FALSE;
3250 static int
3251 DumpMetaData(AMFObject *obj)
3253 AMFObjectProperty *prop;
3254 int n, len;
3255 for (n = 0; n < obj->o_num; n++)
3257 char str[256] = "";
3258 prop = AMF_GetProp(obj, NULL, n);
3259 switch (prop->p_type)
3261 case AMF_OBJECT:
3262 case AMF_ECMA_ARRAY:
3263 case AMF_STRICT_ARRAY:
3264 if (prop->p_name.av_len)
3265 RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
3266 DumpMetaData(&prop->p_vu.p_object);
3267 break;
3268 case AMF_NUMBER:
3269 snprintf(str, 255, "%.2f", prop->p_vu.p_number);
3270 break;
3271 case AMF_BOOLEAN:
3272 snprintf(str, 255, "%s",
3273 prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
3274 break;
3275 case AMF_STRING:
3276 len = snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
3277 prop->p_vu.p_aval.av_val);
3278 if (len >= 1 && str[len-1] == '\n')
3279 str[len-1] = '\0';
3280 break;
3281 case AMF_DATE:
3282 snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
3283 break;
3284 default:
3285 snprintf(str, 255, "INVALID TYPE 0x%02x",
3286 (unsigned char)prop->p_type);
3288 if (str[0] && prop->p_name.av_len)
3290 RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
3291 prop->p_name.av_val, str);
3294 return FALSE;
3297 SAVC(onMetaData);
3298 SAVC(duration);
3299 SAVC(video);
3300 SAVC(audio);
3302 static int
3303 HandleMetadata(RTMP *r, char *body, unsigned int len)
3305 /* allright we get some info here, so parse it and print it */
3306 /* also keep duration or filesize to make a nice progress bar */
3308 AMFObject obj;
3309 AVal metastring;
3310 int ret = FALSE;
3312 int nRes = AMF_Decode(&obj, body, len, FALSE);
3313 if (nRes < 0)
3315 RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
3316 return FALSE;
3319 AMF_Dump(&obj);
3320 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
3322 if (AVMATCH(&metastring, &av_onMetaData))
3324 AMFObjectProperty prop;
3325 /* Show metadata */
3326 RTMP_Log(RTMP_LOGINFO, "Metadata:");
3327 DumpMetaData(&obj);
3328 if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
3330 r->m_fDuration = prop.p_vu.p_number;
3331 /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
3333 /* Search for audio or video tags */
3334 if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
3335 r->m_read.dataType |= 1;
3336 if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
3337 r->m_read.dataType |= 4;
3338 ret = TRUE;
3340 AMF_Reset(&obj);
3341 return ret;
3344 static void
3345 HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
3347 if (packet->m_nBodySize >= 4)
3349 r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
3350 RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
3351 r->m_inChunkSize);
3355 static void
3356 HandleAudio(RTMP *r, const RTMPPacket *packet)
3360 static void
3361 HandleVideo(RTMP *r, const RTMPPacket *packet)
3365 static void
3366 HandleCtrl(RTMP *r, const RTMPPacket *packet)
3368 short nType = -1;
3369 unsigned int tmp;
3370 if (packet->m_body && packet->m_nBodySize >= 2)
3371 nType = AMF_DecodeInt16(packet->m_body);
3372 RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
3373 packet->m_nBodySize);
3374 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3376 if (packet->m_nBodySize >= 6)
3378 switch (nType)
3380 case 0:
3381 tmp = AMF_DecodeInt32(packet->m_body + 2);
3382 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
3383 break;
3385 case 1:
3386 tmp = AMF_DecodeInt32(packet->m_body + 2);
3387 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
3388 if (r->m_pausing == 1)
3389 r->m_pausing = 2;
3390 break;
3392 case 2:
3393 tmp = AMF_DecodeInt32(packet->m_body + 2);
3394 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
3395 break;
3397 case 4:
3398 tmp = AMF_DecodeInt32(packet->m_body + 2);
3399 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
3400 break;
3402 case 6: /* server ping. reply with pong. */
3403 tmp = AMF_DecodeInt32(packet->m_body + 2);
3404 RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
3405 RTMP_SendCtrl(r, 0x07, tmp, 0);
3406 break;
3408 /* FMS 3.5 servers send the following two controls to let the client
3409 * know when the server has sent a complete buffer. I.e., when the
3410 * server has sent an amount of data equal to m_nBufferMS in duration.
3411 * The server meters its output so that data arrives at the client
3412 * in realtime and no faster.
3414 * The rtmpdump program tries to set m_nBufferMS as large as
3415 * possible, to force the server to send data as fast as possible.
3416 * In practice, the server appears to cap this at about 1 hour's
3417 * worth of data. After the server has sent a complete buffer, and
3418 * sends this BufferEmpty message, it will wait until the play
3419 * duration of that buffer has passed before sending a new buffer.
3420 * The BufferReady message will be sent when the new buffer starts.
3421 * (There is no BufferReady message for the very first buffer;
3422 * presumably the Stream Begin message is sufficient for that
3423 * purpose.)
3425 * If the network speed is much faster than the data bitrate, then
3426 * there may be long delays between the end of one buffer and the
3427 * start of the next.
3429 * Since usually the network allows data to be sent at
3430 * faster than realtime, and rtmpdump wants to download the data
3431 * as fast as possible, we use this RTMP_LF_BUFX hack: when we
3432 * get the BufferEmpty message, we send a Pause followed by an
3433 * Unpause. This causes the server to send the next buffer immediately
3434 * instead of waiting for the full duration to elapse. (That's
3435 * also the purpose of the ToggleStream function, which rtmpdump
3436 * calls if we get a read timeout.)
3438 * Media player apps don't need this hack since they are just
3439 * going to play the data in realtime anyway. It also doesn't work
3440 * for live streams since they obviously can only be sent in
3441 * realtime. And it's all moot if the network speed is actually
3442 * slower than the media bitrate.
3444 case 31:
3445 tmp = AMF_DecodeInt32(packet->m_body + 2);
3446 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
3447 if (!(r->Link.lFlags & RTMP_LF_BUFX))
3448 break;
3449 if (!r->m_pausing)
3451 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
3452 r->m_channelTimestamp[r->m_mediaChannel] : 0;
3453 RTMP_SendPause(r, TRUE, r->m_pauseStamp);
3454 r->m_pausing = 1;
3456 else if (r->m_pausing == 2)
3458 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3459 r->m_pausing = 3;
3461 break;
3463 case 32:
3464 tmp = AMF_DecodeInt32(packet->m_body + 2);
3465 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
3466 break;
3468 default:
3469 tmp = AMF_DecodeInt32(packet->m_body + 2);
3470 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
3471 break;
3476 if (nType == 0x1A)
3478 RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
3479 if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
3481 RTMP_Log(RTMP_LOGERROR,
3482 "%s: SWFVerification Type %d request not supported! Patches welcome...",
3483 __FUNCTION__, packet->m_body[2]);
3485 #ifdef CRYPTO
3486 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3488 /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
3489 else if (r->Link.SWFSize)
3491 RTMP_SendCtrl(r, 0x1B, 0, 0);
3493 else
3495 RTMP_Log(RTMP_LOGERROR,
3496 "%s: Ignoring SWFVerification request, use --swfVfy!",
3497 __FUNCTION__);
3499 #else
3500 RTMP_Log(RTMP_LOGERROR,
3501 "%s: Ignoring SWFVerification request, no CRYPTO support!",
3502 __FUNCTION__);
3503 #endif
3507 static void
3508 HandleServerBW(RTMP *r, const RTMPPacket *packet)
3510 r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
3511 RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
3514 static void
3515 HandleClientBW(RTMP *r, const RTMPPacket *packet)
3517 r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
3518 if (packet->m_nBodySize > 4)
3519 r->m_nClientBW2 = packet->m_body[4];
3520 else
3521 r->m_nClientBW2 = -1;
3522 RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
3523 r->m_nClientBW2);
3526 static int
3527 DecodeInt32LE(const char *data)
3529 unsigned char *c = (unsigned char *)data;
3530 unsigned int val;
3532 val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
3533 return val;
3536 static int
3537 EncodeInt32LE(char *output, int nVal)
3539 output[0] = nVal;
3540 nVal >>= 8;
3541 output[1] = nVal;
3542 nVal >>= 8;
3543 output[2] = nVal;
3544 nVal >>= 8;
3545 output[3] = nVal;
3546 return 4;
3550 RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
3552 uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
3553 char *header = (char *)hbuf;
3554 int nSize, hSize, nToRead, nChunk;
3555 int didAlloc = FALSE;
3556 int extendedTimestamp;
3558 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);
3560 if (ReadN(r, (char *)hbuf, 1) == 0)
3562 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
3563 return FALSE;
3566 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3567 packet->m_nChannel = (hbuf[0] & 0x3f);
3568 header++;
3569 if (packet->m_nChannel == 0)
3571 if (ReadN(r, (char *)&hbuf[1], 1) != 1)
3573 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
3574 __FUNCTION__);
3575 return FALSE;
3577 packet->m_nChannel = hbuf[1];
3578 packet->m_nChannel += 64;
3579 header++;
3581 else if (packet->m_nChannel == 1)
3583 int tmp;
3584 if (ReadN(r, (char *)&hbuf[1], 2) != 2)
3586 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
3587 __FUNCTION__);
3588 return FALSE;
3590 tmp = (hbuf[2] << 8) + hbuf[1];
3591 packet->m_nChannel = tmp + 64;
3592 RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
3593 header += 2;
3596 nSize = packetSize[packet->m_headerType];
3598 if (packet->m_nChannel >= r->m_channelsAllocatedIn)
3600 int n = packet->m_nChannel + 10;
3601 int *timestamp = realloc(r->m_channelTimestamp, sizeof(int) * n);
3602 RTMPPacket **packets = realloc(r->m_vecChannelsIn, sizeof(RTMPPacket*) * n);
3603 if (!timestamp)
3604 free(r->m_channelTimestamp);
3605 if (!packets)
3606 free(r->m_vecChannelsIn);
3607 r->m_channelTimestamp = timestamp;
3608 r->m_vecChannelsIn = packets;
3609 if (!timestamp || !packets) {
3610 r->m_channelsAllocatedIn = 0;
3611 return FALSE;
3613 memset(r->m_channelTimestamp + r->m_channelsAllocatedIn, 0, sizeof(int) * (n - r->m_channelsAllocatedIn));
3614 memset(r->m_vecChannelsIn + r->m_channelsAllocatedIn, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedIn));
3615 r->m_channelsAllocatedIn = n;
3618 if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
3619 packet->m_hasAbsTimestamp = TRUE;
3621 else if (nSize < RTMP_LARGE_HEADER_SIZE)
3622 { /* using values from the last message of this channel */
3623 if (r->m_vecChannelsIn[packet->m_nChannel])
3624 memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
3625 sizeof(RTMPPacket));
3628 nSize--;
3630 if (nSize > 0 && ReadN(r, header, nSize) != nSize)
3632 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
3633 __FUNCTION__, (unsigned int)hbuf[0]);
3634 return FALSE;
3637 hSize = nSize + (header - (char *)hbuf);
3639 if (nSize >= 3)
3641 packet->m_nTimeStamp = AMF_DecodeInt24(header);
3643 /*RTMP_Log(RTMP_LOGDEBUG, "%s, reading RTMP packet chunk on channel %x, headersz %i, timestamp %i, abs timestamp %i", __FUNCTION__, packet.m_nChannel, nSize, packet.m_nTimeStamp, packet.m_hasAbsTimestamp); */
3645 if (nSize >= 6)
3647 packet->m_nBodySize = AMF_DecodeInt24(header + 3);
3648 packet->m_nBytesRead = 0;
3650 if (nSize > 6)
3652 packet->m_packetType = header[6];
3654 if (nSize == 11)
3655 packet->m_nInfoField2 = DecodeInt32LE(header + 7);
3660 extendedTimestamp = packet->m_nTimeStamp == 0xffffff;
3661 if (extendedTimestamp)
3663 if (ReadN(r, header + nSize, 4) != 4)
3665 RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
3666 __FUNCTION__);
3667 return FALSE;
3669 packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
3670 hSize += 4;
3673 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
3675 if (packet->m_nBodySize > 0 && packet->m_body == NULL)
3677 if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
3679 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
3680 return FALSE;
3682 didAlloc = TRUE;
3683 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3686 nToRead = packet->m_nBodySize - packet->m_nBytesRead;
3687 nChunk = r->m_inChunkSize;
3688 if (nToRead < nChunk)
3689 nChunk = nToRead;
3691 /* Does the caller want the raw chunk? */
3692 if (packet->m_chunk)
3694 packet->m_chunk->c_headerSize = hSize;
3695 memcpy(packet->m_chunk->c_header, hbuf, hSize);
3696 packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
3697 packet->m_chunk->c_chunkSize = nChunk;
3700 if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
3702 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %u",
3703 __FUNCTION__, packet->m_nBodySize);
3704 return FALSE;
3707 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
3709 packet->m_nBytesRead += nChunk;
3711 /* keep the packet as ref for other packets on this channel */
3712 if (!r->m_vecChannelsIn[packet->m_nChannel])
3713 r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3714 memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
3715 if (extendedTimestamp)
3717 r->m_vecChannelsIn[packet->m_nChannel]->m_nTimeStamp = 0xffffff;
3720 if (RTMPPacket_IsReady(packet))
3722 /* make packet's timestamp absolute */
3723 if (!packet->m_hasAbsTimestamp)
3724 packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
3726 r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
3728 /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
3729 /* arrives and requests to re-use some info (small packet header) */
3730 r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
3731 r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
3732 r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
3734 else
3736 packet->m_body = NULL; /* so it won't be erased on free */
3739 return TRUE;
3742 #ifndef CRYPTO
3743 static int
3744 HandShake(RTMP *r, int FP9HandShake)
3746 int i;
3747 uint32_t uptime, suptime;
3748 int bMatch;
3749 char type;
3750 char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
3751 char serversig[RTMP_SIG_SIZE];
3753 clientbuf[0] = 0x03; /* not encrypted */
3755 uptime = htonl(RTMP_GetTime());
3756 memcpy(clientsig, &uptime, 4);
3758 memset(&clientsig[4], 0, 4);
3760 #ifdef _DEBUG
3761 for (i = 8; i < RTMP_SIG_SIZE; i++)
3762 clientsig[i] = 0xff;
3763 #else
3764 for (i = 8; i < RTMP_SIG_SIZE; i++)
3765 clientsig[i] = (char)(rand() % 256);
3766 #endif
3768 if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
3769 return FALSE;
3771 if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
3772 return FALSE;
3774 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
3776 if (type != clientbuf[0])
3777 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
3778 __FUNCTION__, clientbuf[0], type);
3780 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3781 return FALSE;
3783 /* decode server response */
3785 memcpy(&suptime, serversig, 4);
3786 suptime = ntohl(suptime);
3788 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
3789 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
3790 serversig[4], serversig[5], serversig[6], serversig[7]);
3792 /* 2nd part of handshake */
3793 if (!WriteN(r, serversig, RTMP_SIG_SIZE))
3794 return FALSE;
3796 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3797 return FALSE;
3799 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3800 if (!bMatch)
3802 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3804 return TRUE;
3807 static int
3808 SHandShake(RTMP *r)
3810 int i;
3811 char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1;
3812 char clientsig[RTMP_SIG_SIZE];
3813 uint32_t uptime;
3814 int bMatch;
3816 if (ReadN(r, serverbuf, 1) != 1) /* 0x03 or 0x06 */
3817 return FALSE;
3819 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Request : %02X", __FUNCTION__, serverbuf[0]);
3821 if (serverbuf[0] != 3)
3823 RTMP_Log(RTMP_LOGERROR, "%s: Type unknown: client sent %02X",
3824 __FUNCTION__, serverbuf[0]);
3825 return FALSE;
3828 uptime = htonl(RTMP_GetTime());
3829 memcpy(serversig, &uptime, 4);
3831 memset(&serversig[4], 0, 4);
3832 #ifdef _DEBUG
3833 for (i = 8; i < RTMP_SIG_SIZE; i++)
3834 serversig[i] = 0xff;
3835 #else
3836 for (i = 8; i < RTMP_SIG_SIZE; i++)
3837 serversig[i] = (char)(rand() % 256);
3838 #endif
3840 if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1))
3841 return FALSE;
3843 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3844 return FALSE;
3846 /* decode client response */
3848 memcpy(&uptime, clientsig, 4);
3849 uptime = ntohl(uptime);
3851 RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
3852 RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__,
3853 clientsig[4], clientsig[5], clientsig[6], clientsig[7]);
3855 /* 2nd part of handshake */
3856 if (!WriteN(r, clientsig, RTMP_SIG_SIZE))
3857 return FALSE;
3859 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3860 return FALSE;
3862 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3863 if (!bMatch)
3865 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3867 return TRUE;
3869 #endif
3872 RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
3874 int wrote;
3875 char hbuf[RTMP_MAX_HEADER_SIZE];
3877 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3878 chunk->c_chunkSize);
3879 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
3880 if (chunk->c_chunkSize)
3882 char *ptr = chunk->c_chunk - chunk->c_headerSize;
3883 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
3884 /* save header bytes we're about to overwrite */
3885 memcpy(hbuf, ptr, chunk->c_headerSize);
3886 memcpy(ptr, chunk->c_header, chunk->c_headerSize);
3887 wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
3888 memcpy(ptr, hbuf, chunk->c_headerSize);
3890 else
3891 wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
3892 return wrote;
3896 RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
3898 const RTMPPacket *prevPacket;
3899 uint32_t last = 0;
3900 int nSize;
3901 int hSize, cSize;
3902 char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
3903 uint32_t t;
3904 char *buffer, *tbuf = NULL, *toff = NULL;
3905 int nChunkSize;
3906 int tlen;
3908 if (packet->m_nChannel >= r->m_channelsAllocatedOut)
3910 int n = packet->m_nChannel + 10;
3911 RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket*) * n);
3912 if (!packets) {
3913 free(r->m_vecChannelsOut);
3914 r->m_vecChannelsOut = NULL;
3915 r->m_channelsAllocatedOut = 0;
3916 return FALSE;
3918 r->m_vecChannelsOut = packets;
3919 memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedOut));
3920 r->m_channelsAllocatedOut = n;
3923 prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
3924 if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
3926 /* compress a bit by using the prev packet's attributes */
3927 if (prevPacket->m_nBodySize == packet->m_nBodySize
3928 && prevPacket->m_packetType == packet->m_packetType
3929 && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
3930 packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
3932 if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
3933 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
3934 packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
3935 last = prevPacket->m_nTimeStamp;
3938 if (packet->m_headerType > 3) /* sanity */
3940 RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
3941 (unsigned char)packet->m_headerType);
3942 return FALSE;
3945 nSize = packetSize[packet->m_headerType];
3946 hSize = nSize; cSize = 0;
3947 t = packet->m_nTimeStamp - last;
3949 if (packet->m_body)
3951 header = packet->m_body - nSize;
3952 hend = packet->m_body;
3954 else
3956 header = hbuf + 6;
3957 hend = hbuf + sizeof(hbuf);
3960 if (packet->m_nChannel > 319)
3961 cSize = 2;
3962 else if (packet->m_nChannel > 63)
3963 cSize = 1;
3964 if (cSize)
3966 header -= cSize;
3967 hSize += cSize;
3970 if (t >= 0xffffff)
3972 header -= 4;
3973 hSize += 4;
3974 RTMP_Log(RTMP_LOGWARNING, "Larger timestamp than 24-bit: 0x%x", t);
3977 hptr = header;
3978 c = packet->m_headerType << 6;
3979 switch (cSize)
3981 case 0:
3982 c |= packet->m_nChannel;
3983 break;
3984 case 1:
3985 break;
3986 case 2:
3987 c |= 1;
3988 break;
3990 *hptr++ = c;
3991 if (cSize)
3993 int tmp = packet->m_nChannel - 64;
3994 *hptr++ = tmp & 0xff;
3995 if (cSize == 2)
3996 *hptr++ = tmp >> 8;
3999 if (nSize > 1)
4001 hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
4004 if (nSize > 4)
4006 hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
4007 *hptr++ = packet->m_packetType;
4010 if (nSize > 8)
4011 hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
4013 if (t >= 0xffffff)
4014 hptr = AMF_EncodeInt32(hptr, hend, t);
4016 nSize = packet->m_nBodySize;
4017 buffer = packet->m_body;
4018 nChunkSize = r->m_outChunkSize;
4020 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
4021 nSize);
4022 /* send all chunks in one HTTP request */
4023 if (r->Link.protocol & RTMP_FEATURE_HTTP)
4025 int chunks = (nSize+nChunkSize-1) / nChunkSize;
4026 if (chunks > 1)
4028 tlen = chunks * (cSize + 1) + nSize + hSize;
4029 tbuf = malloc(tlen);
4030 if (!tbuf)
4031 return FALSE;
4032 toff = tbuf;
4035 while (nSize + hSize)
4037 int wrote;
4039 if (nSize < nChunkSize)
4040 nChunkSize = nSize;
4042 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
4043 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
4044 if (tbuf)
4046 memcpy(toff, header, nChunkSize + hSize);
4047 toff += nChunkSize + hSize;
4049 else
4051 wrote = WriteN(r, header, nChunkSize + hSize);
4052 if (!wrote)
4053 return FALSE;
4055 nSize -= nChunkSize;
4056 buffer += nChunkSize;
4057 hSize = 0;
4059 if (nSize > 0)
4061 header = buffer - 1;
4062 hSize = 1;
4063 if (cSize)
4065 header -= cSize;
4066 hSize += cSize;
4068 if (t >= 0xffffff)
4070 header -= 4;
4071 hSize += 4;
4073 *header = (0xc0 | c);
4074 if (cSize)
4076 int tmp = packet->m_nChannel - 64;
4077 header[1] = tmp & 0xff;
4078 if (cSize == 2)
4079 header[2] = tmp >> 8;
4081 if (t >= 0xffffff)
4083 char* extendedTimestamp = header + 1 + cSize;
4084 AMF_EncodeInt32(extendedTimestamp, extendedTimestamp + 4, t);
4088 if (tbuf)
4090 int wrote = WriteN(r, tbuf, toff-tbuf);
4091 free(tbuf);
4092 tbuf = NULL;
4093 if (!wrote)
4094 return FALSE;
4097 /* we invoked a remote method */
4098 if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE)
4100 AVal method;
4101 char *ptr;
4102 ptr = packet->m_body + 1;
4103 AMF_DecodeString(ptr, &method);
4104 RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
4105 /* keep it in call queue till result arrives */
4106 if (queue) {
4107 int txn;
4108 ptr += 3 + method.av_len;
4109 txn = (int)AMF_DecodeNumber(ptr);
4110 AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
4114 if (!r->m_vecChannelsOut[packet->m_nChannel])
4115 r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
4116 memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
4117 return TRUE;
4121 RTMP_Serve(RTMP *r)
4123 return SHandShake(r);
4126 void
4127 RTMP_Close(RTMP *r)
4129 CloseInternal(r, 0);
4132 static void
4133 CloseInternal(RTMP *r, int reconnect)
4135 int i;
4137 if (RTMP_IsConnected(r))
4139 if (r->m_stream_id > 0)
4141 i = r->m_stream_id;
4142 r->m_stream_id = 0;
4143 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
4144 SendFCUnpublish(r);
4145 SendDeleteStream(r, i);
4147 if (r->m_clientID.av_val)
4149 HTTP_Post(r, RTMPT_CLOSE, "", 1);
4150 free(r->m_clientID.av_val);
4151 r->m_clientID.av_val = NULL;
4152 r->m_clientID.av_len = 0;
4154 RTMPSockBuf_Close(&r->m_sb);
4157 r->m_stream_id = -1;
4158 r->m_sb.sb_socket = -1;
4159 r->m_nBWCheckCounter = 0;
4160 r->m_nBytesIn = 0;
4161 r->m_nBytesInSent = 0;
4163 if (r->m_read.flags & RTMP_READ_HEADER) {
4164 free(r->m_read.buf);
4165 r->m_read.buf = NULL;
4167 r->m_read.dataType = 0;
4168 r->m_read.flags = 0;
4169 r->m_read.status = 0;
4170 r->m_read.nResumeTS = 0;
4171 r->m_read.nIgnoredFrameCounter = 0;
4172 r->m_read.nIgnoredFlvFrameCounter = 0;
4174 r->m_write.m_nBytesRead = 0;
4175 RTMPPacket_Free(&r->m_write);
4177 for (i = 0; i < r->m_channelsAllocatedIn; i++)
4179 if (r->m_vecChannelsIn[i])
4181 RTMPPacket_Free(r->m_vecChannelsIn[i]);
4182 free(r->m_vecChannelsIn[i]);
4183 r->m_vecChannelsIn[i] = NULL;
4186 free(r->m_vecChannelsIn);
4187 r->m_vecChannelsIn = NULL;
4188 free(r->m_channelTimestamp);
4189 r->m_channelTimestamp = NULL;
4190 r->m_channelsAllocatedIn = 0;
4191 for (i = 0; i < r->m_channelsAllocatedOut; i++)
4193 if (r->m_vecChannelsOut[i])
4195 free(r->m_vecChannelsOut[i]);
4196 r->m_vecChannelsOut[i] = NULL;
4199 free(r->m_vecChannelsOut);
4200 r->m_vecChannelsOut = NULL;
4201 r->m_channelsAllocatedOut = 0;
4202 AV_clear(r->m_methodCalls, r->m_numCalls);
4203 r->m_methodCalls = NULL;
4204 r->m_numCalls = 0;
4205 r->m_numInvokes = 0;
4207 r->m_bPlaying = FALSE;
4208 r->m_sb.sb_size = 0;
4210 r->m_msgCounter = 0;
4211 r->m_resplen = 0;
4212 r->m_unackd = 0;
4214 if (r->Link.lFlags & RTMP_LF_FTCU && !reconnect)
4216 free(r->Link.tcUrl.av_val);
4217 r->Link.tcUrl.av_val = NULL;
4218 r->Link.lFlags ^= RTMP_LF_FTCU;
4220 if (r->Link.lFlags & RTMP_LF_FAPU && !reconnect)
4222 free(r->Link.app.av_val);
4223 r->Link.app.av_val = NULL;
4224 r->Link.lFlags ^= RTMP_LF_FAPU;
4227 if (!reconnect)
4229 free(r->Link.playpath0.av_val);
4230 r->Link.playpath0.av_val = NULL;
4232 #ifdef CRYPTO
4233 if (r->Link.dh)
4235 MDH_free(r->Link.dh);
4236 r->Link.dh = NULL;
4238 if (r->Link.rc4keyIn)
4240 RC4_free(r->Link.rc4keyIn);
4241 r->Link.rc4keyIn = NULL;
4243 if (r->Link.rc4keyOut)
4245 RC4_free(r->Link.rc4keyOut);
4246 r->Link.rc4keyOut = NULL;
4248 #endif
4252 RTMPSockBuf_Fill(RTMPSockBuf *sb)
4254 int nBytes;
4256 if (!sb->sb_size)
4257 sb->sb_start = sb->sb_buf;
4259 while (1)
4261 nBytes = sizeof(sb->sb_buf) - 1 - sb->sb_size - (sb->sb_start - sb->sb_buf);
4262 #if defined(CRYPTO) && !defined(NO_SSL)
4263 if (sb->sb_ssl)
4265 nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
4267 else
4268 #endif
4270 nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
4272 if (nBytes != -1)
4274 sb->sb_size += nBytes;
4276 else
4278 int sockerr = GetSockError();
4279 RTMP_Log(RTMP_LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
4280 __FUNCTION__, nBytes, sockerr, strerror(sockerr));
4281 if (sockerr == EINTR && !RTMP_ctrlC)
4282 continue;
4284 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
4286 sb->sb_timedout = TRUE;
4287 nBytes = 0;
4290 break;
4293 return nBytes;
4297 RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
4299 int rc;
4301 #ifdef _DEBUG
4302 fwrite(buf, 1, len, netstackdump);
4303 #endif
4305 #if defined(CRYPTO) && !defined(NO_SSL)
4306 if (sb->sb_ssl)
4308 rc = TLS_write(sb->sb_ssl, buf, len);
4310 else
4311 #endif
4313 rc = send(sb->sb_socket, buf, len, 0);
4315 return rc;
4319 RTMPSockBuf_Close(RTMPSockBuf *sb)
4321 #if defined(CRYPTO) && !defined(NO_SSL)
4322 if (sb->sb_ssl)
4324 TLS_shutdown(sb->sb_ssl);
4325 TLS_close(sb->sb_ssl);
4326 sb->sb_ssl = NULL;
4328 #endif
4329 if (sb->sb_socket != -1)
4330 return closesocket(sb->sb_socket);
4331 return 0;
4334 #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
4336 static void
4337 DecodeTEA(AVal *key, AVal *text)
4339 uint32_t *v, k[4] = { 0 }, u;
4340 uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
4341 int32_t p, q;
4342 int i, n;
4343 unsigned char *ptr, *out;
4345 /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
4346 ptr = (unsigned char *)key->av_val;
4347 u = 0;
4348 n = 0;
4349 v = k;
4350 p = key->av_len > 16 ? 16 : key->av_len;
4351 for (i = 0; i < p; i++)
4353 u |= ptr[i] << (n * 8);
4354 if (n == 3)
4356 *v++ = u;
4357 u = 0;
4358 n = 0;
4360 else
4362 n++;
4365 /* any trailing chars */
4366 if (u)
4367 *v = u;
4369 /* prep text: hex2bin, multiples of 4 */
4370 n = (text->av_len + 7) / 8;
4371 out = malloc(n * 8);
4372 ptr = (unsigned char *)text->av_val;
4373 v = (uint32_t *) out;
4374 for (i = 0; i < n; i++)
4376 u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
4377 u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
4378 u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
4379 u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
4380 *v++ = u;
4381 ptr += 8;
4383 v = (uint32_t *) out;
4385 /* http://www.movable-type.co.uk/scripts/tea-block.html */
4386 #define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
4387 z = v[n - 1];
4388 y = v[0];
4389 q = 6 + 52 / n;
4390 sum = q * DELTA;
4391 while (sum != 0)
4393 e = sum >> 2 & 3;
4394 for (p = n - 1; p > 0; p--)
4395 z = v[p - 1], y = v[p] -= MX;
4396 z = v[n - 1];
4397 y = v[0] -= MX;
4398 sum -= DELTA;
4401 text->av_len /= 2;
4402 memcpy(text->av_val, out, text->av_len);
4403 free(out);
4406 static int
4407 HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
4409 char hbuf[512];
4410 int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
4411 "Host: %.*s:%d\r\n"
4412 "Accept: */*\r\n"
4413 "User-Agent: Shockwave Flash\r\n"
4414 "Connection: Keep-Alive\r\n"
4415 "Cache-Control: no-cache\r\n"
4416 "Content-type: application/x-fcs\r\n"
4417 "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
4418 r->m_clientID.av_val ? r->m_clientID.av_val : "",
4419 r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
4420 r->Link.port, len);
4421 RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
4422 hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
4423 r->m_msgCounter++;
4424 r->m_unackd++;
4425 return hlen;
4428 static int
4429 HTTP_read(RTMP *r, int fill)
4431 char *ptr;
4432 int hlen;
4434 restart:
4435 if (fill)
4436 RTMPSockBuf_Fill(&r->m_sb);
4437 if (r->m_sb.sb_size < 13) {
4438 if (fill)
4439 goto restart;
4440 return -2;
4442 if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
4443 return -1;
4444 r->m_sb.sb_start[r->m_sb.sb_size] = '\0';
4445 if (!strstr(r->m_sb.sb_start, "\r\n\r\n")) {
4446 if (fill)
4447 goto restart;
4448 return -2;
4451 ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
4452 while ((ptr = strstr(ptr, "Content-"))) {
4453 if (!strncasecmp(ptr+8, "length:", 7)) break;
4454 ptr += 8;
4456 if (!ptr)
4457 return -1;
4458 hlen = atoi(ptr+16);
4459 ptr = strstr(ptr+16, "\r\n\r\n");
4460 if (!ptr)
4461 return -1;
4462 ptr += 4;
4463 if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size)
4465 if (fill)
4466 goto restart;
4467 return -2;
4469 r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
4470 r->m_sb.sb_start = ptr;
4471 r->m_unackd--;
4473 if (!r->m_clientID.av_val)
4475 r->m_clientID.av_len = hlen;
4476 r->m_clientID.av_val = malloc(hlen+1);
4477 if (!r->m_clientID.av_val)
4478 return -1;
4479 r->m_clientID.av_val[0] = '/';
4480 memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
4481 r->m_clientID.av_val[hlen] = 0;
4482 r->m_sb.sb_size = 0;
4484 else
4486 r->m_polling = *ptr++;
4487 r->m_resplen = hlen - 1;
4488 r->m_sb.sb_start++;
4489 r->m_sb.sb_size--;
4491 return 0;
4494 #define MAX_IGNORED_FRAMES 50
4496 /* Read from the stream until we get a media packet.
4497 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
4498 * packets, 0 if ignorable error, >0 if there is a media packet
4500 static int
4501 Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
4503 uint32_t prevTagSize = 0;
4504 int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
4505 RTMPPacket packet = { 0 };
4506 int recopy = FALSE;
4507 unsigned int size;
4508 char *ptr, *pend;
4509 uint32_t nTimeStamp = 0;
4510 unsigned int len;
4512 rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
4513 while (rtnGetNextMediaPacket)
4515 char *packetBody = packet.m_body;
4516 unsigned int nPacketLen = packet.m_nBodySize;
4518 /* Return RTMP_READ_COMPLETE if this was completed nicely with
4519 * invoke message Play.Stop or Play.Complete
4521 if (rtnGetNextMediaPacket == 2)
4523 RTMP_Log(RTMP_LOGDEBUG,
4524 "Got Play.Complete or Play.Stop from server. "
4525 "Assuming stream is complete");
4526 ret = RTMP_READ_COMPLETE;
4527 break;
4530 r->m_read.dataType |= (((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) << 2) |
4531 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO));
4533 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO && nPacketLen <= 5)
4535 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
4536 nPacketLen);
4537 ret = RTMP_READ_IGNORE;
4538 break;
4540 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO && nPacketLen <= 1)
4542 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
4543 nPacketLen);
4544 ret = RTMP_READ_IGNORE;
4545 break;
4548 if (r->m_read.flags & RTMP_READ_SEEKING)
4550 ret = RTMP_READ_IGNORE;
4551 break;
4553 #ifdef _DEBUG
4554 RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
4555 packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
4556 packet.m_hasAbsTimestamp);
4557 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
4558 RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
4559 #endif
4561 if (r->m_read.flags & RTMP_READ_RESUME)
4563 /* check the header if we get one */
4564 if (packet.m_nTimeStamp == 0)
4566 if (r->m_read.nMetaHeaderSize > 0
4567 && packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4569 AMFObject metaObj;
4570 int nRes =
4571 AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
4572 if (nRes >= 0)
4574 AVal metastring;
4575 AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
4576 &metastring);
4578 if (AVMATCH(&metastring, &av_onMetaData))
4580 /* compare */
4581 if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
4582 (memcmp
4583 (r->m_read.metaHeader, packetBody,
4584 r->m_read.nMetaHeaderSize) != 0))
4586 ret = RTMP_READ_ERROR;
4589 AMF_Reset(&metaObj);
4590 if (ret == RTMP_READ_ERROR)
4591 break;
4595 /* check first keyframe to make sure we got the right position
4596 * in the stream! (the first non ignored frame)
4598 if (r->m_read.nInitialFrameSize > 0)
4600 /* video or audio data */
4601 if (packet.m_packetType == r->m_read.initialFrameType
4602 && r->m_read.nInitialFrameSize == nPacketLen)
4604 /* we don't compare the sizes since the packet can
4605 * contain several FLV packets, just make sure the
4606 * first frame is our keyframe (which we are going
4607 * to rewrite)
4609 if (memcmp
4610 (r->m_read.initialFrame, packetBody,
4611 r->m_read.nInitialFrameSize) == 0)
4613 RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
4614 r->m_read.flags |= RTMP_READ_GOTKF;
4615 /* ignore it! (what about audio data after it? it is
4616 * handled by ignoring all 0ms frames, see below)
4618 ret = RTMP_READ_IGNORE;
4619 break;
4623 /* hande FLV streams, even though the server resends the
4624 * keyframe as an extra video packet it is also included
4625 * in the first FLV stream chunk and we have to compare
4626 * it and filter it out !!
4628 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4630 /* basically we have to find the keyframe with the
4631 * correct TS being nResumeTS
4633 unsigned int pos = 0;
4634 uint32_t ts = 0;
4636 while (pos + 11 < nPacketLen)
4638 /* size without header (11) and prevTagSize (4) */
4639 uint32_t dataSize =
4640 AMF_DecodeInt24(packetBody + pos + 1);
4641 ts = AMF_DecodeInt24(packetBody + pos + 4);
4642 ts |= (packetBody[pos + 7] << 24);
4644 #ifdef _DEBUG
4645 RTMP_Log(RTMP_LOGDEBUG,
4646 "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
4647 packetBody[pos], dataSize, ts);
4648 #endif
4649 /* ok, is it a keyframe?:
4650 * well doesn't work for audio!
4652 if (packetBody[pos /*6928, test 0 */ ] ==
4653 r->m_read.initialFrameType
4654 /* && (packetBody[11]&0xf0) == 0x10 */ )
4656 if (ts == r->m_read.nResumeTS)
4658 RTMP_Log(RTMP_LOGDEBUG,
4659 "Found keyframe with resume-keyframe timestamp!");
4660 if (r->m_read.nInitialFrameSize != dataSize
4661 || memcmp(r->m_read.initialFrame,
4662 packetBody + pos + 11,
4663 r->m_read.
4664 nInitialFrameSize) != 0)
4666 RTMP_Log(RTMP_LOGERROR,
4667 "FLV Stream: Keyframe doesn't match!");
4668 ret = RTMP_READ_ERROR;
4669 break;
4671 r->m_read.flags |= RTMP_READ_GOTFLVK;
4673 /* skip this packet?
4674 * check whether skippable:
4676 if (pos + 11 + dataSize + 4 > nPacketLen)
4678 RTMP_Log(RTMP_LOGWARNING,
4679 "Non skipable packet since it doesn't end with chunk, stream corrupt!");
4680 ret = RTMP_READ_ERROR;
4681 break;
4683 packetBody += (pos + 11 + dataSize + 4);
4684 nPacketLen -= (pos + 11 + dataSize + 4);
4686 goto stopKeyframeSearch;
4689 else if (r->m_read.nResumeTS < ts)
4691 /* the timestamp ts will only increase with
4692 * further packets, wait for seek
4694 goto stopKeyframeSearch;
4697 pos += (11 + dataSize + 4);
4699 if (ts < r->m_read.nResumeTS)
4701 RTMP_Log(RTMP_LOGERROR,
4702 "First packet does not contain keyframe, all "
4703 "timestamps are smaller than the keyframe "
4704 "timestamp; probably the resume seek failed?");
4706 stopKeyframeSearch:
4708 if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
4710 RTMP_Log(RTMP_LOGERROR,
4711 "Couldn't find the seeked keyframe in this chunk!");
4712 ret = RTMP_READ_IGNORE;
4713 break;
4719 if (packet.m_nTimeStamp > 0
4720 && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
4722 /* another problem is that the server can actually change from
4723 * 09/08 video/audio packets to an FLV stream or vice versa and
4724 * our keyframe check will prevent us from going along with the
4725 * new stream if we resumed.
4727 * in this case set the 'found keyframe' variables to true.
4728 * We assume that if we found one keyframe somewhere and were
4729 * already beyond TS > 0 we have written data to the output
4730 * which means we can accept all forthcoming data including the
4731 * change between 08/09 <-> FLV packets
4733 r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
4736 /* skip till we find our keyframe
4737 * (seeking might put us somewhere before it)
4739 if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
4740 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4742 RTMP_Log(RTMP_LOGWARNING,
4743 "Stream does not start with requested frame, ignoring data... ");
4744 r->m_read.nIgnoredFrameCounter++;
4745 if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
4746 ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
4747 else
4748 ret = RTMP_READ_IGNORE;
4749 break;
4751 /* ok, do the same for FLV streams */
4752 if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
4753 packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4755 RTMP_Log(RTMP_LOGWARNING,
4756 "Stream does not start with requested FLV frame, ignoring data... ");
4757 r->m_read.nIgnoredFlvFrameCounter++;
4758 if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
4759 ret = RTMP_READ_ERROR;
4760 else
4761 ret = RTMP_READ_IGNORE;
4762 break;
4765 /* we have to ignore the 0ms frames since these are the first
4766 * keyframes; we've got these so don't mess around with multiple
4767 * copies sent by the server to us! (if the keyframe is found at a
4768 * later position there is only one copy and it will be ignored by
4769 * the preceding if clause)
4771 if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
4772 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4774 /* exclude type RTMP_PACKET_TYPE_FLASH_VIDEO since it can
4775 * contain several FLV packets
4777 if (packet.m_nTimeStamp == 0)
4779 ret = RTMP_READ_IGNORE;
4780 break;
4782 else
4784 /* stop ignoring packets */
4785 r->m_read.flags |= RTMP_READ_NO_IGNORE;
4790 /* calculate packet size and allocate slop buffer if necessary */
4791 size = nPacketLen +
4792 ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4793 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4794 || packet.m_packetType == RTMP_PACKET_TYPE_INFO) ? 11 : 0) +
4795 (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO ? 4 : 0);
4797 if (size + 4 > buflen)
4799 /* the extra 4 is for the case of an FLV stream without a last
4800 * prevTagSize (we need extra 4 bytes to append it) */
4801 r->m_read.buf = malloc(size + 4);
4802 if (r->m_read.buf == 0)
4804 RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
4805 ret = RTMP_READ_ERROR; /* fatal error */
4806 break;
4808 recopy = TRUE;
4809 ptr = r->m_read.buf;
4811 else
4813 ptr = buf;
4815 pend = ptr + size + 4;
4817 /* use to return timestamp of last processed packet */
4819 /* audio (0x08), video (0x09) or metadata (0x12) packets :
4820 * construct 11 byte header then add rtmp packet's data */
4821 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4822 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4823 || packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4825 nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
4826 prevTagSize = 11 + nPacketLen;
4828 *ptr = packet.m_packetType;
4829 ptr++;
4830 ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
4832 #if 0
4833 if(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) {
4835 /* H264 fix: */
4836 if((packetBody[0] & 0x0f) == 7) { /* CodecId = H264 */
4837 uint8_t packetType = *(packetBody+1);
4839 uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
4840 int32_t cts = (ts+0xff800000)^0xff800000;
4841 RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
4843 nTimeStamp -= cts;
4844 /* get rid of the composition time */
4845 CRTMP::EncodeInt24(packetBody+2, 0);
4847 RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
4849 #endif
4851 ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
4852 *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
4853 ptr++;
4855 /* stream id */
4856 ptr = AMF_EncodeInt24(ptr, pend, 0);
4859 memcpy(ptr, packetBody, nPacketLen);
4860 len = nPacketLen;
4862 /* correct tagSize and obtain timestamp if we have an FLV stream */
4863 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4865 unsigned int pos = 0;
4866 int delta;
4868 /* grab first timestamp and see if it needs fixing */
4869 nTimeStamp = AMF_DecodeInt24(packetBody + 4);
4870 nTimeStamp |= (packetBody[7] << 24);
4871 delta = packet.m_nTimeStamp - nTimeStamp + r->m_read.nResumeTS;
4873 while (pos + 11 < nPacketLen)
4875 /* size without header (11) and without prevTagSize (4) */
4876 uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
4877 nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
4878 nTimeStamp |= (packetBody[pos + 7] << 24);
4880 if (delta)
4882 nTimeStamp += delta;
4883 AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
4884 ptr[pos+7] = nTimeStamp>>24;
4887 /* set data type */
4888 r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
4889 (*(packetBody + pos) == 0x09));
4891 if (pos + 11 + dataSize + 4 > nPacketLen)
4893 if (pos + 11 + dataSize > nPacketLen)
4895 RTMP_Log(RTMP_LOGERROR,
4896 "Wrong data size (%u), stream corrupted, aborting!",
4897 dataSize);
4898 ret = RTMP_READ_ERROR;
4899 break;
4901 RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
4903 /* we have to append a last tagSize! */
4904 prevTagSize = dataSize + 11;
4905 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4906 prevTagSize);
4907 size += 4;
4908 len += 4;
4910 else
4912 prevTagSize =
4913 AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
4915 #ifdef _DEBUG
4916 RTMP_Log(RTMP_LOGDEBUG,
4917 "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
4918 (unsigned char)packetBody[pos], dataSize, prevTagSize,
4919 nTimeStamp);
4920 #endif
4922 if (prevTagSize != (dataSize + 11))
4924 #ifdef _DEBUG
4925 RTMP_Log(RTMP_LOGWARNING,
4926 "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
4927 dataSize + 11);
4928 #endif
4930 prevTagSize = dataSize + 11;
4931 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4932 prevTagSize);
4936 pos += prevTagSize + 4; /*(11+dataSize+4); */
4939 ptr += len;
4941 if (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4943 /* FLV tag packets contain their own prevTagSize */
4944 AMF_EncodeInt32(ptr, pend, prevTagSize);
4947 /* In non-live this nTimeStamp can contain an absolute TS.
4948 * Update ext timestamp with this absolute offset in non-live mode
4949 * otherwise report the relative one
4951 /* RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, pktTS: %dms, TS: %dms, bLiveStream: %d", packet.m_packetType, nPacketLen, packet.m_nTimeStamp, nTimeStamp, r->Link.lFlags & RTMP_LF_LIVE); */
4952 r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
4954 ret = size;
4955 break;
4958 if (rtnGetNextMediaPacket)
4959 RTMPPacket_Free(&packet);
4961 if (recopy)
4963 len = ret > buflen ? buflen : ret;
4964 memcpy(buf, r->m_read.buf, len);
4965 r->m_read.bufpos = r->m_read.buf + len;
4966 r->m_read.buflen = ret - len;
4968 return ret;
4971 static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
4972 0x00, /* 0x04 == audio, 0x01 == video */
4973 0x00, 0x00, 0x00, 0x09,
4974 0x00, 0x00, 0x00, 0x00
4977 #define HEADERBUF (128*1024)
4979 RTMP_Read(RTMP *r, char *buf, int size)
4981 int nRead = 0, total = 0;
4983 /* can't continue */
4984 fail:
4985 switch (r->m_read.status) {
4986 case RTMP_READ_EOF:
4987 case RTMP_READ_COMPLETE:
4988 return 0;
4989 case RTMP_READ_ERROR: /* corrupted stream, resume failed */
4990 SetSockError(EINVAL);
4991 return -1;
4992 default:
4993 break;
4996 /* first time thru */
4997 if (!(r->m_read.flags & RTMP_READ_HEADER))
4999 if (!(r->m_read.flags & RTMP_READ_RESUME))
5001 char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
5002 int cnt = 0;
5003 r->m_read.buf = mybuf;
5004 r->m_read.buflen = HEADERBUF;
5006 memcpy(mybuf, flvHeader, sizeof(flvHeader));
5007 r->m_read.buf += sizeof(flvHeader);
5008 r->m_read.buflen -= sizeof(flvHeader);
5009 cnt += sizeof(flvHeader);
5011 while (r->m_read.timestamp == 0)
5013 nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
5014 if (nRead < 0)
5016 free(mybuf);
5017 r->m_read.buf = NULL;
5018 r->m_read.buflen = 0;
5019 r->m_read.status = nRead;
5020 goto fail;
5022 /* buffer overflow, fix buffer and give up */
5023 if (r->m_read.buf < mybuf || r->m_read.buf > end) {
5024 mybuf = realloc(mybuf, cnt + nRead);
5025 memcpy(mybuf+cnt, r->m_read.buf, nRead);
5026 free(r->m_read.buf);
5027 r->m_read.buf = mybuf+cnt+nRead;
5028 break;
5030 cnt += nRead;
5031 r->m_read.buf += nRead;
5032 r->m_read.buflen -= nRead;
5033 if (r->m_read.dataType == 5)
5034 break;
5036 mybuf[4] = r->m_read.dataType;
5037 r->m_read.buflen = r->m_read.buf - mybuf;
5038 r->m_read.buf = mybuf;
5039 r->m_read.bufpos = mybuf;
5041 r->m_read.flags |= RTMP_READ_HEADER;
5044 if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
5046 /* drop whatever's here */
5047 free(r->m_read.buf);
5048 r->m_read.buf = NULL;
5049 r->m_read.bufpos = NULL;
5050 r->m_read.buflen = 0;
5053 /* If there's leftover data buffered, use it up */
5054 if (r->m_read.buf)
5056 nRead = r->m_read.buflen;
5057 if (nRead > size)
5058 nRead = size;
5059 memcpy(buf, r->m_read.bufpos, nRead);
5060 r->m_read.buflen -= nRead;
5061 if (!r->m_read.buflen)
5063 free(r->m_read.buf);
5064 r->m_read.buf = NULL;
5065 r->m_read.bufpos = NULL;
5067 else
5069 r->m_read.bufpos += nRead;
5071 buf += nRead;
5072 total += nRead;
5073 size -= nRead;
5076 while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
5078 if (!nRead) continue;
5079 buf += nRead;
5080 total += nRead;
5081 size -= nRead;
5082 break;
5084 if (nRead < 0)
5085 r->m_read.status = nRead;
5087 if (size < 0)
5088 total += size;
5089 return total;
5092 static const AVal av_setDataFrame = AVC("@setDataFrame");
5095 RTMP_Write(RTMP *r, const char *buf, int size)
5097 RTMPPacket *pkt = &r->m_write;
5098 char *pend, *enc;
5099 int s2 = size, ret, num;
5101 pkt->m_nChannel = 0x04; /* source channel */
5102 pkt->m_nInfoField2 = r->m_stream_id;
5104 while (s2)
5106 if (!pkt->m_nBytesRead)
5108 if (size < 11) {
5109 /* FLV pkt too small */
5110 return 0;
5113 if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
5115 buf += 13;
5116 s2 -= 13;
5119 pkt->m_packetType = *buf++;
5120 pkt->m_nBodySize = AMF_DecodeInt24(buf);
5121 buf += 3;
5122 pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
5123 buf += 3;
5124 pkt->m_nTimeStamp |= *buf++ << 24;
5125 buf += 3;
5126 s2 -= 11;
5128 if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
5129 || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
5130 !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5132 pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
5133 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5134 pkt->m_nBodySize += 16;
5136 else
5138 pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
5141 if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
5143 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
5144 return FALSE;
5146 enc = pkt->m_body;
5147 pend = enc + pkt->m_nBodySize;
5148 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5150 enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
5151 pkt->m_nBytesRead = enc - pkt->m_body;
5154 else
5156 enc = pkt->m_body + pkt->m_nBytesRead;
5158 num = pkt->m_nBodySize - pkt->m_nBytesRead;
5159 if (num > s2)
5160 num = s2;
5161 memcpy(enc, buf, num);
5162 pkt->m_nBytesRead += num;
5163 s2 -= num;
5164 buf += num;
5165 if (pkt->m_nBytesRead == pkt->m_nBodySize)
5167 ret = RTMP_SendPacket(r, pkt, FALSE);
5168 RTMPPacket_Free(pkt);
5169 pkt->m_nBytesRead = 0;
5170 if (!ret)
5171 return -1;
5172 buf += 4;
5173 s2 -= 4;
5174 if (s2 < 0)
5175 break;
5178 return size+s2;