Refill if HTTP_read indicated it needs more data
[rtmpdump.git] / librtmp / rtmp.c
blob6183d200c36da64f236ae15b70fd34a355221892
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>
31 #include "rtmp_sys.h"
32 #include "log.h"
34 #ifdef CRYPTO
35 #ifdef USE_POLARSSL
36 #include <polarssl/version.h>
37 #include <polarssl/havege.h>
39 static const char *my_dhm_P =
40 "E4004C1F94182000103D883A448B3F80" \
41 "2CE4B44A83301270002C20D0321CFD00" \
42 "11CCEF784C26A400F43DFB901BCA7538" \
43 "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
44 "F6AC8E1DA6BCC3B4E1F96B0564965300" \
45 "FFA1D0B601EB2800F489AA512C4B248C" \
46 "01F76949A60BB7F00A40B1EAB64BDD48" \
47 "E8A700D60B7F1200FA8E77B0A979DABF";
49 static const char *my_dhm_G = "4";
51 #elif defined(USE_GNUTLS)
52 #include <gnutls/gnutls.h>
53 #else /* USE_OPENSSL */
54 #include <openssl/ssl.h>
55 #include <openssl/rc4.h>
56 #endif
57 TLS_CTX RTMP_TLS_ctx;
58 #endif
60 #define RTMP_SIG_SIZE 1536
61 #define RTMP_LARGE_HEADER_SIZE 12
63 static const int packetSize[] = { 12, 8, 4, 1 };
65 int RTMP_ctrlC;
67 const char RTMPProtocolStrings[][7] = {
68 "RTMP",
69 "RTMPT",
70 "RTMPE",
71 "RTMPTE",
72 "RTMPS",
73 "RTMPTS",
74 "",
75 "",
76 "RTMFP"
79 const char RTMPProtocolStringsLower[][7] = {
80 "rtmp",
81 "rtmpt",
82 "rtmpe",
83 "rtmpte",
84 "rtmps",
85 "rtmpts",
86 "",
87 "",
88 "rtmfp"
91 static const char *RTMPT_cmds[] = {
92 "open",
93 "send",
94 "idle",
95 "close"
98 typedef enum {
99 RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
100 } RTMPTCmd;
102 static int DumpMetaData(AMFObject *obj);
103 static int HandShake(RTMP *r, int FP9HandShake);
104 static int SocksNegotiate(RTMP *r);
106 static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
107 static int SendCheckBW(RTMP *r);
108 static int SendCheckBWResult(RTMP *r, double txn);
109 static int SendDeleteStream(RTMP *r, double dStreamId);
110 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
111 static int SendPlay(RTMP *r);
112 static int SendBytesReceived(RTMP *r);
113 static int SendUsherToken(RTMP *r, AVal *usherToken);
115 #if 0 /* unused */
116 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
117 #endif
119 static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
120 static int HandleMetadata(RTMP *r, char *body, unsigned int len);
121 static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
122 static void HandleAudio(RTMP *r, const RTMPPacket *packet);
123 static void HandleVideo(RTMP *r, const RTMPPacket *packet);
124 static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
125 static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
126 static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
128 static int ReadN(RTMP *r, char *buffer, int n);
129 static int WriteN(RTMP *r, const char *buffer, int n);
131 static void DecodeTEA(AVal *key, AVal *text);
133 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
134 static int HTTP_read(RTMP *r, int fill);
136 #ifndef _WIN32
137 static int clk_tck;
138 #endif
140 #ifdef CRYPTO
141 #include "handshake.h"
142 #endif
144 uint32_t
145 RTMP_GetTime()
147 #ifdef _DEBUG
148 return 0;
149 #elif defined(_WIN32)
150 return timeGetTime();
151 #else
152 struct tms t;
153 if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
154 return times(&t) * 1000 / clk_tck;
155 #endif
158 void
159 RTMP_UserInterrupt()
161 RTMP_ctrlC = TRUE;
164 void
165 RTMPPacket_Reset(RTMPPacket *p)
167 p->m_headerType = 0;
168 p->m_packetType = 0;
169 p->m_nChannel = 0;
170 p->m_nTimeStamp = 0;
171 p->m_nInfoField2 = 0;
172 p->m_hasAbsTimestamp = FALSE;
173 p->m_nBodySize = 0;
174 p->m_nBytesRead = 0;
178 RTMPPacket_Alloc(RTMPPacket *p, int nSize)
180 char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
181 if (!ptr)
182 return FALSE;
183 p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
184 p->m_nBytesRead = 0;
185 return TRUE;
188 void
189 RTMPPacket_Free(RTMPPacket *p)
191 if (p->m_body)
193 free(p->m_body - RTMP_MAX_HEADER_SIZE);
194 p->m_body = NULL;
198 void
199 RTMPPacket_Dump(RTMPPacket *p)
201 RTMP_Log(RTMP_LOGDEBUG,
202 "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %u. body: 0x%02x",
203 p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
204 p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
208 RTMP_LibVersion()
210 return RTMP_LIB_VERSION;
213 void
214 RTMP_TLS_Init()
216 #ifdef CRYPTO
217 #ifdef USE_POLARSSL
218 /* Do this regardless of NO_SSL, we use havege for rtmpe too */
219 RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
220 havege_init(&RTMP_TLS_ctx->hs);
221 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
222 /* Technically we need to initialize libgcrypt ourselves if
223 * we're not going to call gnutls_global_init(). Ignoring this
224 * for now.
226 gnutls_global_init();
227 RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
228 gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
229 gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
230 gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
231 "ca.pem", GNUTLS_X509_FMT_PEM);
232 #elif !defined(NO_SSL) /* USE_OPENSSL */
233 /* libcrypto doesn't need anything special */
234 SSL_load_error_strings();
235 SSL_library_init();
236 OpenSSL_add_all_digests();
237 RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
238 SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
239 SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
240 #endif
241 #endif
244 void *
245 RTMP_TLS_AllocServerContext(const char* cert, const char* key)
247 void *ctx = NULL;
248 #ifdef CRYPTO
249 if (!RTMP_TLS_ctx)
250 RTMP_TLS_Init();
251 #ifdef USE_POLARSSL
252 tls_server_ctx *tc = ctx = calloc(1, sizeof(struct tls_server_ctx));
253 tc->dhm_P = my_dhm_P;
254 tc->dhm_G = my_dhm_G;
255 tc->hs = &RTMP_TLS_ctx->hs;
256 if (x509parse_crtfile(&tc->cert, cert)) {
257 free(tc);
258 return NULL;
260 if (x509parse_keyfile(&tc->key, key, NULL)) {
261 x509_free(&tc->cert);
262 free(tc);
263 return NULL;
265 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
266 gnutls_certificate_allocate_credentials((gnutls_certificate_credentials*) &ctx);
267 if (gnutls_certificate_set_x509_key_file(ctx, cert, key, GNUTLS_X509_FMT_PEM) != 0) {
268 gnutls_certificate_free_credentials(ctx);
269 return NULL;
271 #elif !defined(NO_SSL) /* USE_OPENSSL */
272 ctx = SSL_CTX_new(SSLv23_server_method());
273 FILE *f = fopen(key, "r");
274 if (!f) {
275 SSL_CTX_free(ctx);
276 return NULL;
278 EVP_PKEY *k = PEM_read_PrivateKey(f, NULL, NULL, NULL);
279 fclose(f);
280 if (!k) {
281 SSL_CTX_free(ctx);
282 return NULL;
284 SSL_CTX_use_PrivateKey(ctx, k);
285 EVP_PKEY_free(k);
286 f = fopen(cert, "r");
287 if (!f) {
288 SSL_CTX_free(ctx);
289 return NULL;
291 X509 *c = PEM_read_X509(f, NULL, NULL, NULL);
292 fclose(f);
293 if (!c) {
294 SSL_CTX_free(ctx);
295 return NULL;
297 SSL_CTX_use_certificate(ctx, c);
298 X509_free(c);
299 #endif
300 #endif
301 return ctx;
304 void
305 RTMP_TLS_FreeServerContext(void *ctx)
307 #ifdef CRYPTO
308 #ifdef USE_POLARSSL
309 x509_free(&((tls_server_ctx*)ctx)->cert);
310 rsa_free(&((tls_server_ctx*)ctx)->key);
311 free(ctx);
312 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
313 gnutls_certificate_free_credentials(ctx);
314 #elif !defined(NO_SSL) /* USE_OPENSSL */
315 SSL_CTX_free(ctx);
316 #endif
317 #endif
320 RTMP *
321 RTMP_Alloc()
323 return calloc(1, sizeof(RTMP));
326 void
327 RTMP_Free(RTMP *r)
329 free(r);
332 void
333 RTMP_Init(RTMP *r)
335 #ifdef CRYPTO
336 if (!RTMP_TLS_ctx)
337 RTMP_TLS_Init();
338 #endif
340 memset(r, 0, sizeof(RTMP));
341 r->m_sb.sb_socket = -1;
342 r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
343 r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
344 r->m_nBufferMS = 30000;
345 r->m_nClientBW = 2500000;
346 r->m_nClientBW2 = 2;
347 r->m_nServerBW = 2500000;
348 r->m_fAudioCodecs = 3191.0;
349 r->m_fVideoCodecs = 252.0;
350 r->Link.timeout = 30;
351 r->Link.swfAge = 30;
354 void
355 RTMP_EnableWrite(RTMP *r)
357 r->Link.protocol |= RTMP_FEATURE_WRITE;
360 double
361 RTMP_GetDuration(RTMP *r)
363 return r->m_fDuration;
367 RTMP_IsConnected(RTMP *r)
369 return r->m_sb.sb_socket != -1;
373 RTMP_Socket(RTMP *r)
375 return r->m_sb.sb_socket;
379 RTMP_IsTimedout(RTMP *r)
381 return r->m_sb.sb_timedout;
384 void
385 RTMP_SetBufferMS(RTMP *r, int size)
387 r->m_nBufferMS = size;
390 void
391 RTMP_UpdateBufferMS(RTMP *r)
393 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
396 #undef OSS
397 #ifdef _WIN32
398 #define OSS "WIN"
399 #elif defined(__sun__)
400 #define OSS "SOL"
401 #elif defined(__APPLE__)
402 #define OSS "MAC"
403 #elif defined(__linux__)
404 #define OSS "LNX"
405 #else
406 #define OSS "GNU"
407 #endif
408 #define DEF_VERSTR OSS " 10,0,32,18"
409 static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
410 const AVal RTMP_DefaultFlashVer =
411 { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
413 static void
414 SocksSetup(RTMP *r, AVal *sockshost)
416 if (sockshost->av_len)
418 const char *socksport = strchr(sockshost->av_val, ':');
419 char *hostname = strdup(sockshost->av_val);
421 if (socksport)
422 hostname[socksport - sockshost->av_val] = '\0';
423 r->Link.sockshost.av_val = hostname;
424 r->Link.sockshost.av_len = strlen(hostname);
426 r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
427 RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
428 r->Link.socksport);
430 else
432 r->Link.sockshost.av_val = NULL;
433 r->Link.sockshost.av_len = 0;
434 r->Link.socksport = 0;
438 void
439 RTMP_SetupStream(RTMP *r,
440 int protocol,
441 AVal *host,
442 unsigned int port,
443 AVal *sockshost,
444 AVal *playpath,
445 AVal *tcUrl,
446 AVal *swfUrl,
447 AVal *pageUrl,
448 AVal *app,
449 AVal *auth,
450 AVal *swfSHA256Hash,
451 uint32_t swfSize,
452 AVal *flashVer,
453 AVal *subscribepath,
454 AVal *usherToken,
455 int dStart,
456 int dStop, int bLiveStream, long int timeout)
458 RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
459 RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
460 RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
461 RTMP_Log(RTMP_LOGDEBUG, "Playpath : %s", playpath->av_val);
463 if (tcUrl && tcUrl->av_val)
464 RTMP_Log(RTMP_LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
465 if (swfUrl && swfUrl->av_val)
466 RTMP_Log(RTMP_LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
467 if (pageUrl && pageUrl->av_val)
468 RTMP_Log(RTMP_LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
469 if (app && app->av_val)
470 RTMP_Log(RTMP_LOGDEBUG, "app : %.*s", app->av_len, app->av_val);
471 if (auth && auth->av_val)
472 RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
473 if (subscribepath && subscribepath->av_val)
474 RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
475 if (usherToken && usherToken->av_val)
476 RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
477 if (flashVer && flashVer->av_val)
478 RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
479 if (dStart > 0)
480 RTMP_Log(RTMP_LOGDEBUG, "StartTime : %d msec", dStart);
481 if (dStop > 0)
482 RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
484 RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
485 RTMP_Log(RTMP_LOGDEBUG, "timeout : %ld sec", timeout);
487 #ifdef CRYPTO
488 if (swfSHA256Hash != NULL && swfSize > 0)
490 memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
491 r->Link.SWFSize = swfSize;
492 RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
493 RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
494 RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %u", r->Link.SWFSize);
496 else
498 r->Link.SWFSize = 0;
500 #endif
502 SocksSetup(r, sockshost);
504 if (tcUrl && tcUrl->av_len)
505 r->Link.tcUrl = *tcUrl;
506 if (swfUrl && swfUrl->av_len)
507 r->Link.swfUrl = *swfUrl;
508 if (pageUrl && pageUrl->av_len)
509 r->Link.pageUrl = *pageUrl;
510 if (app && app->av_len)
511 r->Link.app = *app;
512 if (auth && auth->av_len)
514 r->Link.auth = *auth;
515 r->Link.lFlags |= RTMP_LF_AUTH;
517 if (flashVer && flashVer->av_len)
518 r->Link.flashVer = *flashVer;
519 else
520 r->Link.flashVer = RTMP_DefaultFlashVer;
521 if (subscribepath && subscribepath->av_len)
522 r->Link.subscribepath = *subscribepath;
523 if (usherToken && usherToken->av_len)
524 r->Link.usherToken = *usherToken;
525 r->Link.seekTime = dStart;
526 r->Link.stopTime = dStop;
527 if (bLiveStream)
528 r->Link.lFlags |= RTMP_LF_LIVE;
529 r->Link.timeout = timeout;
531 r->Link.protocol = protocol;
532 r->Link.hostname = *host;
533 r->Link.port = port;
534 r->Link.playpath = *playpath;
536 if (r->Link.port == 0)
538 if (protocol & RTMP_FEATURE_SSL)
539 r->Link.port = 443;
540 else if (protocol & RTMP_FEATURE_HTTP)
541 r->Link.port = 80;
542 else
543 r->Link.port = 1935;
547 enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
548 static const char *optinfo[] = {
549 "string", "integer", "boolean", "AMF" };
551 #define OFF(x) offsetof(struct RTMP,x)
553 static struct urlopt {
554 AVal name;
555 off_t off;
556 int otype;
557 int omisc;
558 char *use;
559 } options[] = {
560 { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
561 "Use the specified SOCKS proxy" },
562 { AVC("app"), OFF(Link.app), OPT_STR, 0,
563 "Name of target app on server" },
564 { AVC("tcUrl"), OFF(Link.tcUrl), OPT_STR, 0,
565 "URL to played stream" },
566 { AVC("pageUrl"), OFF(Link.pageUrl), OPT_STR, 0,
567 "URL of played media's web page" },
568 { AVC("swfUrl"), OFF(Link.swfUrl), OPT_STR, 0,
569 "URL to player SWF file" },
570 { AVC("flashver"), OFF(Link.flashVer), OPT_STR, 0,
571 "Flash version string (default " DEF_VERSTR ")" },
572 { AVC("conn"), OFF(Link.extras), OPT_CONN, 0,
573 "Append arbitrary AMF data to Connect message" },
574 { AVC("playpath"), OFF(Link.playpath), OPT_STR, 0,
575 "Path to target media on server" },
576 { AVC("playlist"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_PLST,
577 "Set playlist before play command" },
578 { AVC("live"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_LIVE,
579 "Stream is live, no seeking possible" },
580 { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
581 "Stream to subscribe to" },
582 { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
583 "Justin.tv authentication token" },
584 { AVC("token"), OFF(Link.token), OPT_STR, 0,
585 "Key for SecureToken response" },
586 { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
587 "Perform SWF Verification" },
588 { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
589 "Number of days to use cached SWF hash" },
590 { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
591 "Stream start position in milliseconds" },
592 { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
593 "Stream stop position in milliseconds" },
594 { AVC("buffer"), OFF(m_nBufferMS), OPT_INT, 0,
595 "Buffer time in milliseconds" },
596 { AVC("timeout"), OFF(Link.timeout), OPT_INT, 0,
597 "Session timeout in seconds" },
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))
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 continue;
1211 r->m_pausing = 0;
1215 if (bHasMediaPacket)
1216 r->m_bPlaying = TRUE;
1217 else if (r->m_sb.sb_timedout && !r->m_pausing)
1218 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
1220 return bHasMediaPacket;
1224 RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
1226 int bHasMediaPacket = 0;
1227 switch (packet->m_packetType)
1229 case RTMP_PACKET_TYPE_CHUNK_SIZE:
1230 /* chunk size */
1231 HandleChangeChunkSize(r, packet);
1232 break;
1234 case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
1235 /* bytes read report */
1236 RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
1237 break;
1239 case RTMP_PACKET_TYPE_CONTROL:
1240 /* ctrl */
1241 HandleCtrl(r, packet);
1242 break;
1244 case RTMP_PACKET_TYPE_SERVER_BW:
1245 /* server bw */
1246 HandleServerBW(r, packet);
1247 break;
1249 case RTMP_PACKET_TYPE_CLIENT_BW:
1250 /* client bw */
1251 HandleClientBW(r, packet);
1252 break;
1254 case RTMP_PACKET_TYPE_AUDIO:
1255 /* audio data */
1256 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1257 HandleAudio(r, packet);
1258 bHasMediaPacket = 1;
1259 if (!r->m_mediaChannel)
1260 r->m_mediaChannel = packet->m_nChannel;
1261 if (!r->m_pausing)
1262 r->m_mediaStamp = packet->m_nTimeStamp;
1263 break;
1265 case RTMP_PACKET_TYPE_VIDEO:
1266 /* video data */
1267 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1268 HandleVideo(r, packet);
1269 bHasMediaPacket = 1;
1270 if (!r->m_mediaChannel)
1271 r->m_mediaChannel = packet->m_nChannel;
1272 if (!r->m_pausing)
1273 r->m_mediaStamp = packet->m_nTimeStamp;
1274 break;
1276 case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
1277 /* flex stream send */
1278 RTMP_Log(RTMP_LOGDEBUG,
1279 "%s, flex stream send, size %u bytes, not supported, ignoring",
1280 __FUNCTION__, packet->m_nBodySize);
1281 break;
1283 case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
1284 /* flex shared object */
1285 RTMP_Log(RTMP_LOGDEBUG,
1286 "%s, flex shared object, size %u bytes, not supported, ignoring",
1287 __FUNCTION__, packet->m_nBodySize);
1288 break;
1290 case RTMP_PACKET_TYPE_FLEX_MESSAGE:
1291 /* flex message */
1293 RTMP_Log(RTMP_LOGDEBUG,
1294 "%s, flex message, size %u bytes, not fully supported",
1295 __FUNCTION__, packet->m_nBodySize);
1296 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1298 /* some DEBUG code */
1299 #if 0
1300 RTMP_LIB_AMFObject obj;
1301 int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
1302 if(nRes < 0) {
1303 RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
1304 /*return; */
1307 obj.Dump();
1308 #endif
1310 if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
1311 bHasMediaPacket = 2;
1312 break;
1314 case RTMP_PACKET_TYPE_INFO:
1315 /* metadata (notify) */
1316 RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
1317 packet->m_nBodySize);
1318 if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
1319 bHasMediaPacket = 1;
1320 break;
1322 case RTMP_PACKET_TYPE_SHARED_OBJECT:
1323 RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
1324 __FUNCTION__);
1325 break;
1327 case RTMP_PACKET_TYPE_INVOKE:
1328 /* invoke */
1329 RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
1330 packet->m_nBodySize);
1331 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1333 if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
1334 bHasMediaPacket = 2;
1335 break;
1337 case RTMP_PACKET_TYPE_FLASH_VIDEO:
1339 /* go through FLV packets and handle metadata packets */
1340 unsigned int pos = 0;
1341 uint32_t nTimeStamp = packet->m_nTimeStamp;
1343 while (pos + 11 < packet->m_nBodySize)
1345 uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
1347 if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
1349 RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
1350 break;
1352 if (packet->m_body[pos] == 0x12)
1354 HandleMetadata(r, packet->m_body + pos + 11, dataSize);
1356 else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
1358 nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
1359 nTimeStamp |= (packet->m_body[pos + 7] << 24);
1361 pos += (11 + dataSize + 4);
1363 if (!r->m_pausing)
1364 r->m_mediaStamp = nTimeStamp;
1366 /* FLV tag(s) */
1367 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1368 bHasMediaPacket = 1;
1369 break;
1371 default:
1372 RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
1373 packet->m_packetType);
1374 #ifdef _DEBUG
1375 RTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize);
1376 #endif
1379 return bHasMediaPacket;
1382 #ifdef _DEBUG
1383 extern FILE *netstackdump;
1384 extern FILE *netstackdump_read;
1385 #endif
1387 static int
1388 ReadN(RTMP *r, char *buffer, int n)
1390 int nOriginalSize = n;
1391 int avail;
1392 char *ptr;
1394 r->m_sb.sb_timedout = FALSE;
1396 #ifdef _DEBUG
1397 memset(buffer, 0, n);
1398 #endif
1400 ptr = buffer;
1401 while (n > 0)
1403 int nBytes = 0, nRead;
1404 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1406 int refill = 0;
1407 while (!r->m_resplen)
1409 int ret;
1410 if (r->m_sb.sb_size < 13 || refill)
1412 if (!r->m_unackd)
1413 HTTP_Post(r, RTMPT_IDLE, "", 1);
1414 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1416 if (!r->m_sb.sb_timedout)
1417 RTMP_Close(r);
1418 return 0;
1421 if ((ret = HTTP_read(r, 0)) == -1)
1423 RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__);
1424 RTMP_Close(r);
1425 return 0;
1427 else if (ret == -2)
1429 refill = 1;
1431 else
1433 refill = 0;
1436 if (r->m_resplen && !r->m_sb.sb_size)
1437 RTMPSockBuf_Fill(&r->m_sb);
1438 avail = r->m_sb.sb_size;
1439 if (avail > r->m_resplen)
1440 avail = r->m_resplen;
1442 else
1444 avail = r->m_sb.sb_size;
1445 if (avail == 0)
1447 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1449 if (!r->m_sb.sb_timedout)
1450 RTMP_Close(r);
1451 return 0;
1453 avail = r->m_sb.sb_size;
1456 nRead = ((n < avail) ? n : avail);
1457 if (nRead > 0)
1459 memcpy(ptr, r->m_sb.sb_start, nRead);
1460 r->m_sb.sb_start += nRead;
1461 r->m_sb.sb_size -= nRead;
1462 nBytes = nRead;
1463 r->m_nBytesIn += nRead;
1464 if (r->m_bSendCounter
1465 && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
1466 if (!SendBytesReceived(r))
1467 return FALSE;
1469 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
1470 #ifdef _DEBUG
1471 fwrite(ptr, 1, nBytes, netstackdump_read);
1472 #endif
1474 if (nBytes == 0)
1476 RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
1477 /*goto again; */
1478 RTMP_Close(r);
1479 break;
1482 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1483 r->m_resplen -= nBytes;
1485 #ifdef CRYPTO
1486 if (r->Link.rc4keyIn)
1488 RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
1490 #endif
1492 n -= nBytes;
1493 ptr += nBytes;
1496 return nOriginalSize - n;
1499 static int
1500 WriteN(RTMP *r, const char *buffer, int n)
1502 const char *ptr = buffer;
1503 #ifdef CRYPTO
1504 char *encrypted = 0;
1505 char buf[RTMP_BUFFER_CACHE_SIZE];
1507 if (r->Link.rc4keyOut)
1509 if (n > sizeof(buf))
1510 encrypted = (char *)malloc(n);
1511 else
1512 encrypted = (char *)buf;
1513 ptr = encrypted;
1514 RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
1516 #endif
1518 while (n > 0)
1520 int nBytes;
1522 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1523 nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
1524 else
1525 nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
1526 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
1528 if (nBytes < 0)
1530 int sockerr = GetSockError();
1531 RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
1532 sockerr, n);
1534 if (sockerr == EINTR && !RTMP_ctrlC)
1535 continue;
1537 RTMP_Close(r);
1538 n = 1;
1539 break;
1542 if (nBytes == 0)
1543 break;
1545 n -= nBytes;
1546 ptr += nBytes;
1549 #ifdef CRYPTO
1550 if (encrypted && encrypted != buf)
1551 free(encrypted);
1552 #endif
1554 return n == 0;
1557 #define SAVC(x) static const AVal av_##x = AVC(#x)
1559 SAVC(app);
1560 SAVC(connect);
1561 SAVC(flashVer);
1562 SAVC(swfUrl);
1563 SAVC(pageUrl);
1564 SAVC(tcUrl);
1565 SAVC(fpad);
1566 SAVC(capabilities);
1567 SAVC(audioCodecs);
1568 SAVC(videoCodecs);
1569 SAVC(videoFunction);
1570 SAVC(objectEncoding);
1571 SAVC(secureToken);
1572 SAVC(secureTokenResponse);
1573 SAVC(type);
1574 SAVC(nonprivate);
1576 static int
1577 SendConnectPacket(RTMP *r, RTMPPacket *cp)
1579 RTMPPacket packet;
1580 char pbuf[4096], *pend = pbuf + sizeof(pbuf);
1581 char *enc;
1583 if (cp)
1584 return RTMP_SendPacket(r, cp, TRUE);
1586 packet.m_nChannel = 0x03; /* control channel (invoke) */
1587 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1588 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1589 packet.m_nTimeStamp = 0;
1590 packet.m_nInfoField2 = 0;
1591 packet.m_hasAbsTimestamp = 0;
1592 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1594 enc = packet.m_body;
1595 enc = AMF_EncodeString(enc, pend, &av_connect);
1596 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1597 *enc++ = AMF_OBJECT;
1599 enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
1600 if (!enc)
1601 return FALSE;
1602 if (r->Link.protocol & RTMP_FEATURE_WRITE)
1604 enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
1605 if (!enc)
1606 return FALSE;
1608 if (r->Link.flashVer.av_len)
1610 enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
1611 if (!enc)
1612 return FALSE;
1614 if (r->Link.swfUrl.av_len)
1616 enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
1617 if (!enc)
1618 return FALSE;
1620 if (r->Link.tcUrl.av_len)
1622 enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
1623 if (!enc)
1624 return FALSE;
1626 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
1628 enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
1629 if (!enc)
1630 return FALSE;
1631 enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
1632 if (!enc)
1633 return FALSE;
1634 enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
1635 if (!enc)
1636 return FALSE;
1637 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
1638 if (!enc)
1639 return FALSE;
1640 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
1641 if (!enc)
1642 return FALSE;
1643 if (r->Link.pageUrl.av_len)
1645 enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
1646 if (!enc)
1647 return FALSE;
1650 if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
1651 { /* AMF0, AMF3 not fully supported yet */
1652 enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
1653 if (!enc)
1654 return FALSE;
1656 if (enc + 3 >= pend)
1657 return FALSE;
1658 *enc++ = 0;
1659 *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
1660 *enc++ = AMF_OBJECT_END;
1662 /* add auth string */
1663 if (r->Link.auth.av_len)
1665 enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
1666 if (!enc)
1667 return FALSE;
1668 enc = AMF_EncodeString(enc, pend, &r->Link.auth);
1669 if (!enc)
1670 return FALSE;
1672 if (r->Link.extras.o_num)
1674 int i;
1675 for (i = 0; i < r->Link.extras.o_num; i++)
1677 enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
1678 if (!enc)
1679 return FALSE;
1682 packet.m_nBodySize = enc - packet.m_body;
1684 return RTMP_SendPacket(r, &packet, TRUE);
1687 #if 0 /* unused */
1688 SAVC(bgHasStream);
1690 static int
1691 SendBGHasStream(RTMP *r, double dId, AVal *playpath)
1693 RTMPPacket packet;
1694 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1695 char *enc;
1697 packet.m_nChannel = 0x03; /* control channel (invoke) */
1698 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1699 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1700 packet.m_nTimeStamp = 0;
1701 packet.m_nInfoField2 = 0;
1702 packet.m_hasAbsTimestamp = 0;
1703 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1705 enc = packet.m_body;
1706 enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
1707 enc = AMF_EncodeNumber(enc, pend, dId);
1708 *enc++ = AMF_NULL;
1710 enc = AMF_EncodeString(enc, pend, playpath);
1711 if (enc == NULL)
1712 return FALSE;
1714 packet.m_nBodySize = enc - packet.m_body;
1716 return RTMP_SendPacket(r, &packet, TRUE);
1718 #endif
1720 SAVC(createStream);
1723 RTMP_SendCreateStream(RTMP *r)
1725 RTMPPacket packet;
1726 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1727 char *enc;
1729 packet.m_nChannel = 0x03; /* control channel (invoke) */
1730 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1731 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1732 packet.m_nTimeStamp = 0;
1733 packet.m_nInfoField2 = 0;
1734 packet.m_hasAbsTimestamp = 0;
1735 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1737 enc = packet.m_body;
1738 enc = AMF_EncodeString(enc, pend, &av_createStream);
1739 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1740 *enc++ = AMF_NULL; /* NULL */
1742 packet.m_nBodySize = enc - packet.m_body;
1744 return RTMP_SendPacket(r, &packet, TRUE);
1747 SAVC(FCSubscribe);
1749 static int
1750 SendFCSubscribe(RTMP *r, AVal *subscribepath)
1752 RTMPPacket packet;
1753 char pbuf[512], *pend = pbuf + sizeof(pbuf);
1754 char *enc;
1755 packet.m_nChannel = 0x03; /* control channel (invoke) */
1756 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1757 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1758 packet.m_nTimeStamp = 0;
1759 packet.m_nInfoField2 = 0;
1760 packet.m_hasAbsTimestamp = 0;
1761 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1763 RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
1764 enc = packet.m_body;
1765 enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
1766 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1767 *enc++ = AMF_NULL;
1768 enc = AMF_EncodeString(enc, pend, subscribepath);
1770 if (!enc)
1771 return FALSE;
1773 packet.m_nBodySize = enc - packet.m_body;
1775 return RTMP_SendPacket(r, &packet, TRUE);
1778 /* Justin.tv specific authentication */
1779 static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
1781 static int
1782 SendUsherToken(RTMP *r, AVal *usherToken)
1784 RTMPPacket packet;
1785 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1786 char *enc;
1787 packet.m_nChannel = 0x03; /* control channel (invoke) */
1788 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1789 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1790 packet.m_nTimeStamp = 0;
1791 packet.m_nInfoField2 = 0;
1792 packet.m_hasAbsTimestamp = 0;
1793 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1795 RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
1796 enc = packet.m_body;
1797 enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
1798 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1799 *enc++ = AMF_NULL;
1800 enc = AMF_EncodeString(enc, pend, usherToken);
1802 if (!enc)
1803 return FALSE;
1805 packet.m_nBodySize = enc - packet.m_body;
1807 return RTMP_SendPacket(r, &packet, FALSE);
1809 /******************************************/
1811 SAVC(releaseStream);
1813 static int
1814 SendReleaseStream(RTMP *r)
1816 RTMPPacket packet;
1817 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1818 char *enc;
1820 packet.m_nChannel = 0x03; /* control channel (invoke) */
1821 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1822 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1823 packet.m_nTimeStamp = 0;
1824 packet.m_nInfoField2 = 0;
1825 packet.m_hasAbsTimestamp = 0;
1826 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1828 enc = packet.m_body;
1829 enc = AMF_EncodeString(enc, pend, &av_releaseStream);
1830 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1831 *enc++ = AMF_NULL;
1832 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1833 if (!enc)
1834 return FALSE;
1836 packet.m_nBodySize = enc - packet.m_body;
1838 return RTMP_SendPacket(r, &packet, FALSE);
1841 SAVC(FCPublish);
1843 static int
1844 SendFCPublish(RTMP *r)
1846 RTMPPacket packet;
1847 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1848 char *enc;
1850 packet.m_nChannel = 0x03; /* control channel (invoke) */
1851 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1852 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1853 packet.m_nTimeStamp = 0;
1854 packet.m_nInfoField2 = 0;
1855 packet.m_hasAbsTimestamp = 0;
1856 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1858 enc = packet.m_body;
1859 enc = AMF_EncodeString(enc, pend, &av_FCPublish);
1860 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1861 *enc++ = AMF_NULL;
1862 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1863 if (!enc)
1864 return FALSE;
1866 packet.m_nBodySize = enc - packet.m_body;
1868 return RTMP_SendPacket(r, &packet, FALSE);
1871 SAVC(FCUnpublish);
1873 static int
1874 SendFCUnpublish(RTMP *r)
1876 RTMPPacket packet;
1877 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1878 char *enc;
1880 packet.m_nChannel = 0x03; /* control channel (invoke) */
1881 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1882 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1883 packet.m_nTimeStamp = 0;
1884 packet.m_nInfoField2 = 0;
1885 packet.m_hasAbsTimestamp = 0;
1886 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1888 enc = packet.m_body;
1889 enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
1890 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1891 *enc++ = AMF_NULL;
1892 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1893 if (!enc)
1894 return FALSE;
1896 packet.m_nBodySize = enc - packet.m_body;
1898 return RTMP_SendPacket(r, &packet, FALSE);
1901 SAVC(publish);
1902 SAVC(live);
1903 SAVC(record);
1905 static int
1906 SendPublish(RTMP *r)
1908 RTMPPacket packet;
1909 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1910 char *enc;
1912 packet.m_nChannel = 0x04; /* source channel (invoke) */
1913 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1914 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1915 packet.m_nTimeStamp = 0;
1916 packet.m_nInfoField2 = r->m_stream_id;
1917 packet.m_hasAbsTimestamp = 0;
1918 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1920 enc = packet.m_body;
1921 enc = AMF_EncodeString(enc, pend, &av_publish);
1922 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1923 *enc++ = AMF_NULL;
1924 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1925 if (!enc)
1926 return FALSE;
1928 /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
1929 enc = AMF_EncodeString(enc, pend, &av_live);
1930 if (!enc)
1931 return FALSE;
1933 packet.m_nBodySize = enc - packet.m_body;
1935 return RTMP_SendPacket(r, &packet, TRUE);
1938 SAVC(deleteStream);
1940 static int
1941 SendDeleteStream(RTMP *r, double dStreamId)
1943 RTMPPacket packet;
1944 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1945 char *enc;
1947 packet.m_nChannel = 0x03; /* control channel (invoke) */
1948 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1949 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1950 packet.m_nTimeStamp = 0;
1951 packet.m_nInfoField2 = 0;
1952 packet.m_hasAbsTimestamp = 0;
1953 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1955 enc = packet.m_body;
1956 enc = AMF_EncodeString(enc, pend, &av_deleteStream);
1957 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1958 *enc++ = AMF_NULL;
1959 enc = AMF_EncodeNumber(enc, pend, dStreamId);
1961 packet.m_nBodySize = enc - packet.m_body;
1963 /* no response expected */
1964 return RTMP_SendPacket(r, &packet, FALSE);
1967 SAVC(pause);
1970 RTMP_SendPause(RTMP *r, int DoPause, int iTime)
1972 RTMPPacket packet;
1973 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1974 char *enc;
1976 packet.m_nChannel = 0x08; /* video channel */
1977 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1978 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1979 packet.m_nTimeStamp = 0;
1980 packet.m_nInfoField2 = 0;
1981 packet.m_hasAbsTimestamp = 0;
1982 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1984 enc = packet.m_body;
1985 enc = AMF_EncodeString(enc, pend, &av_pause);
1986 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1987 *enc++ = AMF_NULL;
1988 enc = AMF_EncodeBoolean(enc, pend, DoPause);
1989 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
1991 packet.m_nBodySize = enc - packet.m_body;
1993 RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
1994 return RTMP_SendPacket(r, &packet, TRUE);
1997 int RTMP_Pause(RTMP *r, int DoPause)
1999 if (DoPause)
2000 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
2001 return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
2004 SAVC(seek);
2007 RTMP_SendSeek(RTMP *r, int iTime)
2009 RTMPPacket packet;
2010 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2011 char *enc;
2013 packet.m_nChannel = 0x08; /* video channel */
2014 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2015 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2016 packet.m_nTimeStamp = 0;
2017 packet.m_nInfoField2 = 0;
2018 packet.m_hasAbsTimestamp = 0;
2019 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2021 enc = packet.m_body;
2022 enc = AMF_EncodeString(enc, pend, &av_seek);
2023 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2024 *enc++ = AMF_NULL;
2025 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
2027 packet.m_nBodySize = enc - packet.m_body;
2029 r->m_read.flags |= RTMP_READ_SEEKING;
2030 r->m_read.nResumeTS = 0;
2032 return RTMP_SendPacket(r, &packet, TRUE);
2036 RTMP_SendServerBW(RTMP *r)
2038 RTMPPacket packet;
2039 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2041 packet.m_nChannel = 0x02; /* control channel (invoke) */
2042 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2043 packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
2044 packet.m_nTimeStamp = 0;
2045 packet.m_nInfoField2 = 0;
2046 packet.m_hasAbsTimestamp = 0;
2047 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2049 packet.m_nBodySize = 4;
2051 AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
2052 return RTMP_SendPacket(r, &packet, FALSE);
2056 RTMP_SendClientBW(RTMP *r)
2058 RTMPPacket packet;
2059 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2061 packet.m_nChannel = 0x02; /* control channel (invoke) */
2062 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2063 packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
2064 packet.m_nTimeStamp = 0;
2065 packet.m_nInfoField2 = 0;
2066 packet.m_hasAbsTimestamp = 0;
2067 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2069 packet.m_nBodySize = 5;
2071 AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
2072 packet.m_body[4] = r->m_nClientBW2;
2073 return RTMP_SendPacket(r, &packet, FALSE);
2076 static int
2077 SendBytesReceived(RTMP *r)
2079 RTMPPacket packet;
2080 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2082 packet.m_nChannel = 0x02; /* control channel (invoke) */
2083 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2084 packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
2085 packet.m_nTimeStamp = 0;
2086 packet.m_nInfoField2 = 0;
2087 packet.m_hasAbsTimestamp = 0;
2088 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2090 packet.m_nBodySize = 4;
2092 AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
2093 r->m_nBytesInSent = r->m_nBytesIn;
2095 /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
2096 return RTMP_SendPacket(r, &packet, FALSE);
2099 SAVC(_checkbw);
2101 static int
2102 SendCheckBW(RTMP *r)
2104 RTMPPacket packet;
2105 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2106 char *enc;
2108 packet.m_nChannel = 0x03; /* control channel (invoke) */
2109 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2110 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2111 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2112 packet.m_nInfoField2 = 0;
2113 packet.m_hasAbsTimestamp = 0;
2114 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2116 enc = packet.m_body;
2117 enc = AMF_EncodeString(enc, pend, &av__checkbw);
2118 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2119 *enc++ = AMF_NULL;
2121 packet.m_nBodySize = enc - packet.m_body;
2123 /* triggers _onbwcheck and eventually results in _onbwdone */
2124 return RTMP_SendPacket(r, &packet, FALSE);
2127 SAVC(_result);
2129 static int
2130 SendCheckBWResult(RTMP *r, double txn)
2132 RTMPPacket packet;
2133 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2134 char *enc;
2136 packet.m_nChannel = 0x03; /* control channel (invoke) */
2137 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2138 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2139 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2140 packet.m_nInfoField2 = 0;
2141 packet.m_hasAbsTimestamp = 0;
2142 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2144 enc = packet.m_body;
2145 enc = AMF_EncodeString(enc, pend, &av__result);
2146 enc = AMF_EncodeNumber(enc, pend, txn);
2147 *enc++ = AMF_NULL;
2148 enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
2150 packet.m_nBodySize = enc - packet.m_body;
2152 return RTMP_SendPacket(r, &packet, FALSE);
2155 SAVC(ping);
2156 SAVC(pong);
2158 static int
2159 SendPong(RTMP *r, double txn)
2161 RTMPPacket packet;
2162 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2163 char *enc;
2165 packet.m_nChannel = 0x03; /* control channel (invoke) */
2166 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2167 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2168 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2169 packet.m_nInfoField2 = 0;
2170 packet.m_hasAbsTimestamp = 0;
2171 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2173 enc = packet.m_body;
2174 enc = AMF_EncodeString(enc, pend, &av_pong);
2175 enc = AMF_EncodeNumber(enc, pend, txn);
2176 *enc++ = AMF_NULL;
2178 packet.m_nBodySize = enc - packet.m_body;
2180 return RTMP_SendPacket(r, &packet, FALSE);
2183 SAVC(play);
2185 static int
2186 SendPlay(RTMP *r)
2188 RTMPPacket packet;
2189 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2190 char *enc;
2192 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2193 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2194 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2195 packet.m_nTimeStamp = 0;
2196 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2197 packet.m_hasAbsTimestamp = 0;
2198 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2200 enc = packet.m_body;
2201 enc = AMF_EncodeString(enc, pend, &av_play);
2202 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2203 *enc++ = AMF_NULL;
2205 RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
2206 __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
2207 r->Link.playpath.av_val);
2208 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
2209 if (!enc)
2210 return FALSE;
2212 /* Optional parameters start and len.
2214 * start: -2, -1, 0, positive number
2215 * -2: looks for a live stream, then a recorded stream,
2216 * if not found any open a live stream
2217 * -1: plays a live stream
2218 * >=0: plays a recorded streams from 'start' milliseconds
2220 if (r->Link.lFlags & RTMP_LF_LIVE)
2221 enc = AMF_EncodeNumber(enc, pend, -1000.0);
2222 else
2224 if (r->Link.seekTime > 0.0)
2225 enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
2226 else
2227 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 */
2229 if (!enc)
2230 return FALSE;
2232 /* len: -1, 0, positive number
2233 * -1: plays live or recorded stream to the end (default)
2234 * 0: plays a frame 'start' ms away from the beginning
2235 * >0: plays a live or recoded stream for 'len' milliseconds
2237 /*enc += EncodeNumber(enc, -1.0); */ /* len */
2238 if (r->Link.stopTime)
2240 enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
2241 if (!enc)
2242 return FALSE;
2245 packet.m_nBodySize = enc - packet.m_body;
2247 return RTMP_SendPacket(r, &packet, TRUE);
2250 SAVC(set_playlist);
2251 SAVC(0);
2253 static int
2254 SendPlaylist(RTMP *r)
2256 RTMPPacket packet;
2257 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2258 char *enc;
2260 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2261 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2262 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2263 packet.m_nTimeStamp = 0;
2264 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2265 packet.m_hasAbsTimestamp = 0;
2266 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2268 enc = packet.m_body;
2269 enc = AMF_EncodeString(enc, pend, &av_set_playlist);
2270 enc = AMF_EncodeNumber(enc, pend, 0);
2271 *enc++ = AMF_NULL;
2272 *enc++ = AMF_ECMA_ARRAY;
2273 *enc++ = 0;
2274 *enc++ = 0;
2275 *enc++ = 0;
2276 *enc++ = AMF_OBJECT;
2277 enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.playpath);
2278 if (!enc)
2279 return FALSE;
2280 if (enc + 3 >= pend)
2281 return FALSE;
2282 *enc++ = 0;
2283 *enc++ = 0;
2284 *enc++ = AMF_OBJECT_END;
2286 packet.m_nBodySize = enc - packet.m_body;
2288 return RTMP_SendPacket(r, &packet, TRUE);
2291 static int
2292 SendSecureTokenResponse(RTMP *r, AVal *resp)
2294 RTMPPacket packet;
2295 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2296 char *enc;
2298 packet.m_nChannel = 0x03; /* control channel (invoke) */
2299 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2300 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2301 packet.m_nTimeStamp = 0;
2302 packet.m_nInfoField2 = 0;
2303 packet.m_hasAbsTimestamp = 0;
2304 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2306 enc = packet.m_body;
2307 enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
2308 enc = AMF_EncodeNumber(enc, pend, 0.0);
2309 *enc++ = AMF_NULL;
2310 enc = AMF_EncodeString(enc, pend, resp);
2311 if (!enc)
2312 return FALSE;
2314 packet.m_nBodySize = enc - packet.m_body;
2316 return RTMP_SendPacket(r, &packet, FALSE);
2320 from http://jira.red5.org/confluence/display/docs/Ping:
2322 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.
2324 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.
2326 * 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.
2327 * type 1: Tell the stream to clear the playing buffer.
2328 * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
2329 * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
2330 * type 6: Ping the client from server. The second parameter is the current time.
2331 * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
2332 * type 26: SWFVerification request
2333 * type 27: SWFVerification response
2336 RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
2338 RTMPPacket packet;
2339 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2340 int nSize;
2341 char *buf;
2343 RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
2345 packet.m_nChannel = 0x02; /* control channel (ping) */
2346 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2347 packet.m_packetType = RTMP_PACKET_TYPE_CONTROL;
2348 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2349 packet.m_nInfoField2 = 0;
2350 packet.m_hasAbsTimestamp = 0;
2351 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2353 switch(nType) {
2354 case 0x03: nSize = 10; break; /* buffer time */
2355 case 0x1A: nSize = 3; break; /* SWF verify request */
2356 case 0x1B: nSize = 44; break; /* SWF verify response */
2357 default: nSize = 6; break;
2360 packet.m_nBodySize = nSize;
2362 buf = packet.m_body;
2363 buf = AMF_EncodeInt16(buf, pend, nType);
2365 if (nType == 0x1B)
2367 #ifdef CRYPTO
2368 memcpy(buf, r->Link.SWFVerificationResponse, 42);
2369 RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
2370 RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
2371 #endif
2373 else if (nType == 0x1A)
2375 *buf = nObject & 0xff;
2377 else
2379 if (nSize > 2)
2380 buf = AMF_EncodeInt32(buf, pend, nObject);
2382 if (nSize > 6)
2383 buf = AMF_EncodeInt32(buf, pend, nTime);
2386 return RTMP_SendPacket(r, &packet, FALSE);
2389 static void
2390 AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
2392 if (freeit)
2393 free(vals[i].name.av_val);
2394 (*num)--;
2395 for (; i < *num; i++)
2397 vals[i] = vals[i + 1];
2399 vals[i].name.av_val = NULL;
2400 vals[i].name.av_len = 0;
2401 vals[i].num = 0;
2404 void
2405 RTMP_DropRequest(RTMP *r, int i, int freeit)
2407 AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
2410 static void
2411 AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
2413 char *tmp;
2414 if (!(*num & 0x0f))
2415 *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
2416 tmp = malloc(av->av_len + 1);
2417 memcpy(tmp, av->av_val, av->av_len);
2418 tmp[av->av_len] = '\0';
2419 (*vals)[*num].num = txn;
2420 (*vals)[*num].name.av_len = av->av_len;
2421 (*vals)[(*num)++].name.av_val = tmp;
2424 static void
2425 AV_clear(RTMP_METHOD *vals, int num)
2427 int i;
2428 for (i = 0; i < num; i++)
2429 free(vals[i].name.av_val);
2430 free(vals);
2433 SAVC(onBWDone);
2434 SAVC(onFCSubscribe);
2435 SAVC(onFCUnsubscribe);
2436 SAVC(_onbwcheck);
2437 SAVC(_onbwdone);
2438 SAVC(_error);
2439 SAVC(close);
2440 SAVC(code);
2441 SAVC(level);
2442 SAVC(onStatus);
2443 SAVC(playlist_ready);
2444 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
2445 static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
2446 static const AVal av_NetStream_Play_StreamNotFound =
2447 AVC("NetStream.Play.StreamNotFound");
2448 static const AVal av_NetConnection_Connect_InvalidApp =
2449 AVC("NetConnection.Connect.InvalidApp");
2450 static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
2451 static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
2452 static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
2453 static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
2454 static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
2455 static const AVal av_NetStream_Play_PublishNotify =
2456 AVC("NetStream.Play.PublishNotify");
2457 static const AVal av_NetStream_Play_UnpublishNotify =
2458 AVC("NetStream.Play.UnpublishNotify");
2459 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
2461 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
2462 static int
2463 HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
2465 AMFObject obj;
2466 AVal method;
2467 double txn;
2468 int ret = 0, nRes;
2469 if (body[0] != 0x02) /* make sure it is a string method name we start with */
2471 RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
2472 __FUNCTION__);
2473 return 0;
2476 nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
2477 if (nRes < 0)
2479 RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
2480 return 0;
2483 AMF_Dump(&obj);
2484 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
2485 txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
2486 RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
2488 if (AVMATCH(&method, &av__result))
2490 AVal methodInvoked = {0};
2491 int i;
2493 for (i=0; i<r->m_numCalls; i++) {
2494 if (r->m_methodCalls[i].num == (int)txn) {
2495 methodInvoked = r->m_methodCalls[i].name;
2496 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
2497 break;
2500 if (!methodInvoked.av_val) {
2501 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
2502 __FUNCTION__, txn);
2503 goto leave;
2506 RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
2507 methodInvoked.av_val);
2509 if (AVMATCH(&methodInvoked, &av_connect))
2511 if (r->Link.token.av_len)
2513 AMFObjectProperty p;
2514 if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
2516 DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
2517 SendSecureTokenResponse(r, &p.p_vu.p_aval);
2520 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2522 SendReleaseStream(r);
2523 SendFCPublish(r);
2525 else
2527 RTMP_SendServerBW(r);
2528 RTMP_SendCtrl(r, 3, 0, 300);
2530 RTMP_SendCreateStream(r);
2532 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
2534 /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
2535 if (r->Link.usherToken.av_len)
2536 SendUsherToken(r, &r->Link.usherToken);
2537 /* Send the FCSubscribe if live stream or if subscribepath is set */
2538 if (r->Link.subscribepath.av_len)
2539 SendFCSubscribe(r, &r->Link.subscribepath);
2540 else if (r->Link.lFlags & RTMP_LF_LIVE)
2541 SendFCSubscribe(r, &r->Link.playpath);
2544 else if (AVMATCH(&methodInvoked, &av_createStream))
2546 r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
2548 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2550 SendPublish(r);
2552 else
2554 if (r->Link.lFlags & RTMP_LF_PLST)
2555 SendPlaylist(r);
2556 SendPlay(r);
2557 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
2560 else if (AVMATCH(&methodInvoked, &av_play) ||
2561 AVMATCH(&methodInvoked, &av_publish))
2563 r->m_bPlaying = TRUE;
2565 free(methodInvoked.av_val);
2567 else if (AVMATCH(&method, &av_onBWDone))
2569 if (!r->m_nBWCheckCounter)
2570 SendCheckBW(r);
2572 else if (AVMATCH(&method, &av_onFCSubscribe))
2574 /* SendOnFCSubscribe(); */
2576 else if (AVMATCH(&method, &av_onFCUnsubscribe))
2578 RTMP_Close(r);
2579 ret = 1;
2581 else if (AVMATCH(&method, &av_ping))
2583 SendPong(r, txn);
2585 else if (AVMATCH(&method, &av__onbwcheck))
2587 SendCheckBWResult(r, txn);
2589 else if (AVMATCH(&method, &av__onbwdone))
2591 int i;
2592 for (i = 0; i < r->m_numCalls; i++)
2593 if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
2595 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2596 break;
2599 else if (AVMATCH(&method, &av__error))
2601 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
2603 else if (AVMATCH(&method, &av_close))
2605 RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
2606 RTMP_Close(r);
2608 else if (AVMATCH(&method, &av_onStatus))
2610 AMFObject obj2;
2611 AVal code, level;
2612 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
2613 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
2614 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
2616 RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
2617 if (AVMATCH(&code, &av_NetStream_Failed)
2618 || AVMATCH(&code, &av_NetStream_Play_Failed)
2619 || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
2620 || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
2622 r->m_stream_id = -1;
2623 RTMP_Close(r);
2624 RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val);
2627 else if (AVMATCH(&code, &av_NetStream_Play_Start)
2628 || AVMATCH(&code, &av_NetStream_Play_PublishNotify))
2630 int i;
2631 r->m_bPlaying = TRUE;
2632 for (i = 0; i < r->m_numCalls; i++)
2634 if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
2636 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2637 break;
2642 else if (AVMATCH(&code, &av_NetStream_Publish_Start))
2644 int i;
2645 r->m_bPlaying = TRUE;
2646 for (i = 0; i < r->m_numCalls; i++)
2648 if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
2650 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2651 break;
2656 /* Return 1 if this is a Play.Complete or Play.Stop */
2657 else if (AVMATCH(&code, &av_NetStream_Play_Complete)
2658 || AVMATCH(&code, &av_NetStream_Play_Stop)
2659 || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
2661 RTMP_Close(r);
2662 ret = 1;
2665 else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
2667 r->m_read.flags &= ~RTMP_READ_SEEKING;
2670 else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
2672 if (r->m_pausing == 1 || r->m_pausing == 2)
2674 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
2675 r->m_pausing = 3;
2679 else if (AVMATCH(&method, &av_playlist_ready))
2681 int i;
2682 for (i = 0; i < r->m_numCalls; i++)
2684 if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
2686 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
2687 break;
2691 else
2695 leave:
2696 AMF_Reset(&obj);
2697 return ret;
2701 RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
2702 AMFObjectProperty * p)
2704 int n;
2705 /* this is a small object search to locate the "duration" property */
2706 for (n = 0; n < obj->o_num; n++)
2708 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
2710 if (AVMATCH(&prop->p_name, name))
2712 memcpy(p, prop, sizeof(*prop));
2713 return TRUE;
2716 if (prop->p_type == AMF_OBJECT)
2718 if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
2719 return TRUE;
2722 return FALSE;
2725 /* Like above, but only check if name is a prefix of property */
2727 RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
2728 AMFObjectProperty * p)
2730 int n;
2731 for (n = 0; n < obj->o_num; n++)
2733 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
2735 if (prop->p_name.av_len > name->av_len &&
2736 !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
2738 memcpy(p, prop, sizeof(*prop));
2739 return TRUE;
2742 if (prop->p_type == AMF_OBJECT)
2744 if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
2745 return TRUE;
2748 return FALSE;
2751 static int
2752 DumpMetaData(AMFObject *obj)
2754 AMFObjectProperty *prop;
2755 int n;
2756 for (n = 0; n < obj->o_num; n++)
2758 prop = AMF_GetProp(obj, NULL, n);
2759 if (prop->p_type != AMF_OBJECT)
2761 char str[256] = "";
2762 switch (prop->p_type)
2764 case AMF_NUMBER:
2765 snprintf(str, 255, "%.2f", prop->p_vu.p_number);
2766 break;
2767 case AMF_BOOLEAN:
2768 snprintf(str, 255, "%s",
2769 prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
2770 break;
2771 case AMF_STRING:
2772 snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
2773 prop->p_vu.p_aval.av_val);
2774 break;
2775 case AMF_DATE:
2776 snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
2777 break;
2778 default:
2779 snprintf(str, 255, "INVALID TYPE 0x%02x",
2780 (unsigned char)prop->p_type);
2782 if (prop->p_name.av_len)
2784 /* chomp */
2785 if (strlen(str) >= 1 && str[strlen(str) - 1] == '\n')
2786 str[strlen(str) - 1] = '\0';
2787 RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
2788 prop->p_name.av_val, str);
2791 else
2793 if (prop->p_name.av_len)
2794 RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
2795 DumpMetaData(&prop->p_vu.p_object);
2798 return FALSE;
2801 SAVC(onMetaData);
2802 SAVC(duration);
2803 SAVC(video);
2804 SAVC(audio);
2806 static int
2807 HandleMetadata(RTMP *r, char *body, unsigned int len)
2809 /* allright we get some info here, so parse it and print it */
2810 /* also keep duration or filesize to make a nice progress bar */
2812 AMFObject obj;
2813 AVal metastring;
2814 int ret = FALSE;
2816 int nRes = AMF_Decode(&obj, body, len, FALSE);
2817 if (nRes < 0)
2819 RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
2820 return FALSE;
2823 AMF_Dump(&obj);
2824 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
2826 if (AVMATCH(&metastring, &av_onMetaData))
2828 AMFObjectProperty prop;
2829 /* Show metadata */
2830 RTMP_Log(RTMP_LOGINFO, "Metadata:");
2831 DumpMetaData(&obj);
2832 if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
2834 r->m_fDuration = prop.p_vu.p_number;
2835 /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
2837 /* Search for audio or video tags */
2838 if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
2839 r->m_read.dataType |= 1;
2840 if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
2841 r->m_read.dataType |= 4;
2842 ret = TRUE;
2844 AMF_Reset(&obj);
2845 return ret;
2848 static void
2849 HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
2851 if (packet->m_nBodySize >= 4)
2853 r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
2854 RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
2855 r->m_inChunkSize);
2859 static void
2860 HandleAudio(RTMP *r, const RTMPPacket *packet)
2864 static void
2865 HandleVideo(RTMP *r, const RTMPPacket *packet)
2869 static void
2870 HandleCtrl(RTMP *r, const RTMPPacket *packet)
2872 short nType = -1;
2873 unsigned int tmp;
2874 if (packet->m_body && packet->m_nBodySize >= 2)
2875 nType = AMF_DecodeInt16(packet->m_body);
2876 RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
2877 packet->m_nBodySize);
2878 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
2880 if (packet->m_nBodySize >= 6)
2882 switch (nType)
2884 case 0:
2885 tmp = AMF_DecodeInt32(packet->m_body + 2);
2886 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
2887 break;
2889 case 1:
2890 tmp = AMF_DecodeInt32(packet->m_body + 2);
2891 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
2892 if (r->m_pausing == 1)
2893 r->m_pausing = 2;
2894 break;
2896 case 2:
2897 tmp = AMF_DecodeInt32(packet->m_body + 2);
2898 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
2899 break;
2901 case 4:
2902 tmp = AMF_DecodeInt32(packet->m_body + 2);
2903 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
2904 break;
2906 case 6: /* server ping. reply with pong. */
2907 tmp = AMF_DecodeInt32(packet->m_body + 2);
2908 RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
2909 RTMP_SendCtrl(r, 0x07, tmp, 0);
2910 break;
2912 /* FMS 3.5 servers send the following two controls to let the client
2913 * know when the server has sent a complete buffer. I.e., when the
2914 * server has sent an amount of data equal to m_nBufferMS in duration.
2915 * The server meters its output so that data arrives at the client
2916 * in realtime and no faster.
2918 * The rtmpdump program tries to set m_nBufferMS as large as
2919 * possible, to force the server to send data as fast as possible.
2920 * In practice, the server appears to cap this at about 1 hour's
2921 * worth of data. After the server has sent a complete buffer, and
2922 * sends this BufferEmpty message, it will wait until the play
2923 * duration of that buffer has passed before sending a new buffer.
2924 * The BufferReady message will be sent when the new buffer starts.
2925 * (There is no BufferReady message for the very first buffer;
2926 * presumably the Stream Begin message is sufficient for that
2927 * purpose.)
2929 * If the network speed is much faster than the data bitrate, then
2930 * there may be long delays between the end of one buffer and the
2931 * start of the next.
2933 * Since usually the network allows data to be sent at
2934 * faster than realtime, and rtmpdump wants to download the data
2935 * as fast as possible, we use this RTMP_LF_BUFX hack: when we
2936 * get the BufferEmpty message, we send a Pause followed by an
2937 * Unpause. This causes the server to send the next buffer immediately
2938 * instead of waiting for the full duration to elapse. (That's
2939 * also the purpose of the ToggleStream function, which rtmpdump
2940 * calls if we get a read timeout.)
2942 * Media player apps don't need this hack since they are just
2943 * going to play the data in realtime anyway. It also doesn't work
2944 * for live streams since they obviously can only be sent in
2945 * realtime. And it's all moot if the network speed is actually
2946 * slower than the media bitrate.
2948 case 31:
2949 tmp = AMF_DecodeInt32(packet->m_body + 2);
2950 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
2951 if (!(r->Link.lFlags & RTMP_LF_BUFX))
2952 break;
2953 if (!r->m_pausing)
2955 r->m_pauseStamp = r->m_channelTimestamp[r->m_mediaChannel];
2956 RTMP_SendPause(r, TRUE, r->m_pauseStamp);
2957 r->m_pausing = 1;
2959 else if (r->m_pausing == 2)
2961 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
2962 r->m_pausing = 3;
2964 break;
2966 case 32:
2967 tmp = AMF_DecodeInt32(packet->m_body + 2);
2968 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
2969 break;
2971 default:
2972 tmp = AMF_DecodeInt32(packet->m_body + 2);
2973 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
2974 break;
2979 if (nType == 0x1A)
2981 RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
2982 if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
2984 RTMP_Log(RTMP_LOGERROR,
2985 "%s: SWFVerification Type %d request not supported! Patches welcome...",
2986 __FUNCTION__, packet->m_body[2]);
2988 #ifdef CRYPTO
2989 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
2991 /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
2992 else if (r->Link.SWFSize)
2994 RTMP_SendCtrl(r, 0x1B, 0, 0);
2996 else
2998 RTMP_Log(RTMP_LOGERROR,
2999 "%s: Ignoring SWFVerification request, use --swfVfy!",
3000 __FUNCTION__);
3002 #else
3003 RTMP_Log(RTMP_LOGERROR,
3004 "%s: Ignoring SWFVerification request, no CRYPTO support!",
3005 __FUNCTION__);
3006 #endif
3010 static void
3011 HandleServerBW(RTMP *r, const RTMPPacket *packet)
3013 r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
3014 RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
3017 static void
3018 HandleClientBW(RTMP *r, const RTMPPacket *packet)
3020 r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
3021 if (packet->m_nBodySize > 4)
3022 r->m_nClientBW2 = packet->m_body[4];
3023 else
3024 r->m_nClientBW2 = -1;
3025 RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
3026 r->m_nClientBW2);
3029 static int
3030 DecodeInt32LE(const char *data)
3032 unsigned char *c = (unsigned char *)data;
3033 unsigned int val;
3035 val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
3036 return val;
3039 static int
3040 EncodeInt32LE(char *output, int nVal)
3042 output[0] = nVal;
3043 nVal >>= 8;
3044 output[1] = nVal;
3045 nVal >>= 8;
3046 output[2] = nVal;
3047 nVal >>= 8;
3048 output[3] = nVal;
3049 return 4;
3053 RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
3055 uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
3056 char *header = (char *)hbuf;
3057 int nSize, hSize, nToRead, nChunk;
3058 int didAlloc = FALSE;
3060 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);
3062 if (ReadN(r, (char *)hbuf, 1) == 0)
3064 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
3065 return FALSE;
3068 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3069 packet->m_nChannel = (hbuf[0] & 0x3f);
3070 header++;
3071 if (packet->m_nChannel == 0)
3073 if (ReadN(r, (char *)&hbuf[1], 1) != 1)
3075 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
3076 __FUNCTION__);
3077 return FALSE;
3079 packet->m_nChannel = hbuf[1];
3080 packet->m_nChannel += 64;
3081 header++;
3083 else if (packet->m_nChannel == 1)
3085 int tmp;
3086 if (ReadN(r, (char *)&hbuf[1], 2) != 2)
3088 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
3089 __FUNCTION__);
3090 return FALSE;
3092 tmp = (hbuf[2] << 8) + hbuf[1];
3093 packet->m_nChannel = tmp + 64;
3094 RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
3095 header += 2;
3098 nSize = packetSize[packet->m_headerType];
3100 if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
3101 packet->m_hasAbsTimestamp = TRUE;
3103 else if (nSize < RTMP_LARGE_HEADER_SIZE)
3104 { /* using values from the last message of this channel */
3105 if (r->m_vecChannelsIn[packet->m_nChannel])
3106 memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
3107 sizeof(RTMPPacket));
3110 nSize--;
3112 if (nSize > 0 && ReadN(r, header, nSize) != nSize)
3114 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
3115 __FUNCTION__, (unsigned int)hbuf[0]);
3116 return FALSE;
3119 hSize = nSize + (header - (char *)hbuf);
3121 if (nSize >= 3)
3123 packet->m_nTimeStamp = AMF_DecodeInt24(header);
3125 /*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); */
3127 if (nSize >= 6)
3129 packet->m_nBodySize = AMF_DecodeInt24(header + 3);
3130 packet->m_nBytesRead = 0;
3131 RTMPPacket_Free(packet);
3133 if (nSize > 6)
3135 packet->m_packetType = header[6];
3137 if (nSize == 11)
3138 packet->m_nInfoField2 = DecodeInt32LE(header + 7);
3141 if (packet->m_nTimeStamp == 0xffffff)
3143 if (ReadN(r, header + nSize, 4) != 4)
3145 RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
3146 __FUNCTION__);
3147 return FALSE;
3149 packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
3150 hSize += 4;
3154 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
3156 if (packet->m_nBodySize > 0 && packet->m_body == NULL)
3158 if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
3160 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
3161 return FALSE;
3163 didAlloc = TRUE;
3164 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3167 nToRead = packet->m_nBodySize - packet->m_nBytesRead;
3168 nChunk = r->m_inChunkSize;
3169 if (nToRead < nChunk)
3170 nChunk = nToRead;
3172 /* Does the caller want the raw chunk? */
3173 if (packet->m_chunk)
3175 packet->m_chunk->c_headerSize = hSize;
3176 memcpy(packet->m_chunk->c_header, hbuf, hSize);
3177 packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
3178 packet->m_chunk->c_chunkSize = nChunk;
3181 if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
3183 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %u",
3184 __FUNCTION__, packet->m_nBodySize);
3185 return FALSE;
3188 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
3190 packet->m_nBytesRead += nChunk;
3192 /* keep the packet as ref for other packets on this channel */
3193 if (!r->m_vecChannelsIn[packet->m_nChannel])
3194 r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3195 memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
3197 if (RTMPPacket_IsReady(packet))
3199 /* make packet's timestamp absolute */
3200 if (!packet->m_hasAbsTimestamp)
3201 packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
3203 r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
3205 /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
3206 /* arrives and requests to re-use some info (small packet header) */
3207 r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
3208 r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
3209 r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
3211 else
3213 packet->m_body = NULL; /* so it won't be erased on free */
3216 return TRUE;
3219 #ifndef CRYPTO
3220 static int
3221 HandShake(RTMP *r, int FP9HandShake)
3223 int i;
3224 uint32_t uptime, suptime;
3225 int bMatch;
3226 char type;
3227 char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
3228 char serversig[RTMP_SIG_SIZE];
3230 clientbuf[0] = 0x03; /* not encrypted */
3232 uptime = htonl(RTMP_GetTime());
3233 memcpy(clientsig, &uptime, 4);
3235 memset(&clientsig[4], 0, 4);
3237 #ifdef _DEBUG
3238 for (i = 8; i < RTMP_SIG_SIZE; i++)
3239 clientsig[i] = 0xff;
3240 #else
3241 for (i = 8; i < RTMP_SIG_SIZE; i++)
3242 clientsig[i] = (char)(rand() % 256);
3243 #endif
3245 if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
3246 return FALSE;
3248 if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
3249 return FALSE;
3251 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
3253 if (type != clientbuf[0])
3254 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
3255 __FUNCTION__, clientbuf[0], type);
3257 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3258 return FALSE;
3260 /* decode server response */
3262 memcpy(&suptime, serversig, 4);
3263 suptime = ntohl(suptime);
3265 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
3266 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
3267 serversig[4], serversig[5], serversig[6], serversig[7]);
3269 /* 2nd part of handshake */
3270 if (!WriteN(r, serversig, RTMP_SIG_SIZE))
3271 return FALSE;
3273 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3274 return FALSE;
3276 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3277 if (!bMatch)
3279 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3281 return TRUE;
3284 static int
3285 SHandShake(RTMP *r)
3287 int i;
3288 char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1;
3289 char clientsig[RTMP_SIG_SIZE];
3290 uint32_t uptime;
3291 int bMatch;
3293 if (ReadN(r, serverbuf, 1) != 1) /* 0x03 or 0x06 */
3294 return FALSE;
3296 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Request : %02X", __FUNCTION__, serverbuf[0]);
3298 if (serverbuf[0] != 3)
3300 RTMP_Log(RTMP_LOGERROR, "%s: Type unknown: client sent %02X",
3301 __FUNCTION__, serverbuf[0]);
3302 return FALSE;
3305 uptime = htonl(RTMP_GetTime());
3306 memcpy(serversig, &uptime, 4);
3308 memset(&serversig[4], 0, 4);
3309 #ifdef _DEBUG
3310 for (i = 8; i < RTMP_SIG_SIZE; i++)
3311 serversig[i] = 0xff;
3312 #else
3313 for (i = 8; i < RTMP_SIG_SIZE; i++)
3314 serversig[i] = (char)(rand() % 256);
3315 #endif
3317 if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1))
3318 return FALSE;
3320 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3321 return FALSE;
3323 /* decode client response */
3325 memcpy(&uptime, clientsig, 4);
3326 uptime = ntohl(uptime);
3328 RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
3329 RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__,
3330 clientsig[4], clientsig[5], clientsig[6], clientsig[7]);
3332 /* 2nd part of handshake */
3333 if (!WriteN(r, clientsig, RTMP_SIG_SIZE))
3334 return FALSE;
3336 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3337 return FALSE;
3339 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3340 if (!bMatch)
3342 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3344 return TRUE;
3346 #endif
3349 RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
3351 int wrote;
3352 char hbuf[RTMP_MAX_HEADER_SIZE];
3354 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3355 chunk->c_chunkSize);
3356 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
3357 if (chunk->c_chunkSize)
3359 char *ptr = chunk->c_chunk - chunk->c_headerSize;
3360 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
3361 /* save header bytes we're about to overwrite */
3362 memcpy(hbuf, ptr, chunk->c_headerSize);
3363 memcpy(ptr, chunk->c_header, chunk->c_headerSize);
3364 wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
3365 memcpy(ptr, hbuf, chunk->c_headerSize);
3367 else
3368 wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
3369 return wrote;
3373 RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
3375 const RTMPPacket *prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
3376 uint32_t last = 0;
3377 int nSize;
3378 int hSize, cSize;
3379 char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
3380 uint32_t t;
3381 char *buffer, *tbuf = NULL, *toff = NULL;
3382 int nChunkSize;
3383 int tlen;
3385 if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
3387 /* compress a bit by using the prev packet's attributes */
3388 if (prevPacket->m_nBodySize == packet->m_nBodySize
3389 && prevPacket->m_packetType == packet->m_packetType
3390 && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
3391 packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
3393 if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
3394 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
3395 packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
3396 last = prevPacket->m_nTimeStamp;
3399 if (packet->m_headerType > 3) /* sanity */
3401 RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
3402 (unsigned char)packet->m_headerType);
3403 return FALSE;
3406 nSize = packetSize[packet->m_headerType];
3407 hSize = nSize; cSize = 0;
3408 t = packet->m_nTimeStamp - last;
3410 if (packet->m_body)
3412 header = packet->m_body - nSize;
3413 hend = packet->m_body;
3415 else
3417 header = hbuf + 6;
3418 hend = hbuf + sizeof(hbuf);
3421 if (packet->m_nChannel > 319)
3422 cSize = 2;
3423 else if (packet->m_nChannel > 63)
3424 cSize = 1;
3425 if (cSize)
3427 header -= cSize;
3428 hSize += cSize;
3431 if (nSize > 1 && t >= 0xffffff)
3433 header -= 4;
3434 hSize += 4;
3437 hptr = header;
3438 c = packet->m_headerType << 6;
3439 switch (cSize)
3441 case 0:
3442 c |= packet->m_nChannel;
3443 break;
3444 case 1:
3445 break;
3446 case 2:
3447 c |= 1;
3448 break;
3450 *hptr++ = c;
3451 if (cSize)
3453 int tmp = packet->m_nChannel - 64;
3454 *hptr++ = tmp & 0xff;
3455 if (cSize == 2)
3456 *hptr++ = tmp >> 8;
3459 if (nSize > 1)
3461 hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
3464 if (nSize > 4)
3466 hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
3467 *hptr++ = packet->m_packetType;
3470 if (nSize > 8)
3471 hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
3473 if (nSize > 1 && t >= 0xffffff)
3474 hptr = AMF_EncodeInt32(hptr, hend, t);
3476 nSize = packet->m_nBodySize;
3477 buffer = packet->m_body;
3478 nChunkSize = r->m_outChunkSize;
3480 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3481 nSize);
3482 /* send all chunks in one HTTP request */
3483 if (r->Link.protocol & RTMP_FEATURE_HTTP)
3485 int chunks = (nSize+nChunkSize-1) / nChunkSize;
3486 if (chunks > 1)
3488 tlen = chunks * (cSize + 1) + nSize + hSize;
3489 tbuf = malloc(tlen);
3490 if (!tbuf)
3491 return FALSE;
3492 toff = tbuf;
3495 while (nSize + hSize)
3497 int wrote;
3499 if (nSize < nChunkSize)
3500 nChunkSize = nSize;
3502 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
3503 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
3504 if (tbuf)
3506 memcpy(toff, header, nChunkSize + hSize);
3507 toff += nChunkSize + hSize;
3509 else
3511 wrote = WriteN(r, header, nChunkSize + hSize);
3512 if (!wrote)
3513 return FALSE;
3515 nSize -= nChunkSize;
3516 buffer += nChunkSize;
3517 hSize = 0;
3519 if (nSize > 0)
3521 header = buffer - 1;
3522 hSize = 1;
3523 if (cSize)
3525 header -= cSize;
3526 hSize += cSize;
3528 *header = (0xc0 | c);
3529 if (cSize)
3531 int tmp = packet->m_nChannel - 64;
3532 header[1] = tmp & 0xff;
3533 if (cSize == 2)
3534 header[2] = tmp >> 8;
3538 if (tbuf)
3540 int wrote = WriteN(r, tbuf, toff-tbuf);
3541 free(tbuf);
3542 tbuf = NULL;
3543 if (!wrote)
3544 return FALSE;
3547 /* we invoked a remote method */
3548 if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE)
3550 AVal method;
3551 char *ptr;
3552 ptr = packet->m_body + 1;
3553 AMF_DecodeString(ptr, &method);
3554 RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
3555 /* keep it in call queue till result arrives */
3556 if (queue) {
3557 int txn;
3558 ptr += 3 + method.av_len;
3559 txn = (int)AMF_DecodeNumber(ptr);
3560 AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
3564 if (!r->m_vecChannelsOut[packet->m_nChannel])
3565 r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3566 memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
3567 return TRUE;
3571 RTMP_Serve(RTMP *r)
3573 return SHandShake(r);
3576 void
3577 RTMP_Close(RTMP *r)
3579 int i;
3581 if (RTMP_IsConnected(r))
3583 if (r->m_stream_id > 0)
3585 i = r->m_stream_id;
3586 r->m_stream_id = 0;
3587 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
3588 SendFCUnpublish(r);
3589 SendDeleteStream(r, i);
3591 if (r->m_clientID.av_val)
3593 HTTP_Post(r, RTMPT_CLOSE, "", 1);
3594 free(r->m_clientID.av_val);
3595 r->m_clientID.av_val = NULL;
3596 r->m_clientID.av_len = 0;
3598 RTMPSockBuf_Close(&r->m_sb);
3601 r->m_stream_id = -1;
3602 r->m_sb.sb_socket = -1;
3603 r->m_nBWCheckCounter = 0;
3604 r->m_nBytesIn = 0;
3605 r->m_nBytesInSent = 0;
3607 if (r->m_read.flags & RTMP_READ_HEADER) {
3608 free(r->m_read.buf);
3609 r->m_read.buf = NULL;
3611 r->m_read.dataType = 0;
3612 r->m_read.flags = 0;
3613 r->m_read.status = 0;
3614 r->m_read.nResumeTS = 0;
3615 r->m_read.nIgnoredFrameCounter = 0;
3616 r->m_read.nIgnoredFlvFrameCounter = 0;
3618 r->m_write.m_nBytesRead = 0;
3619 RTMPPacket_Free(&r->m_write);
3621 for (i = 0; i < RTMP_CHANNELS; i++)
3623 if (r->m_vecChannelsIn[i])
3625 RTMPPacket_Free(r->m_vecChannelsIn[i]);
3626 free(r->m_vecChannelsIn[i]);
3627 r->m_vecChannelsIn[i] = NULL;
3629 if (r->m_vecChannelsOut[i])
3631 free(r->m_vecChannelsOut[i]);
3632 r->m_vecChannelsOut[i] = NULL;
3635 AV_clear(r->m_methodCalls, r->m_numCalls);
3636 r->m_methodCalls = NULL;
3637 r->m_numCalls = 0;
3638 r->m_numInvokes = 0;
3640 r->m_bPlaying = FALSE;
3641 r->m_sb.sb_size = 0;
3643 r->m_msgCounter = 0;
3644 r->m_resplen = 0;
3645 r->m_unackd = 0;
3647 free(r->Link.playpath0.av_val);
3648 r->Link.playpath0.av_val = NULL;
3650 if (r->Link.lFlags & RTMP_LF_FTCU)
3652 free(r->Link.tcUrl.av_val);
3653 r->Link.tcUrl.av_val = NULL;
3654 r->Link.lFlags ^= RTMP_LF_FTCU;
3657 #ifdef CRYPTO
3658 if (r->Link.dh)
3660 MDH_free(r->Link.dh);
3661 r->Link.dh = NULL;
3663 if (r->Link.rc4keyIn)
3665 RC4_free(r->Link.rc4keyIn);
3666 r->Link.rc4keyIn = NULL;
3668 if (r->Link.rc4keyOut)
3670 RC4_free(r->Link.rc4keyOut);
3671 r->Link.rc4keyOut = NULL;
3673 #endif
3677 RTMPSockBuf_Fill(RTMPSockBuf *sb)
3679 int nBytes;
3681 if (!sb->sb_size)
3682 sb->sb_start = sb->sb_buf;
3684 while (1)
3686 nBytes = sizeof(sb->sb_buf) - 1 - sb->sb_size - (sb->sb_start - sb->sb_buf);
3687 #if defined(CRYPTO) && !defined(NO_SSL)
3688 if (sb->sb_ssl)
3690 nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
3692 else
3693 #endif
3695 nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
3697 if (nBytes != -1)
3699 sb->sb_size += nBytes;
3701 else
3703 int sockerr = GetSockError();
3704 RTMP_Log(RTMP_LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
3705 __FUNCTION__, nBytes, sockerr, strerror(sockerr));
3706 if (sockerr == EINTR && !RTMP_ctrlC)
3707 continue;
3709 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
3711 sb->sb_timedout = TRUE;
3712 nBytes = 0;
3715 break;
3718 return nBytes;
3722 RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
3724 int rc;
3726 #ifdef _DEBUG
3727 fwrite(buf, 1, len, netstackdump);
3728 #endif
3730 #if defined(CRYPTO) && !defined(NO_SSL)
3731 if (sb->sb_ssl)
3733 rc = TLS_write(sb->sb_ssl, buf, len);
3735 else
3736 #endif
3738 rc = send(sb->sb_socket, buf, len, 0);
3740 return rc;
3744 RTMPSockBuf_Close(RTMPSockBuf *sb)
3746 #if defined(CRYPTO) && !defined(NO_SSL)
3747 if (sb->sb_ssl)
3749 TLS_shutdown(sb->sb_ssl);
3750 TLS_close(sb->sb_ssl);
3751 sb->sb_ssl = NULL;
3753 #endif
3754 if (sb->sb_socket != -1)
3755 return closesocket(sb->sb_socket);
3756 return 0;
3759 #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
3761 static void
3762 DecodeTEA(AVal *key, AVal *text)
3764 uint32_t *v, k[4] = { 0 }, u;
3765 uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
3766 int32_t p, q;
3767 int i, n;
3768 unsigned char *ptr, *out;
3770 /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
3771 ptr = (unsigned char *)key->av_val;
3772 u = 0;
3773 n = 0;
3774 v = k;
3775 p = key->av_len > 16 ? 16 : key->av_len;
3776 for (i = 0; i < p; i++)
3778 u |= ptr[i] << (n * 8);
3779 if (n == 3)
3781 *v++ = u;
3782 u = 0;
3783 n = 0;
3785 else
3787 n++;
3790 /* any trailing chars */
3791 if (u)
3792 *v = u;
3794 /* prep text: hex2bin, multiples of 4 */
3795 n = (text->av_len + 7) / 8;
3796 out = malloc(n * 8);
3797 ptr = (unsigned char *)text->av_val;
3798 v = (uint32_t *) out;
3799 for (i = 0; i < n; i++)
3801 u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
3802 u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
3803 u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
3804 u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
3805 *v++ = u;
3806 ptr += 8;
3808 v = (uint32_t *) out;
3810 /* http://www.movable-type.co.uk/scripts/tea-block.html */
3811 #define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
3812 z = v[n - 1];
3813 y = v[0];
3814 q = 6 + 52 / n;
3815 sum = q * DELTA;
3816 while (sum != 0)
3818 e = sum >> 2 & 3;
3819 for (p = n - 1; p > 0; p--)
3820 z = v[p - 1], y = v[p] -= MX;
3821 z = v[n - 1];
3822 y = v[0] -= MX;
3823 sum -= DELTA;
3826 text->av_len /= 2;
3827 memcpy(text->av_val, out, text->av_len);
3828 free(out);
3831 static int
3832 HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
3834 char hbuf[512];
3835 int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
3836 "Host: %.*s:%d\r\n"
3837 "Accept: */*\r\n"
3838 "User-Agent: Shockwave Flash\n"
3839 "Connection: Keep-Alive\n"
3840 "Cache-Control: no-cache\r\n"
3841 "Content-type: application/x-fcs\r\n"
3842 "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
3843 r->m_clientID.av_val ? r->m_clientID.av_val : "",
3844 r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
3845 r->Link.port, len);
3846 RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
3847 hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
3848 r->m_msgCounter++;
3849 r->m_unackd++;
3850 return hlen;
3853 static int
3854 HTTP_read(RTMP *r, int fill)
3856 char *ptr;
3857 int hlen;
3859 restart:
3860 if (fill)
3861 RTMPSockBuf_Fill(&r->m_sb);
3862 if (r->m_sb.sb_size < 13) {
3863 if (fill)
3864 goto restart;
3865 return -2;
3867 if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
3868 return -1;
3869 r->m_sb.sb_start[r->m_sb.sb_size] = '\0';
3870 if (!strstr(r->m_sb.sb_start, "\r\n\r\n")) {
3871 if (fill)
3872 goto restart;
3873 return -2;
3876 ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
3877 while ((ptr = strstr(ptr, "Content-"))) {
3878 if (!strncasecmp(ptr+8, "length:", 7)) break;
3879 ptr += 8;
3881 if (!ptr)
3882 return -1;
3883 hlen = atoi(ptr+16);
3884 ptr = strstr(ptr+16, "\r\n\r\n");
3885 if (!ptr)
3886 return -1;
3887 ptr += 4;
3888 if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size)
3890 if (fill)
3891 goto restart;
3892 return -2;
3894 r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
3895 r->m_sb.sb_start = ptr;
3896 r->m_unackd--;
3898 if (!r->m_clientID.av_val)
3900 r->m_clientID.av_len = hlen;
3901 r->m_clientID.av_val = malloc(hlen+1);
3902 if (!r->m_clientID.av_val)
3903 return -1;
3904 r->m_clientID.av_val[0] = '/';
3905 memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
3906 r->m_clientID.av_val[hlen] = 0;
3907 r->m_sb.sb_size = 0;
3909 else
3911 r->m_polling = *ptr++;
3912 r->m_resplen = hlen - 1;
3913 r->m_sb.sb_start++;
3914 r->m_sb.sb_size--;
3916 return 0;
3919 #define MAX_IGNORED_FRAMES 50
3921 /* Read from the stream until we get a media packet.
3922 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
3923 * packets, 0 if ignorable error, >0 if there is a media packet
3925 static int
3926 Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
3928 uint32_t prevTagSize = 0;
3929 int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
3930 RTMPPacket packet = { 0 };
3931 int recopy = FALSE;
3932 unsigned int size;
3933 char *ptr, *pend;
3934 uint32_t nTimeStamp = 0;
3935 unsigned int len;
3937 rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
3938 while (rtnGetNextMediaPacket)
3940 char *packetBody = packet.m_body;
3941 unsigned int nPacketLen = packet.m_nBodySize;
3943 /* Return RTMP_READ_COMPLETE if this was completed nicely with
3944 * invoke message Play.Stop or Play.Complete
3946 if (rtnGetNextMediaPacket == 2)
3948 RTMP_Log(RTMP_LOGDEBUG,
3949 "Got Play.Complete or Play.Stop from server. "
3950 "Assuming stream is complete");
3951 ret = RTMP_READ_COMPLETE;
3952 break;
3955 r->m_read.dataType |= (((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) << 2) |
3956 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO));
3958 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO && nPacketLen <= 5)
3960 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
3961 nPacketLen);
3962 ret = RTMP_READ_IGNORE;
3963 break;
3965 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO && nPacketLen <= 1)
3967 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
3968 nPacketLen);
3969 ret = RTMP_READ_IGNORE;
3970 break;
3973 if (r->m_read.flags & RTMP_READ_SEEKING)
3975 ret = RTMP_READ_IGNORE;
3976 break;
3978 #ifdef _DEBUG
3979 RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
3980 packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
3981 packet.m_hasAbsTimestamp);
3982 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
3983 RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
3984 #endif
3986 if (r->m_read.flags & RTMP_READ_RESUME)
3988 /* check the header if we get one */
3989 if (packet.m_nTimeStamp == 0)
3991 if (r->m_read.nMetaHeaderSize > 0
3992 && packet.m_packetType == RTMP_PACKET_TYPE_INFO)
3994 AMFObject metaObj;
3995 int nRes =
3996 AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
3997 if (nRes >= 0)
3999 AVal metastring;
4000 AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
4001 &metastring);
4003 if (AVMATCH(&metastring, &av_onMetaData))
4005 /* compare */
4006 if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
4007 (memcmp
4008 (r->m_read.metaHeader, packetBody,
4009 r->m_read.nMetaHeaderSize) != 0))
4011 ret = RTMP_READ_ERROR;
4014 AMF_Reset(&metaObj);
4015 if (ret == RTMP_READ_ERROR)
4016 break;
4020 /* check first keyframe to make sure we got the right position
4021 * in the stream! (the first non ignored frame)
4023 if (r->m_read.nInitialFrameSize > 0)
4025 /* video or audio data */
4026 if (packet.m_packetType == r->m_read.initialFrameType
4027 && r->m_read.nInitialFrameSize == nPacketLen)
4029 /* we don't compare the sizes since the packet can
4030 * contain several FLV packets, just make sure the
4031 * first frame is our keyframe (which we are going
4032 * to rewrite)
4034 if (memcmp
4035 (r->m_read.initialFrame, packetBody,
4036 r->m_read.nInitialFrameSize) == 0)
4038 RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
4039 r->m_read.flags |= RTMP_READ_GOTKF;
4040 /* ignore it! (what about audio data after it? it is
4041 * handled by ignoring all 0ms frames, see below)
4043 ret = RTMP_READ_IGNORE;
4044 break;
4048 /* hande FLV streams, even though the server resends the
4049 * keyframe as an extra video packet it is also included
4050 * in the first FLV stream chunk and we have to compare
4051 * it and filter it out !!
4053 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4055 /* basically we have to find the keyframe with the
4056 * correct TS being nResumeTS
4058 unsigned int pos = 0;
4059 uint32_t ts = 0;
4061 while (pos + 11 < nPacketLen)
4063 /* size without header (11) and prevTagSize (4) */
4064 uint32_t dataSize =
4065 AMF_DecodeInt24(packetBody + pos + 1);
4066 ts = AMF_DecodeInt24(packetBody + pos + 4);
4067 ts |= (packetBody[pos + 7] << 24);
4069 #ifdef _DEBUG
4070 RTMP_Log(RTMP_LOGDEBUG,
4071 "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
4072 packetBody[pos], dataSize, ts);
4073 #endif
4074 /* ok, is it a keyframe?:
4075 * well doesn't work for audio!
4077 if (packetBody[pos /*6928, test 0 */ ] ==
4078 r->m_read.initialFrameType
4079 /* && (packetBody[11]&0xf0) == 0x10 */ )
4081 if (ts == r->m_read.nResumeTS)
4083 RTMP_Log(RTMP_LOGDEBUG,
4084 "Found keyframe with resume-keyframe timestamp!");
4085 if (r->m_read.nInitialFrameSize != dataSize
4086 || memcmp(r->m_read.initialFrame,
4087 packetBody + pos + 11,
4088 r->m_read.
4089 nInitialFrameSize) != 0)
4091 RTMP_Log(RTMP_LOGERROR,
4092 "FLV Stream: Keyframe doesn't match!");
4093 ret = RTMP_READ_ERROR;
4094 break;
4096 r->m_read.flags |= RTMP_READ_GOTFLVK;
4098 /* skip this packet?
4099 * check whether skippable:
4101 if (pos + 11 + dataSize + 4 > nPacketLen)
4103 RTMP_Log(RTMP_LOGWARNING,
4104 "Non skipable packet since it doesn't end with chunk, stream corrupt!");
4105 ret = RTMP_READ_ERROR;
4106 break;
4108 packetBody += (pos + 11 + dataSize + 4);
4109 nPacketLen -= (pos + 11 + dataSize + 4);
4111 goto stopKeyframeSearch;
4114 else if (r->m_read.nResumeTS < ts)
4116 /* the timestamp ts will only increase with
4117 * further packets, wait for seek
4119 goto stopKeyframeSearch;
4122 pos += (11 + dataSize + 4);
4124 if (ts < r->m_read.nResumeTS)
4126 RTMP_Log(RTMP_LOGERROR,
4127 "First packet does not contain keyframe, all "
4128 "timestamps are smaller than the keyframe "
4129 "timestamp; probably the resume seek failed?");
4131 stopKeyframeSearch:
4133 if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
4135 RTMP_Log(RTMP_LOGERROR,
4136 "Couldn't find the seeked keyframe in this chunk!");
4137 ret = RTMP_READ_IGNORE;
4138 break;
4144 if (packet.m_nTimeStamp > 0
4145 && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
4147 /* another problem is that the server can actually change from
4148 * 09/08 video/audio packets to an FLV stream or vice versa and
4149 * our keyframe check will prevent us from going along with the
4150 * new stream if we resumed.
4152 * in this case set the 'found keyframe' variables to true.
4153 * We assume that if we found one keyframe somewhere and were
4154 * already beyond TS > 0 we have written data to the output
4155 * which means we can accept all forthcoming data including the
4156 * change between 08/09 <-> FLV packets
4158 r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
4161 /* skip till we find our keyframe
4162 * (seeking might put us somewhere before it)
4164 if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
4165 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4167 RTMP_Log(RTMP_LOGWARNING,
4168 "Stream does not start with requested frame, ignoring data... ");
4169 r->m_read.nIgnoredFrameCounter++;
4170 if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
4171 ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
4172 else
4173 ret = RTMP_READ_IGNORE;
4174 break;
4176 /* ok, do the same for FLV streams */
4177 if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
4178 packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4180 RTMP_Log(RTMP_LOGWARNING,
4181 "Stream does not start with requested FLV frame, ignoring data... ");
4182 r->m_read.nIgnoredFlvFrameCounter++;
4183 if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
4184 ret = RTMP_READ_ERROR;
4185 else
4186 ret = RTMP_READ_IGNORE;
4187 break;
4190 /* we have to ignore the 0ms frames since these are the first
4191 * keyframes; we've got these so don't mess around with multiple
4192 * copies sent by the server to us! (if the keyframe is found at a
4193 * later position there is only one copy and it will be ignored by
4194 * the preceding if clause)
4196 if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
4197 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4199 /* exclude type RTMP_PACKET_TYPE_FLASH_VIDEO since it can
4200 * contain several FLV packets
4202 if (packet.m_nTimeStamp == 0)
4204 ret = RTMP_READ_IGNORE;
4205 break;
4207 else
4209 /* stop ignoring packets */
4210 r->m_read.flags |= RTMP_READ_NO_IGNORE;
4215 /* calculate packet size and allocate slop buffer if necessary */
4216 size = nPacketLen +
4217 ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4218 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4219 || packet.m_packetType == RTMP_PACKET_TYPE_INFO) ? 11 : 0) +
4220 (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO ? 4 : 0);
4222 if (size + 4 > buflen)
4224 /* the extra 4 is for the case of an FLV stream without a last
4225 * prevTagSize (we need extra 4 bytes to append it) */
4226 r->m_read.buf = malloc(size + 4);
4227 if (r->m_read.buf == 0)
4229 RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
4230 ret = RTMP_READ_ERROR; /* fatal error */
4231 break;
4233 recopy = TRUE;
4234 ptr = r->m_read.buf;
4236 else
4238 ptr = buf;
4240 pend = ptr + size + 4;
4242 /* use to return timestamp of last processed packet */
4244 /* audio (0x08), video (0x09) or metadata (0x12) packets :
4245 * construct 11 byte header then add rtmp packet's data */
4246 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4247 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4248 || packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4250 nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
4251 prevTagSize = 11 + nPacketLen;
4253 *ptr = packet.m_packetType;
4254 ptr++;
4255 ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
4257 #if 0
4258 if(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) {
4260 /* H264 fix: */
4261 if((packetBody[0] & 0x0f) == 7) { /* CodecId = H264 */
4262 uint8_t packetType = *(packetBody+1);
4264 uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
4265 int32_t cts = (ts+0xff800000)^0xff800000;
4266 RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
4268 nTimeStamp -= cts;
4269 /* get rid of the composition time */
4270 CRTMP::EncodeInt24(packetBody+2, 0);
4272 RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
4274 #endif
4276 ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
4277 *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
4278 ptr++;
4280 /* stream id */
4281 ptr = AMF_EncodeInt24(ptr, pend, 0);
4284 memcpy(ptr, packetBody, nPacketLen);
4285 len = nPacketLen;
4287 /* correct tagSize and obtain timestamp if we have an FLV stream */
4288 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4290 unsigned int pos = 0;
4291 int delta;
4293 /* grab first timestamp and see if it needs fixing */
4294 nTimeStamp = AMF_DecodeInt24(packetBody + 4);
4295 nTimeStamp |= (packetBody[7] << 24);
4296 delta = packet.m_nTimeStamp - nTimeStamp + r->m_read.nResumeTS;
4298 while (pos + 11 < nPacketLen)
4300 /* size without header (11) and without prevTagSize (4) */
4301 uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
4302 nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
4303 nTimeStamp |= (packetBody[pos + 7] << 24);
4305 if (delta)
4307 nTimeStamp += delta;
4308 AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
4309 ptr[pos+7] = nTimeStamp>>24;
4312 /* set data type */
4313 r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
4314 (*(packetBody + pos) == 0x09));
4316 if (pos + 11 + dataSize + 4 > nPacketLen)
4318 if (pos + 11 + dataSize > nPacketLen)
4320 RTMP_Log(RTMP_LOGERROR,
4321 "Wrong data size (%u), stream corrupted, aborting!",
4322 dataSize);
4323 ret = RTMP_READ_ERROR;
4324 break;
4326 RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
4328 /* we have to append a last tagSize! */
4329 prevTagSize = dataSize + 11;
4330 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4331 prevTagSize);
4332 size += 4;
4333 len += 4;
4335 else
4337 prevTagSize =
4338 AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
4340 #ifdef _DEBUG
4341 RTMP_Log(RTMP_LOGDEBUG,
4342 "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
4343 (unsigned char)packetBody[pos], dataSize, prevTagSize,
4344 nTimeStamp);
4345 #endif
4347 if (prevTagSize != (dataSize + 11))
4349 #ifdef _DEBUG
4350 RTMP_Log(RTMP_LOGWARNING,
4351 "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
4352 dataSize + 11);
4353 #endif
4355 prevTagSize = dataSize + 11;
4356 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4357 prevTagSize);
4361 pos += prevTagSize + 4; /*(11+dataSize+4); */
4364 ptr += len;
4366 if (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4368 /* FLV tag packets contain their own prevTagSize */
4369 AMF_EncodeInt32(ptr, pend, prevTagSize);
4372 /* In non-live this nTimeStamp can contain an absolute TS.
4373 * Update ext timestamp with this absolute offset in non-live mode
4374 * otherwise report the relative one
4376 /* 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); */
4377 r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
4379 ret = size;
4380 break;
4383 if (rtnGetNextMediaPacket)
4384 RTMPPacket_Free(&packet);
4386 if (recopy)
4388 len = ret > buflen ? buflen : ret;
4389 memcpy(buf, r->m_read.buf, len);
4390 r->m_read.bufpos = r->m_read.buf + len;
4391 r->m_read.buflen = ret - len;
4393 return ret;
4396 static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
4397 0x00, /* 0x04 == audio, 0x01 == video */
4398 0x00, 0x00, 0x00, 0x09,
4399 0x00, 0x00, 0x00, 0x00
4402 #define HEADERBUF (128*1024)
4404 RTMP_Read(RTMP *r, char *buf, int size)
4406 int nRead = 0, total = 0;
4408 /* can't continue */
4409 fail:
4410 switch (r->m_read.status) {
4411 case RTMP_READ_EOF:
4412 case RTMP_READ_COMPLETE:
4413 return 0;
4414 case RTMP_READ_ERROR: /* corrupted stream, resume failed */
4415 SetSockError(EINVAL);
4416 return -1;
4417 default:
4418 break;
4421 /* first time thru */
4422 if (!(r->m_read.flags & RTMP_READ_HEADER))
4424 if (!(r->m_read.flags & RTMP_READ_RESUME))
4426 char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
4427 int cnt = 0;
4428 r->m_read.buf = mybuf;
4429 r->m_read.buflen = HEADERBUF;
4431 memcpy(mybuf, flvHeader, sizeof(flvHeader));
4432 r->m_read.buf += sizeof(flvHeader);
4433 r->m_read.buflen -= sizeof(flvHeader);
4435 while (r->m_read.timestamp == 0)
4437 nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
4438 if (nRead < 0)
4440 free(mybuf);
4441 r->m_read.buf = NULL;
4442 r->m_read.buflen = 0;
4443 r->m_read.status = nRead;
4444 goto fail;
4446 /* buffer overflow, fix buffer and give up */
4447 if (r->m_read.buf < mybuf || r->m_read.buf > end) {
4448 mybuf = realloc(mybuf, cnt + nRead);
4449 memcpy(mybuf+cnt, r->m_read.buf, nRead);
4450 r->m_read.buf = mybuf+cnt+nRead;
4451 break;
4453 cnt += nRead;
4454 r->m_read.buf += nRead;
4455 r->m_read.buflen -= nRead;
4456 if (r->m_read.dataType == 5)
4457 break;
4459 mybuf[4] = r->m_read.dataType;
4460 r->m_read.buflen = r->m_read.buf - mybuf;
4461 r->m_read.buf = mybuf;
4462 r->m_read.bufpos = mybuf;
4464 r->m_read.flags |= RTMP_READ_HEADER;
4467 if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
4469 /* drop whatever's here */
4470 free(r->m_read.buf);
4471 r->m_read.buf = NULL;
4472 r->m_read.bufpos = NULL;
4473 r->m_read.buflen = 0;
4476 /* If there's leftover data buffered, use it up */
4477 if (r->m_read.buf)
4479 nRead = r->m_read.buflen;
4480 if (nRead > size)
4481 nRead = size;
4482 memcpy(buf, r->m_read.bufpos, nRead);
4483 r->m_read.buflen -= nRead;
4484 if (!r->m_read.buflen)
4486 free(r->m_read.buf);
4487 r->m_read.buf = NULL;
4488 r->m_read.bufpos = NULL;
4490 else
4492 r->m_read.bufpos += nRead;
4494 buf += nRead;
4495 total += nRead;
4496 size -= nRead;
4499 while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
4501 if (!nRead) continue;
4502 buf += nRead;
4503 total += nRead;
4504 size -= nRead;
4505 break;
4507 if (nRead < 0)
4508 r->m_read.status = nRead;
4510 if (size < 0)
4511 total += size;
4512 return total;
4515 static const AVal av_setDataFrame = AVC("@setDataFrame");
4518 RTMP_Write(RTMP *r, const char *buf, int size)
4520 RTMPPacket *pkt = &r->m_write;
4521 char *pend, *enc;
4522 int s2 = size, ret, num;
4524 pkt->m_nChannel = 0x04; /* source channel */
4525 pkt->m_nInfoField2 = r->m_stream_id;
4527 while (s2)
4529 if (!pkt->m_nBytesRead)
4531 if (size < 11) {
4532 /* FLV pkt too small */
4533 return 0;
4536 if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
4538 buf += 13;
4539 s2 -= 13;
4542 pkt->m_packetType = *buf++;
4543 pkt->m_nBodySize = AMF_DecodeInt24(buf);
4544 buf += 3;
4545 pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
4546 buf += 3;
4547 pkt->m_nTimeStamp |= *buf++ << 24;
4548 buf += 3;
4549 s2 -= 11;
4551 if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
4552 || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
4553 !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4555 pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
4556 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4557 pkt->m_nBodySize += 16;
4559 else
4561 pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
4564 if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
4566 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
4567 return FALSE;
4569 enc = pkt->m_body;
4570 pend = enc + pkt->m_nBodySize;
4571 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
4573 enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
4574 pkt->m_nBytesRead = enc - pkt->m_body;
4577 else
4579 enc = pkt->m_body + pkt->m_nBytesRead;
4581 num = pkt->m_nBodySize - pkt->m_nBytesRead;
4582 if (num > s2)
4583 num = s2;
4584 memcpy(enc, buf, num);
4585 pkt->m_nBytesRead += num;
4586 s2 -= num;
4587 buf += num;
4588 if (pkt->m_nBytesRead == pkt->m_nBodySize)
4590 ret = RTMP_SendPacket(r, pkt, FALSE);
4591 RTMPPacket_Free(pkt);
4592 pkt->m_nBytesRead = 0;
4593 if (!ret)
4594 return -1;
4595 buf += 4;
4596 s2 -= 4;
4597 if (s2 < 0)
4598 break;
4601 return size+s2;