Simplify initializing the TLS server context
[rtmpdump.git] / librtmp / rtmp.c
blobd72f1051a8427a66b756640fb8d74cb3c39e902f
1 /*
2 * Copyright (C) 2005-2008 Team XBMC
3 * http://www.xbmc.org
4 * Copyright (C) 2008-2009 Andrej Stepanchuk
5 * Copyright (C) 2009-2010 Howard Chu
7 * This file is part of librtmp.
9 * librtmp is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU Lesser General Public License as
11 * published by the Free Software Foundation; either version 2.1,
12 * or (at your option) any later version.
14 * librtmp is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU Lesser General Public License
20 * along with librtmp see the file COPYING. If not, write to
21 * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
22 * Boston, MA 02110-1301, USA.
23 * http://www.gnu.org/copyleft/lgpl.html
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <assert.h>
30 #include <time.h>
32 #include "rtmp_sys.h"
33 #include "log.h"
35 #ifdef CRYPTO
36 #ifdef USE_POLARSSL
37 #include <polarssl/version.h>
38 #include <polarssl/havege.h>
39 #include <polarssl/md5.h>
40 #include <polarssl/base64.h>
41 #define MD5_DIGEST_LENGTH 16
43 static const char *my_dhm_P =
44 "E4004C1F94182000103D883A448B3F80" \
45 "2CE4B44A83301270002C20D0321CFD00" \
46 "11CCEF784C26A400F43DFB901BCA7538" \
47 "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
48 "F6AC8E1DA6BCC3B4E1F96B0564965300" \
49 "FFA1D0B601EB2800F489AA512C4B248C" \
50 "01F76949A60BB7F00A40B1EAB64BDD48" \
51 "E8A700D60B7F1200FA8E77B0A979DABF";
53 static const char *my_dhm_G = "4";
55 #elif defined(USE_GNUTLS)
56 #include <gnutls/gnutls.h>
57 #define MD5_DIGEST_LENGTH 16
58 #include <nettle/base64.h>
59 #include <nettle/md5.h>
60 #else /* USE_OPENSSL */
61 #include <openssl/ssl.h>
62 #include <openssl/rc4.h>
63 #include <openssl/md5.h>
64 #include <openssl/bio.h>
65 #include <openssl/buffer.h>
66 #endif
67 TLS_CTX RTMP_TLS_ctx;
68 #endif
70 #define RTMP_SIG_SIZE 1536
71 #define RTMP_LARGE_HEADER_SIZE 12
73 static const int packetSize[] = { 12, 8, 4, 1 };
75 int RTMP_ctrlC;
77 const char RTMPProtocolStrings[][7] = {
78 "RTMP",
79 "RTMPT",
80 "RTMPE",
81 "RTMPTE",
82 "RTMPS",
83 "RTMPTS",
84 "",
85 "",
86 "RTMFP"
89 const char RTMPProtocolStringsLower[][7] = {
90 "rtmp",
91 "rtmpt",
92 "rtmpe",
93 "rtmpte",
94 "rtmps",
95 "rtmpts",
96 "",
97 "",
98 "rtmfp"
101 static const char *RTMPT_cmds[] = {
102 "open",
103 "send",
104 "idle",
105 "close"
108 typedef enum {
109 RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
110 } RTMPTCmd;
112 static int DumpMetaData(AMFObject *obj);
113 static int HandShake(RTMP *r, int FP9HandShake);
114 static int SocksNegotiate(RTMP *r);
116 static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
117 static int SendCheckBW(RTMP *r);
118 static int SendCheckBWResult(RTMP *r, double txn);
119 static int SendDeleteStream(RTMP *r, double dStreamId);
120 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
121 static int SendPlay(RTMP *r);
122 static int SendBytesReceived(RTMP *r);
123 static int SendUsherToken(RTMP *r, AVal *usherToken);
125 #if 0 /* unused */
126 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
127 #endif
129 static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
130 static int HandleMetadata(RTMP *r, char *body, unsigned int len);
131 static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
132 static void HandleAudio(RTMP *r, const RTMPPacket *packet);
133 static void HandleVideo(RTMP *r, const RTMPPacket *packet);
134 static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
135 static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
136 static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
138 static int ReadN(RTMP *r, char *buffer, int n);
139 static int WriteN(RTMP *r, const char *buffer, int n);
141 static void DecodeTEA(AVal *key, AVal *text);
143 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
144 static int HTTP_read(RTMP *r, int fill);
146 #ifndef _WIN32
147 static int clk_tck;
148 #endif
150 #ifdef CRYPTO
151 #include "handshake.h"
152 #endif
154 uint32_t
155 RTMP_GetTime()
157 #ifdef _DEBUG
158 return 0;
159 #elif defined(_WIN32)
160 return timeGetTime();
161 #else
162 struct tms t;
163 if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
164 return times(&t) * 1000 / clk_tck;
165 #endif
168 void
169 RTMP_UserInterrupt()
171 RTMP_ctrlC = TRUE;
174 void
175 RTMPPacket_Reset(RTMPPacket *p)
177 p->m_headerType = 0;
178 p->m_packetType = 0;
179 p->m_nChannel = 0;
180 p->m_nTimeStamp = 0;
181 p->m_nInfoField2 = 0;
182 p->m_hasAbsTimestamp = FALSE;
183 p->m_nBodySize = 0;
184 p->m_nBytesRead = 0;
188 RTMPPacket_Alloc(RTMPPacket *p, int nSize)
190 char *ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
191 if (!ptr)
192 return FALSE;
193 p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
194 p->m_nBytesRead = 0;
195 return TRUE;
198 void
199 RTMPPacket_Free(RTMPPacket *p)
201 if (p->m_body)
203 free(p->m_body - RTMP_MAX_HEADER_SIZE);
204 p->m_body = NULL;
208 void
209 RTMPPacket_Dump(RTMPPacket *p)
211 RTMP_Log(RTMP_LOGDEBUG,
212 "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %u. body: 0x%02x",
213 p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
214 p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
218 RTMP_LibVersion()
220 return RTMP_LIB_VERSION;
223 void
224 RTMP_TLS_Init()
226 #ifdef CRYPTO
227 #ifdef USE_POLARSSL
228 /* Do this regardless of NO_SSL, we use havege for rtmpe too */
229 RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
230 havege_init(&RTMP_TLS_ctx->hs);
231 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
232 /* Technically we need to initialize libgcrypt ourselves if
233 * we're not going to call gnutls_global_init(). Ignoring this
234 * for now.
236 gnutls_global_init();
237 RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
238 gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
239 gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
240 gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
241 "ca.pem", GNUTLS_X509_FMT_PEM);
242 #elif !defined(NO_SSL) /* USE_OPENSSL */
243 /* libcrypto doesn't need anything special */
244 SSL_load_error_strings();
245 SSL_library_init();
246 OpenSSL_add_all_digests();
247 RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
248 SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
249 SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
250 #endif
251 #endif
254 void *
255 RTMP_TLS_AllocServerContext(const char* cert, const char* key)
257 void *ctx = NULL;
258 #ifdef CRYPTO
259 if (!RTMP_TLS_ctx)
260 RTMP_TLS_Init();
261 #ifdef USE_POLARSSL
262 tls_server_ctx *tc = ctx = calloc(1, sizeof(struct tls_server_ctx));
263 tc->dhm_P = my_dhm_P;
264 tc->dhm_G = my_dhm_G;
265 tc->hs = &RTMP_TLS_ctx->hs;
266 if (x509parse_crtfile(&tc->cert, cert)) {
267 free(tc);
268 return NULL;
270 if (x509parse_keyfile(&tc->key, key, NULL)) {
271 x509_free(&tc->cert);
272 free(tc);
273 return NULL;
275 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
276 gnutls_certificate_allocate_credentials((gnutls_certificate_credentials*) &ctx);
277 if (gnutls_certificate_set_x509_key_file(ctx, cert, key, GNUTLS_X509_FMT_PEM) != 0) {
278 gnutls_certificate_free_credentials(ctx);
279 return NULL;
281 #elif !defined(NO_SSL) /* USE_OPENSSL */
282 ctx = SSL_CTX_new(SSLv23_server_method());
283 if (!SSL_CTX_use_certificate_chain_file(ctx, cert)) {
284 SSL_CTX_free(ctx);
285 return NULL;
287 if (!SSL_CTX_use_PrivateKey_file(ctx, key, SSL_FILETYPE_PEM)) {
288 SSL_CTX_free(ctx);
289 return NULL;
291 #endif
292 #endif
293 return ctx;
296 void
297 RTMP_TLS_FreeServerContext(void *ctx)
299 #ifdef CRYPTO
300 #ifdef USE_POLARSSL
301 x509_free(&((tls_server_ctx*)ctx)->cert);
302 rsa_free(&((tls_server_ctx*)ctx)->key);
303 free(ctx);
304 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
305 gnutls_certificate_free_credentials(ctx);
306 #elif !defined(NO_SSL) /* USE_OPENSSL */
307 SSL_CTX_free(ctx);
308 #endif
309 #endif
312 RTMP *
313 RTMP_Alloc()
315 return calloc(1, sizeof(RTMP));
318 void
319 RTMP_Free(RTMP *r)
321 free(r);
324 void
325 RTMP_Init(RTMP *r)
327 #ifdef CRYPTO
328 if (!RTMP_TLS_ctx)
329 RTMP_TLS_Init();
330 #endif
332 memset(r, 0, sizeof(RTMP));
333 r->m_sb.sb_socket = -1;
334 r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
335 r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
336 r->m_nBufferMS = 30000;
337 r->m_nClientBW = 2500000;
338 r->m_nClientBW2 = 2;
339 r->m_nServerBW = 2500000;
340 r->m_fAudioCodecs = 3191.0;
341 r->m_fVideoCodecs = 252.0;
342 r->Link.timeout = 30;
343 r->Link.swfAge = 30;
346 void
347 RTMP_EnableWrite(RTMP *r)
349 r->Link.protocol |= RTMP_FEATURE_WRITE;
352 double
353 RTMP_GetDuration(RTMP *r)
355 return r->m_fDuration;
359 RTMP_IsConnected(RTMP *r)
361 return r->m_sb.sb_socket != -1;
365 RTMP_Socket(RTMP *r)
367 return r->m_sb.sb_socket;
371 RTMP_IsTimedout(RTMP *r)
373 return r->m_sb.sb_timedout;
376 void
377 RTMP_SetBufferMS(RTMP *r, int size)
379 r->m_nBufferMS = size;
382 void
383 RTMP_UpdateBufferMS(RTMP *r)
385 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
388 #undef OSS
389 #ifdef _WIN32
390 #define OSS "WIN"
391 #elif defined(__sun__)
392 #define OSS "SOL"
393 #elif defined(__APPLE__)
394 #define OSS "MAC"
395 #elif defined(__linux__)
396 #define OSS "LNX"
397 #else
398 #define OSS "GNU"
399 #endif
400 #define DEF_VERSTR OSS " 10,0,32,18"
401 static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
402 const AVal RTMP_DefaultFlashVer =
403 { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
405 static void
406 SocksSetup(RTMP *r, AVal *sockshost)
408 if (sockshost->av_len)
410 const char *socksport = strchr(sockshost->av_val, ':');
411 char *hostname = strdup(sockshost->av_val);
413 if (socksport)
414 hostname[socksport - sockshost->av_val] = '\0';
415 r->Link.sockshost.av_val = hostname;
416 r->Link.sockshost.av_len = strlen(hostname);
418 r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
419 RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
420 r->Link.socksport);
422 else
424 r->Link.sockshost.av_val = NULL;
425 r->Link.sockshost.av_len = 0;
426 r->Link.socksport = 0;
430 void
431 RTMP_SetupStream(RTMP *r,
432 int protocol,
433 AVal *host,
434 unsigned int port,
435 AVal *sockshost,
436 AVal *playpath,
437 AVal *tcUrl,
438 AVal *swfUrl,
439 AVal *pageUrl,
440 AVal *app,
441 AVal *auth,
442 AVal *swfSHA256Hash,
443 uint32_t swfSize,
444 AVal *flashVer,
445 AVal *subscribepath,
446 AVal *usherToken,
447 int dStart,
448 int dStop, int bLiveStream, long int timeout)
450 RTMP_Log(RTMP_LOGDEBUG, "Protocol : %s", RTMPProtocolStrings[protocol&7]);
451 RTMP_Log(RTMP_LOGDEBUG, "Hostname : %.*s", host->av_len, host->av_val);
452 RTMP_Log(RTMP_LOGDEBUG, "Port : %d", port);
453 RTMP_Log(RTMP_LOGDEBUG, "Playpath : %s", playpath->av_val);
455 if (tcUrl && tcUrl->av_val)
456 RTMP_Log(RTMP_LOGDEBUG, "tcUrl : %s", tcUrl->av_val);
457 if (swfUrl && swfUrl->av_val)
458 RTMP_Log(RTMP_LOGDEBUG, "swfUrl : %s", swfUrl->av_val);
459 if (pageUrl && pageUrl->av_val)
460 RTMP_Log(RTMP_LOGDEBUG, "pageUrl : %s", pageUrl->av_val);
461 if (app && app->av_val)
462 RTMP_Log(RTMP_LOGDEBUG, "app : %.*s", app->av_len, app->av_val);
463 if (auth && auth->av_val)
464 RTMP_Log(RTMP_LOGDEBUG, "auth : %s", auth->av_val);
465 if (subscribepath && subscribepath->av_val)
466 RTMP_Log(RTMP_LOGDEBUG, "subscribepath : %s", subscribepath->av_val);
467 if (usherToken && usherToken->av_val)
468 RTMP_Log(RTMP_LOGDEBUG, "NetStream.Authenticate.UsherToken : %s", usherToken->av_val);
469 if (flashVer && flashVer->av_val)
470 RTMP_Log(RTMP_LOGDEBUG, "flashVer : %s", flashVer->av_val);
471 if (dStart > 0)
472 RTMP_Log(RTMP_LOGDEBUG, "StartTime : %d msec", dStart);
473 if (dStop > 0)
474 RTMP_Log(RTMP_LOGDEBUG, "StopTime : %d msec", dStop);
476 RTMP_Log(RTMP_LOGDEBUG, "live : %s", bLiveStream ? "yes" : "no");
477 RTMP_Log(RTMP_LOGDEBUG, "timeout : %ld sec", timeout);
479 #ifdef CRYPTO
480 if (swfSHA256Hash != NULL && swfSize > 0)
482 memcpy(r->Link.SWFHash, swfSHA256Hash->av_val, sizeof(r->Link.SWFHash));
483 r->Link.SWFSize = swfSize;
484 RTMP_Log(RTMP_LOGDEBUG, "SWFSHA256:");
485 RTMP_LogHex(RTMP_LOGDEBUG, r->Link.SWFHash, sizeof(r->Link.SWFHash));
486 RTMP_Log(RTMP_LOGDEBUG, "SWFSize : %u", r->Link.SWFSize);
488 else
490 r->Link.SWFSize = 0;
492 #endif
494 SocksSetup(r, sockshost);
496 if (tcUrl && tcUrl->av_len)
497 r->Link.tcUrl = *tcUrl;
498 if (swfUrl && swfUrl->av_len)
499 r->Link.swfUrl = *swfUrl;
500 if (pageUrl && pageUrl->av_len)
501 r->Link.pageUrl = *pageUrl;
502 if (app && app->av_len)
503 r->Link.app = *app;
504 if (auth && auth->av_len)
506 r->Link.auth = *auth;
507 r->Link.lFlags |= RTMP_LF_AUTH;
509 if (flashVer && flashVer->av_len)
510 r->Link.flashVer = *flashVer;
511 else
512 r->Link.flashVer = RTMP_DefaultFlashVer;
513 if (subscribepath && subscribepath->av_len)
514 r->Link.subscribepath = *subscribepath;
515 if (usherToken && usherToken->av_len)
516 r->Link.usherToken = *usherToken;
517 r->Link.seekTime = dStart;
518 r->Link.stopTime = dStop;
519 if (bLiveStream)
520 r->Link.lFlags |= RTMP_LF_LIVE;
521 r->Link.timeout = timeout;
523 r->Link.protocol = protocol;
524 r->Link.hostname = *host;
525 r->Link.port = port;
526 r->Link.playpath = *playpath;
528 if (r->Link.port == 0)
530 if (protocol & RTMP_FEATURE_SSL)
531 r->Link.port = 443;
532 else if (protocol & RTMP_FEATURE_HTTP)
533 r->Link.port = 80;
534 else
535 r->Link.port = 1935;
539 enum { OPT_STR=0, OPT_INT, OPT_BOOL, OPT_CONN };
540 static const char *optinfo[] = {
541 "string", "integer", "boolean", "AMF" };
543 #define OFF(x) offsetof(struct RTMP,x)
545 static struct urlopt {
546 AVal name;
547 off_t off;
548 int otype;
549 int omisc;
550 char *use;
551 } options[] = {
552 { AVC("socks"), OFF(Link.sockshost), OPT_STR, 0,
553 "Use the specified SOCKS proxy" },
554 { AVC("app"), OFF(Link.app), OPT_STR, 0,
555 "Name of target app on server" },
556 { AVC("tcUrl"), OFF(Link.tcUrl), OPT_STR, 0,
557 "URL to played stream" },
558 { AVC("pageUrl"), OFF(Link.pageUrl), OPT_STR, 0,
559 "URL of played media's web page" },
560 { AVC("swfUrl"), OFF(Link.swfUrl), OPT_STR, 0,
561 "URL to player SWF file" },
562 { AVC("flashver"), OFF(Link.flashVer), OPT_STR, 0,
563 "Flash version string (default " DEF_VERSTR ")" },
564 { AVC("conn"), OFF(Link.extras), OPT_CONN, 0,
565 "Append arbitrary AMF data to Connect message" },
566 { AVC("playpath"), OFF(Link.playpath), OPT_STR, 0,
567 "Path to target media on server" },
568 { AVC("playlist"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_PLST,
569 "Set playlist before play command" },
570 { AVC("live"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_LIVE,
571 "Stream is live, no seeking possible" },
572 { AVC("subscribe"), OFF(Link.subscribepath), OPT_STR, 0,
573 "Stream to subscribe to" },
574 { AVC("jtv"), OFF(Link.usherToken), OPT_STR, 0,
575 "Justin.tv authentication token" },
576 { AVC("token"), OFF(Link.token), OPT_STR, 0,
577 "Key for SecureToken response" },
578 { AVC("swfVfy"), OFF(Link.lFlags), OPT_BOOL, RTMP_LF_SWFV,
579 "Perform SWF Verification" },
580 { AVC("swfAge"), OFF(Link.swfAge), OPT_INT, 0,
581 "Number of days to use cached SWF hash" },
582 { AVC("start"), OFF(Link.seekTime), OPT_INT, 0,
583 "Stream start position in milliseconds" },
584 { AVC("stop"), OFF(Link.stopTime), OPT_INT, 0,
585 "Stream stop position in milliseconds" },
586 { AVC("buffer"), OFF(m_nBufferMS), OPT_INT, 0,
587 "Buffer time in milliseconds" },
588 { AVC("timeout"), OFF(Link.timeout), OPT_INT, 0,
589 "Session timeout in seconds" },
590 { AVC("pubUser"), OFF(Link.pubUser), OPT_STR, 0,
591 "Publisher username" },
592 { AVC("pubPasswd"), OFF(Link.pubPasswd), OPT_STR, 0,
593 "Publisher password" },
594 { {NULL,0}, 0, 0}
597 static const AVal truth[] = {
598 AVC("1"),
599 AVC("on"),
600 AVC("yes"),
601 AVC("true"),
602 {0,0}
605 static void RTMP_OptUsage()
607 int i;
609 RTMP_Log(RTMP_LOGERROR, "Valid RTMP options are:\n");
610 for (i=0; options[i].name.av_len; i++) {
611 RTMP_Log(RTMP_LOGERROR, "%10s %-7s %s\n", options[i].name.av_val,
612 optinfo[options[i].otype], options[i].use);
616 static int
617 parseAMF(AMFObject *obj, AVal *av, int *depth)
619 AMFObjectProperty prop = {{0,0}};
620 int i;
621 char *p, *arg = av->av_val;
623 if (arg[1] == ':')
625 p = (char *)arg+2;
626 switch(arg[0])
628 case 'B':
629 prop.p_type = AMF_BOOLEAN;
630 prop.p_vu.p_number = atoi(p);
631 break;
632 case 'S':
633 prop.p_type = AMF_STRING;
634 prop.p_vu.p_aval.av_val = p;
635 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
636 break;
637 case 'N':
638 prop.p_type = AMF_NUMBER;
639 prop.p_vu.p_number = strtod(p, NULL);
640 break;
641 case 'Z':
642 prop.p_type = AMF_NULL;
643 break;
644 case 'O':
645 i = atoi(p);
646 if (i)
648 prop.p_type = AMF_OBJECT;
650 else
652 (*depth)--;
653 return 0;
655 break;
656 default:
657 return -1;
660 else if (arg[2] == ':' && arg[0] == 'N')
662 p = strchr(arg+3, ':');
663 if (!p || !*depth)
664 return -1;
665 prop.p_name.av_val = (char *)arg+3;
666 prop.p_name.av_len = p - (arg+3);
668 p++;
669 switch(arg[1])
671 case 'B':
672 prop.p_type = AMF_BOOLEAN;
673 prop.p_vu.p_number = atoi(p);
674 break;
675 case 'S':
676 prop.p_type = AMF_STRING;
677 prop.p_vu.p_aval.av_val = p;
678 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
679 break;
680 case 'N':
681 prop.p_type = AMF_NUMBER;
682 prop.p_vu.p_number = strtod(p, NULL);
683 break;
684 case 'O':
685 prop.p_type = AMF_OBJECT;
686 break;
687 default:
688 return -1;
691 else
692 return -1;
694 if (*depth)
696 AMFObject *o2;
697 for (i=0; i<*depth; i++)
699 o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
700 obj = o2;
703 AMF_AddProp(obj, &prop);
704 if (prop.p_type == AMF_OBJECT)
705 (*depth)++;
706 return 0;
709 int RTMP_SetOpt(RTMP *r, const AVal *opt, AVal *arg)
711 int i;
712 void *v;
714 for (i=0; options[i].name.av_len; i++) {
715 if (opt->av_len != options[i].name.av_len) continue;
716 if (strcasecmp(opt->av_val, options[i].name.av_val)) continue;
717 v = (char *)r + options[i].off;
718 switch(options[i].otype) {
719 case OPT_STR: {
720 AVal *aptr = v;
721 *aptr = *arg; }
722 break;
723 case OPT_INT: {
724 long l = strtol(arg->av_val, NULL, 0);
725 *(int *)v = l; }
726 break;
727 case OPT_BOOL: {
728 int j, fl;
729 fl = *(int *)v;
730 for (j=0; truth[j].av_len; j++) {
731 if (arg->av_len != truth[j].av_len) continue;
732 if (strcasecmp(arg->av_val, truth[j].av_val)) continue;
733 fl |= options[i].omisc; break; }
734 *(int *)v = fl;
736 break;
737 case OPT_CONN:
738 if (parseAMF(&r->Link.extras, arg, &r->Link.edepth))
739 return FALSE;
740 break;
742 break;
744 if (!options[i].name.av_len) {
745 RTMP_Log(RTMP_LOGERROR, "Unknown option %s", opt->av_val);
746 RTMP_OptUsage();
747 return FALSE;
750 return TRUE;
753 int RTMP_SetupURL(RTMP *r, char *url)
755 AVal opt, arg;
756 char *p1, *p2, *ptr = strchr(url, ' ');
757 int ret, len;
758 unsigned int port = 0;
760 if (ptr)
761 *ptr = '\0';
763 len = strlen(url);
764 ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
765 &port, &r->Link.playpath0, &r->Link.app);
766 if (!ret)
767 return ret;
768 r->Link.port = port;
769 r->Link.playpath = r->Link.playpath0;
771 while (ptr) {
772 *ptr++ = '\0';
773 p1 = ptr;
774 p2 = strchr(p1, '=');
775 if (!p2)
776 break;
777 opt.av_val = p1;
778 opt.av_len = p2 - p1;
779 *p2++ = '\0';
780 arg.av_val = p2;
781 ptr = strchr(p2, ' ');
782 if (ptr) {
783 *ptr = '\0';
784 arg.av_len = ptr - p2;
785 /* skip repeated spaces */
786 while(ptr[1] == ' ')
787 *ptr++ = '\0';
788 } else {
789 arg.av_len = strlen(p2);
792 /* unescape */
793 port = arg.av_len;
794 for (p1=p2; port >0;) {
795 if (*p1 == '\\') {
796 unsigned int c;
797 if (port < 3)
798 return FALSE;
799 sscanf(p1+1, "%02x", &c);
800 *p2++ = c;
801 port -= 3;
802 p1 += 3;
803 } else {
804 *p2++ = *p1++;
805 port--;
808 arg.av_len = p2 - arg.av_val;
810 ret = RTMP_SetOpt(r, &opt, &arg);
811 if (!ret)
812 return ret;
815 if (!r->Link.tcUrl.av_len)
817 r->Link.tcUrl.av_val = url;
818 if (r->Link.app.av_len)
820 if (r->Link.app.av_val < url + len)
822 /* if app is part of original url, just use it */
823 r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);
825 else
827 len = r->Link.hostname.av_len + r->Link.app.av_len +
828 sizeof("rtmpte://:65535/");
829 r->Link.tcUrl.av_val = malloc(len);
830 r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
831 "%s://%.*s:%d/%.*s",
832 RTMPProtocolStringsLower[r->Link.protocol],
833 r->Link.hostname.av_len, r->Link.hostname.av_val,
834 r->Link.port,
835 r->Link.app.av_len, r->Link.app.av_val);
836 r->Link.lFlags |= RTMP_LF_FTCU;
839 else
841 r->Link.tcUrl.av_len = strlen(url);
845 #ifdef CRYPTO
846 if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
847 RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
848 (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
849 #endif
851 SocksSetup(r, &r->Link.sockshost);
853 if (r->Link.port == 0)
855 if (r->Link.protocol & RTMP_FEATURE_SSL)
856 r->Link.port = 443;
857 else if (r->Link.protocol & RTMP_FEATURE_HTTP)
858 r->Link.port = 80;
859 else
860 r->Link.port = 1935;
862 return TRUE;
865 static int
866 add_addr_info(struct sockaddr_in *service, AVal *host, int port)
868 char *hostname;
869 int ret = TRUE;
870 if (host->av_val[host->av_len])
872 hostname = malloc(host->av_len+1);
873 memcpy(hostname, host->av_val, host->av_len);
874 hostname[host->av_len] = '\0';
876 else
878 hostname = host->av_val;
881 service->sin_addr.s_addr = inet_addr(hostname);
882 if (service->sin_addr.s_addr == INADDR_NONE)
884 struct hostent *host = gethostbyname(hostname);
885 if (host == NULL || host->h_addr == NULL)
887 RTMP_Log(RTMP_LOGERROR, "Problem accessing the DNS. (addr: %s)", hostname);
888 ret = FALSE;
889 goto finish;
891 service->sin_addr = *(struct in_addr *)host->h_addr;
894 service->sin_port = htons(port);
895 finish:
896 if (hostname != host->av_val)
897 free(hostname);
898 return ret;
902 RTMP_Connect0(RTMP *r, struct sockaddr * service)
904 int on = 1;
905 r->m_sb.sb_timedout = FALSE;
906 r->m_pausing = 0;
907 r->m_fDuration = 0.0;
909 r->m_sb.sb_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
910 if (r->m_sb.sb_socket != -1)
912 if (connect(r->m_sb.sb_socket, service, sizeof(struct sockaddr)) < 0)
914 int err = GetSockError();
915 RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket. %d (%s)",
916 __FUNCTION__, err, strerror(err));
917 RTMP_Close(r);
918 return FALSE;
921 if (r->Link.socksport)
923 RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
924 if (!SocksNegotiate(r))
926 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
927 RTMP_Close(r);
928 return FALSE;
932 else
934 RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
935 GetSockError());
936 return FALSE;
939 /* set timeout */
941 SET_RCVTIMEO(tv, r->Link.timeout);
942 if (setsockopt
943 (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
945 RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
946 __FUNCTION__, r->Link.timeout);
950 setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
952 return TRUE;
956 RTMP_TLS_Accept(RTMP *r, void *ctx)
958 #if defined(CRYPTO) && !defined(NO_SSL)
959 TLS_server(ctx, r->m_sb.sb_ssl);
960 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
961 if (TLS_accept(r->m_sb.sb_ssl) < 0)
963 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
964 return FALSE;
966 return TRUE;
967 #else
968 return FALSE;
969 #endif
973 RTMP_Connect1(RTMP *r, RTMPPacket *cp)
975 if (r->Link.protocol & RTMP_FEATURE_SSL)
977 #if defined(CRYPTO) && !defined(NO_SSL)
978 TLS_client(RTMP_TLS_ctx, r->m_sb.sb_ssl);
979 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
980 if (TLS_connect(r->m_sb.sb_ssl) < 0)
982 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed", __FUNCTION__);
983 RTMP_Close(r);
984 return FALSE;
986 #else
987 RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
988 RTMP_Close(r);
989 return FALSE;
991 #endif
993 if (r->Link.protocol & RTMP_FEATURE_HTTP)
995 r->m_msgCounter = 1;
996 r->m_clientID.av_val = NULL;
997 r->m_clientID.av_len = 0;
998 HTTP_Post(r, RTMPT_OPEN, "", 1);
999 if (HTTP_read(r, 1) != 0)
1001 r->m_msgCounter = 0;
1002 RTMP_Log(RTMP_LOGDEBUG, "%s, Could not connect for handshake", __FUNCTION__);
1003 RTMP_Close(r);
1004 return 0;
1006 r->m_msgCounter = 0;
1008 RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
1009 if (!HandShake(r, TRUE))
1011 RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
1012 RTMP_Close(r);
1013 return FALSE;
1015 RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
1017 if (!SendConnectPacket(r, cp))
1019 RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
1020 RTMP_Close(r);
1021 return FALSE;
1023 return TRUE;
1027 RTMP_Connect(RTMP *r, RTMPPacket *cp)
1029 struct sockaddr_in service;
1030 if (!r->Link.hostname.av_len)
1031 return FALSE;
1033 memset(&service, 0, sizeof(struct sockaddr_in));
1034 service.sin_family = AF_INET;
1036 if (r->Link.socksport)
1038 /* Connect via SOCKS */
1039 if (!add_addr_info(&service, &r->Link.sockshost, r->Link.socksport))
1040 return FALSE;
1042 else
1044 /* Connect directly */
1045 if (!add_addr_info(&service, &r->Link.hostname, r->Link.port))
1046 return FALSE;
1049 if (!RTMP_Connect0(r, (struct sockaddr *)&service))
1050 return FALSE;
1052 r->m_bSendCounter = TRUE;
1054 return RTMP_Connect1(r, cp);
1057 static int
1058 SocksNegotiate(RTMP *r)
1060 unsigned long addr;
1061 struct sockaddr_in service;
1062 memset(&service, 0, sizeof(struct sockaddr_in));
1064 add_addr_info(&service, &r->Link.hostname, r->Link.port);
1065 addr = htonl(service.sin_addr.s_addr);
1068 char packet[] = {
1069 4, 1, /* SOCKS 4, connect */
1070 (r->Link.port >> 8) & 0xFF,
1071 (r->Link.port) & 0xFF,
1072 (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
1073 (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
1075 }; /* NULL terminate */
1077 WriteN(r, packet, sizeof packet);
1079 if (ReadN(r, packet, 8) != 8)
1080 return FALSE;
1082 if (packet[0] == 0 && packet[1] == 90)
1084 return TRUE;
1086 else
1088 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
1089 return FALSE;
1095 RTMP_ConnectStream(RTMP *r, int seekTime)
1097 RTMPPacket packet = { 0 };
1099 /* seekTime was already set by SetupStream / SetupURL.
1100 * This is only needed by ReconnectStream.
1102 if (seekTime > 0)
1103 r->Link.seekTime = seekTime;
1105 r->m_mediaChannel = 0;
1107 while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
1109 if (RTMPPacket_IsReady(&packet))
1111 if (!packet.m_nBodySize)
1112 continue;
1113 if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
1114 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
1115 (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
1117 RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
1118 RTMPPacket_Free(&packet);
1119 continue;
1122 RTMP_ClientPacket(r, &packet);
1123 RTMPPacket_Free(&packet);
1127 return r->m_bPlaying;
1131 RTMP_ReconnectStream(RTMP *r, int seekTime)
1133 RTMP_DeleteStream(r);
1135 RTMP_SendCreateStream(r);
1137 return RTMP_ConnectStream(r, seekTime);
1141 RTMP_ToggleStream(RTMP *r)
1143 int res;
1145 if (!r->m_pausing)
1147 if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
1148 r->m_read.status = 0;
1150 res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
1151 if (!res)
1152 return res;
1154 r->m_pausing = 1;
1155 sleep(1);
1157 res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
1158 r->m_pausing = 3;
1159 return res;
1162 void
1163 RTMP_DeleteStream(RTMP *r)
1165 if (r->m_stream_id < 0)
1166 return;
1168 r->m_bPlaying = FALSE;
1170 SendDeleteStream(r, r->m_stream_id);
1171 r->m_stream_id = -1;
1175 RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
1177 int bHasMediaPacket = 0;
1179 while (!bHasMediaPacket && RTMP_IsConnected(r)
1180 && RTMP_ReadPacket(r, packet))
1182 if (!RTMPPacket_IsReady(packet))
1184 continue;
1187 bHasMediaPacket = RTMP_ClientPacket(r, packet);
1189 if (!bHasMediaPacket)
1191 RTMPPacket_Free(packet);
1193 else if (r->m_pausing == 3)
1195 if (packet->m_nTimeStamp <= r->m_mediaStamp)
1197 bHasMediaPacket = 0;
1198 #ifdef _DEBUG
1199 RTMP_Log(RTMP_LOGDEBUG,
1200 "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
1201 packet->m_packetType, packet->m_nBodySize,
1202 packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
1203 r->m_mediaStamp);
1204 #endif
1205 RTMPPacket_Free(packet);
1206 continue;
1208 r->m_pausing = 0;
1212 if (bHasMediaPacket)
1213 r->m_bPlaying = TRUE;
1214 else if (r->m_sb.sb_timedout && !r->m_pausing)
1215 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
1216 r->m_channelTimestamp[r->m_mediaChannel] : 0;
1218 return bHasMediaPacket;
1222 RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
1224 int bHasMediaPacket = 0;
1225 switch (packet->m_packetType)
1227 case RTMP_PACKET_TYPE_CHUNK_SIZE:
1228 /* chunk size */
1229 HandleChangeChunkSize(r, packet);
1230 break;
1232 case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
1233 /* bytes read report */
1234 RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
1235 break;
1237 case RTMP_PACKET_TYPE_CONTROL:
1238 /* ctrl */
1239 HandleCtrl(r, packet);
1240 break;
1242 case RTMP_PACKET_TYPE_SERVER_BW:
1243 /* server bw */
1244 HandleServerBW(r, packet);
1245 break;
1247 case RTMP_PACKET_TYPE_CLIENT_BW:
1248 /* client bw */
1249 HandleClientBW(r, packet);
1250 break;
1252 case RTMP_PACKET_TYPE_AUDIO:
1253 /* audio data */
1254 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1255 HandleAudio(r, packet);
1256 bHasMediaPacket = 1;
1257 if (!r->m_mediaChannel)
1258 r->m_mediaChannel = packet->m_nChannel;
1259 if (!r->m_pausing)
1260 r->m_mediaStamp = packet->m_nTimeStamp;
1261 break;
1263 case RTMP_PACKET_TYPE_VIDEO:
1264 /* video data */
1265 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1266 HandleVideo(r, packet);
1267 bHasMediaPacket = 1;
1268 if (!r->m_mediaChannel)
1269 r->m_mediaChannel = packet->m_nChannel;
1270 if (!r->m_pausing)
1271 r->m_mediaStamp = packet->m_nTimeStamp;
1272 break;
1274 case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
1275 /* flex stream send */
1276 RTMP_Log(RTMP_LOGDEBUG,
1277 "%s, flex stream send, size %u bytes, not supported, ignoring",
1278 __FUNCTION__, packet->m_nBodySize);
1279 break;
1281 case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
1282 /* flex shared object */
1283 RTMP_Log(RTMP_LOGDEBUG,
1284 "%s, flex shared object, size %u bytes, not supported, ignoring",
1285 __FUNCTION__, packet->m_nBodySize);
1286 break;
1288 case RTMP_PACKET_TYPE_FLEX_MESSAGE:
1289 /* flex message */
1291 RTMP_Log(RTMP_LOGDEBUG,
1292 "%s, flex message, size %u bytes, not fully supported",
1293 __FUNCTION__, packet->m_nBodySize);
1294 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1296 /* some DEBUG code */
1297 #if 0
1298 RTMP_LIB_AMFObject obj;
1299 int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
1300 if(nRes < 0) {
1301 RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
1302 /*return; */
1305 obj.Dump();
1306 #endif
1308 if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
1309 bHasMediaPacket = 2;
1310 break;
1312 case RTMP_PACKET_TYPE_INFO:
1313 /* metadata (notify) */
1314 RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
1315 packet->m_nBodySize);
1316 if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
1317 bHasMediaPacket = 1;
1318 break;
1320 case RTMP_PACKET_TYPE_SHARED_OBJECT:
1321 RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
1322 __FUNCTION__);
1323 break;
1325 case RTMP_PACKET_TYPE_INVOKE:
1326 /* invoke */
1327 RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
1328 packet->m_nBodySize);
1329 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1331 if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
1332 bHasMediaPacket = 2;
1333 break;
1335 case RTMP_PACKET_TYPE_FLASH_VIDEO:
1337 /* go through FLV packets and handle metadata packets */
1338 unsigned int pos = 0;
1339 uint32_t nTimeStamp = packet->m_nTimeStamp;
1341 while (pos + 11 < packet->m_nBodySize)
1343 uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
1345 if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
1347 RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
1348 break;
1350 if (packet->m_body[pos] == 0x12)
1352 HandleMetadata(r, packet->m_body + pos + 11, dataSize);
1354 else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
1356 nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
1357 nTimeStamp |= (packet->m_body[pos + 7] << 24);
1359 pos += (11 + dataSize + 4);
1361 if (!r->m_pausing)
1362 r->m_mediaStamp = nTimeStamp;
1364 /* FLV tag(s) */
1365 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1366 bHasMediaPacket = 1;
1367 break;
1369 default:
1370 RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
1371 packet->m_packetType);
1372 #ifdef _DEBUG
1373 RTMP_LogHex(RTMP_LOGDEBUG, packet->m_body, packet->m_nBodySize);
1374 #endif
1377 return bHasMediaPacket;
1380 #ifdef _DEBUG
1381 extern FILE *netstackdump;
1382 extern FILE *netstackdump_read;
1383 #endif
1385 static int
1386 ReadN(RTMP *r, char *buffer, int n)
1388 int nOriginalSize = n;
1389 int avail;
1390 char *ptr;
1392 r->m_sb.sb_timedout = FALSE;
1394 #ifdef _DEBUG
1395 memset(buffer, 0, n);
1396 #endif
1398 ptr = buffer;
1399 while (n > 0)
1401 int nBytes = 0, nRead;
1402 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1404 int refill = 0;
1405 while (!r->m_resplen)
1407 int ret;
1408 if (r->m_sb.sb_size < 13 || refill)
1410 if (!r->m_unackd)
1411 HTTP_Post(r, RTMPT_IDLE, "", 1);
1412 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1414 if (!r->m_sb.sb_timedout)
1415 RTMP_Close(r);
1416 return 0;
1419 if ((ret = HTTP_read(r, 0)) == -1)
1421 RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__);
1422 RTMP_Close(r);
1423 return 0;
1425 else if (ret == -2)
1427 refill = 1;
1429 else
1431 refill = 0;
1434 if (r->m_resplen && !r->m_sb.sb_size)
1435 RTMPSockBuf_Fill(&r->m_sb);
1436 avail = r->m_sb.sb_size;
1437 if (avail > r->m_resplen)
1438 avail = r->m_resplen;
1440 else
1442 avail = r->m_sb.sb_size;
1443 if (avail == 0)
1445 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1447 if (!r->m_sb.sb_timedout)
1448 RTMP_Close(r);
1449 return 0;
1451 avail = r->m_sb.sb_size;
1454 nRead = ((n < avail) ? n : avail);
1455 if (nRead > 0)
1457 memcpy(ptr, r->m_sb.sb_start, nRead);
1458 r->m_sb.sb_start += nRead;
1459 r->m_sb.sb_size -= nRead;
1460 nBytes = nRead;
1461 r->m_nBytesIn += nRead;
1462 if (r->m_bSendCounter
1463 && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
1464 if (!SendBytesReceived(r))
1465 return FALSE;
1467 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
1468 #ifdef _DEBUG
1469 fwrite(ptr, 1, nBytes, netstackdump_read);
1470 #endif
1472 if (nBytes == 0)
1474 RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
1475 /*goto again; */
1476 RTMP_Close(r);
1477 break;
1480 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1481 r->m_resplen -= nBytes;
1483 #ifdef CRYPTO
1484 if (r->Link.rc4keyIn)
1486 RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
1488 #endif
1490 n -= nBytes;
1491 ptr += nBytes;
1494 return nOriginalSize - n;
1497 static int
1498 WriteN(RTMP *r, const char *buffer, int n)
1500 const char *ptr = buffer;
1501 #ifdef CRYPTO
1502 char *encrypted = 0;
1503 char buf[RTMP_BUFFER_CACHE_SIZE];
1505 if (r->Link.rc4keyOut)
1507 if (n > sizeof(buf))
1508 encrypted = (char *)malloc(n);
1509 else
1510 encrypted = (char *)buf;
1511 ptr = encrypted;
1512 RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
1514 #endif
1516 while (n > 0)
1518 int nBytes;
1520 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1521 nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
1522 else
1523 nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
1524 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
1526 if (nBytes < 0)
1528 int sockerr = GetSockError();
1529 RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
1530 sockerr, n);
1532 if (sockerr == EINTR && !RTMP_ctrlC)
1533 continue;
1535 RTMP_Close(r);
1536 n = 1;
1537 break;
1540 if (nBytes == 0)
1541 break;
1543 n -= nBytes;
1544 ptr += nBytes;
1547 #ifdef CRYPTO
1548 if (encrypted && encrypted != buf)
1549 free(encrypted);
1550 #endif
1552 return n == 0;
1555 #define SAVC(x) static const AVal av_##x = AVC(#x)
1557 SAVC(app);
1558 SAVC(connect);
1559 SAVC(flashVer);
1560 SAVC(swfUrl);
1561 SAVC(pageUrl);
1562 SAVC(tcUrl);
1563 SAVC(fpad);
1564 SAVC(capabilities);
1565 SAVC(audioCodecs);
1566 SAVC(videoCodecs);
1567 SAVC(videoFunction);
1568 SAVC(objectEncoding);
1569 SAVC(secureToken);
1570 SAVC(secureTokenResponse);
1571 SAVC(type);
1572 SAVC(nonprivate);
1574 static int
1575 SendConnectPacket(RTMP *r, RTMPPacket *cp)
1577 RTMPPacket packet;
1578 char pbuf[4096], *pend = pbuf + sizeof(pbuf);
1579 char *enc;
1581 if (cp)
1582 return RTMP_SendPacket(r, cp, TRUE);
1584 packet.m_nChannel = 0x03; /* control channel (invoke) */
1585 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1586 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1587 packet.m_nTimeStamp = 0;
1588 packet.m_nInfoField2 = 0;
1589 packet.m_hasAbsTimestamp = 0;
1590 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1592 enc = packet.m_body;
1593 enc = AMF_EncodeString(enc, pend, &av_connect);
1594 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1595 *enc++ = AMF_OBJECT;
1597 enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
1598 if (!enc)
1599 return FALSE;
1600 if (r->Link.protocol & RTMP_FEATURE_WRITE)
1602 enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
1603 if (!enc)
1604 return FALSE;
1606 if (r->Link.flashVer.av_len)
1608 enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
1609 if (!enc)
1610 return FALSE;
1612 if (r->Link.swfUrl.av_len)
1614 enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
1615 if (!enc)
1616 return FALSE;
1618 if (r->Link.tcUrl.av_len)
1620 enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
1621 if (!enc)
1622 return FALSE;
1624 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
1626 enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
1627 if (!enc)
1628 return FALSE;
1629 enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
1630 if (!enc)
1631 return FALSE;
1632 enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
1633 if (!enc)
1634 return FALSE;
1635 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
1636 if (!enc)
1637 return FALSE;
1638 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
1639 if (!enc)
1640 return FALSE;
1641 if (r->Link.pageUrl.av_len)
1643 enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
1644 if (!enc)
1645 return FALSE;
1648 if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
1649 { /* AMF0, AMF3 not fully supported yet */
1650 enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
1651 if (!enc)
1652 return FALSE;
1654 if (enc + 3 >= pend)
1655 return FALSE;
1656 *enc++ = 0;
1657 *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
1658 *enc++ = AMF_OBJECT_END;
1660 /* add auth string */
1661 if (r->Link.auth.av_len)
1663 enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
1664 if (!enc)
1665 return FALSE;
1666 enc = AMF_EncodeString(enc, pend, &r->Link.auth);
1667 if (!enc)
1668 return FALSE;
1670 if (r->Link.extras.o_num)
1672 int i;
1673 for (i = 0; i < r->Link.extras.o_num; i++)
1675 enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
1676 if (!enc)
1677 return FALSE;
1680 packet.m_nBodySize = enc - packet.m_body;
1682 return RTMP_SendPacket(r, &packet, TRUE);
1685 #if 0 /* unused */
1686 SAVC(bgHasStream);
1688 static int
1689 SendBGHasStream(RTMP *r, double dId, AVal *playpath)
1691 RTMPPacket packet;
1692 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1693 char *enc;
1695 packet.m_nChannel = 0x03; /* control channel (invoke) */
1696 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1697 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1698 packet.m_nTimeStamp = 0;
1699 packet.m_nInfoField2 = 0;
1700 packet.m_hasAbsTimestamp = 0;
1701 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1703 enc = packet.m_body;
1704 enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
1705 enc = AMF_EncodeNumber(enc, pend, dId);
1706 *enc++ = AMF_NULL;
1708 enc = AMF_EncodeString(enc, pend, playpath);
1709 if (enc == NULL)
1710 return FALSE;
1712 packet.m_nBodySize = enc - packet.m_body;
1714 return RTMP_SendPacket(r, &packet, TRUE);
1716 #endif
1718 SAVC(createStream);
1721 RTMP_SendCreateStream(RTMP *r)
1723 RTMPPacket packet;
1724 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1725 char *enc;
1727 packet.m_nChannel = 0x03; /* control channel (invoke) */
1728 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1729 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1730 packet.m_nTimeStamp = 0;
1731 packet.m_nInfoField2 = 0;
1732 packet.m_hasAbsTimestamp = 0;
1733 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1735 enc = packet.m_body;
1736 enc = AMF_EncodeString(enc, pend, &av_createStream);
1737 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1738 *enc++ = AMF_NULL; /* NULL */
1740 packet.m_nBodySize = enc - packet.m_body;
1742 return RTMP_SendPacket(r, &packet, TRUE);
1745 SAVC(FCSubscribe);
1747 static int
1748 SendFCSubscribe(RTMP *r, AVal *subscribepath)
1750 RTMPPacket packet;
1751 char pbuf[512], *pend = pbuf + sizeof(pbuf);
1752 char *enc;
1753 packet.m_nChannel = 0x03; /* control channel (invoke) */
1754 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1755 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1756 packet.m_nTimeStamp = 0;
1757 packet.m_nInfoField2 = 0;
1758 packet.m_hasAbsTimestamp = 0;
1759 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1761 RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
1762 enc = packet.m_body;
1763 enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
1764 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1765 *enc++ = AMF_NULL;
1766 enc = AMF_EncodeString(enc, pend, subscribepath);
1768 if (!enc)
1769 return FALSE;
1771 packet.m_nBodySize = enc - packet.m_body;
1773 return RTMP_SendPacket(r, &packet, TRUE);
1776 /* Justin.tv specific authentication */
1777 static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
1779 static int
1780 SendUsherToken(RTMP *r, AVal *usherToken)
1782 RTMPPacket packet;
1783 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1784 char *enc;
1785 packet.m_nChannel = 0x03; /* control channel (invoke) */
1786 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1787 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1788 packet.m_nTimeStamp = 0;
1789 packet.m_nInfoField2 = 0;
1790 packet.m_hasAbsTimestamp = 0;
1791 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1793 RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
1794 enc = packet.m_body;
1795 enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
1796 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1797 *enc++ = AMF_NULL;
1798 enc = AMF_EncodeString(enc, pend, usherToken);
1800 if (!enc)
1801 return FALSE;
1803 packet.m_nBodySize = enc - packet.m_body;
1805 return RTMP_SendPacket(r, &packet, FALSE);
1807 /******************************************/
1809 SAVC(releaseStream);
1811 static int
1812 SendReleaseStream(RTMP *r)
1814 RTMPPacket packet;
1815 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1816 char *enc;
1818 packet.m_nChannel = 0x03; /* control channel (invoke) */
1819 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1820 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1821 packet.m_nTimeStamp = 0;
1822 packet.m_nInfoField2 = 0;
1823 packet.m_hasAbsTimestamp = 0;
1824 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1826 enc = packet.m_body;
1827 enc = AMF_EncodeString(enc, pend, &av_releaseStream);
1828 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1829 *enc++ = AMF_NULL;
1830 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1831 if (!enc)
1832 return FALSE;
1834 packet.m_nBodySize = enc - packet.m_body;
1836 return RTMP_SendPacket(r, &packet, FALSE);
1839 SAVC(FCPublish);
1841 static int
1842 SendFCPublish(RTMP *r)
1844 RTMPPacket packet;
1845 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1846 char *enc;
1848 packet.m_nChannel = 0x03; /* control channel (invoke) */
1849 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1850 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1851 packet.m_nTimeStamp = 0;
1852 packet.m_nInfoField2 = 0;
1853 packet.m_hasAbsTimestamp = 0;
1854 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1856 enc = packet.m_body;
1857 enc = AMF_EncodeString(enc, pend, &av_FCPublish);
1858 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1859 *enc++ = AMF_NULL;
1860 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1861 if (!enc)
1862 return FALSE;
1864 packet.m_nBodySize = enc - packet.m_body;
1866 return RTMP_SendPacket(r, &packet, FALSE);
1869 SAVC(FCUnpublish);
1871 static int
1872 SendFCUnpublish(RTMP *r)
1874 RTMPPacket packet;
1875 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1876 char *enc;
1878 packet.m_nChannel = 0x03; /* control channel (invoke) */
1879 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1880 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1881 packet.m_nTimeStamp = 0;
1882 packet.m_nInfoField2 = 0;
1883 packet.m_hasAbsTimestamp = 0;
1884 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1886 enc = packet.m_body;
1887 enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
1888 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1889 *enc++ = AMF_NULL;
1890 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1891 if (!enc)
1892 return FALSE;
1894 packet.m_nBodySize = enc - packet.m_body;
1896 return RTMP_SendPacket(r, &packet, FALSE);
1899 SAVC(publish);
1900 SAVC(live);
1901 SAVC(record);
1903 static int
1904 SendPublish(RTMP *r)
1906 RTMPPacket packet;
1907 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1908 char *enc;
1910 packet.m_nChannel = 0x04; /* source channel (invoke) */
1911 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1912 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1913 packet.m_nTimeStamp = 0;
1914 packet.m_nInfoField2 = r->m_stream_id;
1915 packet.m_hasAbsTimestamp = 0;
1916 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1918 enc = packet.m_body;
1919 enc = AMF_EncodeString(enc, pend, &av_publish);
1920 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1921 *enc++ = AMF_NULL;
1922 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
1923 if (!enc)
1924 return FALSE;
1926 /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
1927 enc = AMF_EncodeString(enc, pend, &av_live);
1928 if (!enc)
1929 return FALSE;
1931 packet.m_nBodySize = enc - packet.m_body;
1933 return RTMP_SendPacket(r, &packet, TRUE);
1936 SAVC(deleteStream);
1938 static int
1939 SendDeleteStream(RTMP *r, double dStreamId)
1941 RTMPPacket packet;
1942 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1943 char *enc;
1945 packet.m_nChannel = 0x03; /* control channel (invoke) */
1946 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1947 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1948 packet.m_nTimeStamp = 0;
1949 packet.m_nInfoField2 = 0;
1950 packet.m_hasAbsTimestamp = 0;
1951 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1953 enc = packet.m_body;
1954 enc = AMF_EncodeString(enc, pend, &av_deleteStream);
1955 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1956 *enc++ = AMF_NULL;
1957 enc = AMF_EncodeNumber(enc, pend, dStreamId);
1959 packet.m_nBodySize = enc - packet.m_body;
1961 /* no response expected */
1962 return RTMP_SendPacket(r, &packet, FALSE);
1965 SAVC(pause);
1968 RTMP_SendPause(RTMP *r, int DoPause, int iTime)
1970 RTMPPacket packet;
1971 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1972 char *enc;
1974 packet.m_nChannel = 0x08; /* video channel */
1975 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1976 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1977 packet.m_nTimeStamp = 0;
1978 packet.m_nInfoField2 = 0;
1979 packet.m_hasAbsTimestamp = 0;
1980 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1982 enc = packet.m_body;
1983 enc = AMF_EncodeString(enc, pend, &av_pause);
1984 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1985 *enc++ = AMF_NULL;
1986 enc = AMF_EncodeBoolean(enc, pend, DoPause);
1987 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
1989 packet.m_nBodySize = enc - packet.m_body;
1991 RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
1992 return RTMP_SendPacket(r, &packet, TRUE);
1995 int RTMP_Pause(RTMP *r, int DoPause)
1997 if (DoPause)
1998 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
1999 r->m_channelTimestamp[r->m_mediaChannel] : 0;
2000 return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
2003 SAVC(seek);
2006 RTMP_SendSeek(RTMP *r, int iTime)
2008 RTMPPacket packet;
2009 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2010 char *enc;
2012 packet.m_nChannel = 0x08; /* video channel */
2013 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2014 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2015 packet.m_nTimeStamp = 0;
2016 packet.m_nInfoField2 = 0;
2017 packet.m_hasAbsTimestamp = 0;
2018 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2020 enc = packet.m_body;
2021 enc = AMF_EncodeString(enc, pend, &av_seek);
2022 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2023 *enc++ = AMF_NULL;
2024 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
2026 packet.m_nBodySize = enc - packet.m_body;
2028 r->m_read.flags |= RTMP_READ_SEEKING;
2029 r->m_read.nResumeTS = 0;
2031 return RTMP_SendPacket(r, &packet, TRUE);
2035 RTMP_SendServerBW(RTMP *r)
2037 RTMPPacket packet;
2038 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2040 packet.m_nChannel = 0x02; /* control channel (invoke) */
2041 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2042 packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
2043 packet.m_nTimeStamp = 0;
2044 packet.m_nInfoField2 = 0;
2045 packet.m_hasAbsTimestamp = 0;
2046 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2048 packet.m_nBodySize = 4;
2050 AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
2051 return RTMP_SendPacket(r, &packet, FALSE);
2055 RTMP_SendClientBW(RTMP *r)
2057 RTMPPacket packet;
2058 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2060 packet.m_nChannel = 0x02; /* control channel (invoke) */
2061 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2062 packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
2063 packet.m_nTimeStamp = 0;
2064 packet.m_nInfoField2 = 0;
2065 packet.m_hasAbsTimestamp = 0;
2066 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2068 packet.m_nBodySize = 5;
2070 AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
2071 packet.m_body[4] = r->m_nClientBW2;
2072 return RTMP_SendPacket(r, &packet, FALSE);
2075 static int
2076 SendBytesReceived(RTMP *r)
2078 RTMPPacket packet;
2079 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2081 packet.m_nChannel = 0x02; /* control channel (invoke) */
2082 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2083 packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
2084 packet.m_nTimeStamp = 0;
2085 packet.m_nInfoField2 = 0;
2086 packet.m_hasAbsTimestamp = 0;
2087 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2089 packet.m_nBodySize = 4;
2091 AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
2092 r->m_nBytesInSent = r->m_nBytesIn;
2094 /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
2095 return RTMP_SendPacket(r, &packet, FALSE);
2098 SAVC(_checkbw);
2100 static int
2101 SendCheckBW(RTMP *r)
2103 RTMPPacket packet;
2104 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2105 char *enc;
2107 packet.m_nChannel = 0x03; /* control channel (invoke) */
2108 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2109 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2110 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2111 packet.m_nInfoField2 = 0;
2112 packet.m_hasAbsTimestamp = 0;
2113 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2115 enc = packet.m_body;
2116 enc = AMF_EncodeString(enc, pend, &av__checkbw);
2117 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2118 *enc++ = AMF_NULL;
2120 packet.m_nBodySize = enc - packet.m_body;
2122 /* triggers _onbwcheck and eventually results in _onbwdone */
2123 return RTMP_SendPacket(r, &packet, FALSE);
2126 SAVC(_result);
2128 static int
2129 SendCheckBWResult(RTMP *r, double txn)
2131 RTMPPacket packet;
2132 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2133 char *enc;
2135 packet.m_nChannel = 0x03; /* control channel (invoke) */
2136 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2137 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2138 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2139 packet.m_nInfoField2 = 0;
2140 packet.m_hasAbsTimestamp = 0;
2141 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2143 enc = packet.m_body;
2144 enc = AMF_EncodeString(enc, pend, &av__result);
2145 enc = AMF_EncodeNumber(enc, pend, txn);
2146 *enc++ = AMF_NULL;
2147 enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
2149 packet.m_nBodySize = enc - packet.m_body;
2151 return RTMP_SendPacket(r, &packet, FALSE);
2154 SAVC(ping);
2155 SAVC(pong);
2157 static int
2158 SendPong(RTMP *r, double txn)
2160 RTMPPacket packet;
2161 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2162 char *enc;
2164 packet.m_nChannel = 0x03; /* control channel (invoke) */
2165 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2166 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2167 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2168 packet.m_nInfoField2 = 0;
2169 packet.m_hasAbsTimestamp = 0;
2170 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2172 enc = packet.m_body;
2173 enc = AMF_EncodeString(enc, pend, &av_pong);
2174 enc = AMF_EncodeNumber(enc, pend, txn);
2175 *enc++ = AMF_NULL;
2177 packet.m_nBodySize = enc - packet.m_body;
2179 return RTMP_SendPacket(r, &packet, FALSE);
2182 SAVC(play);
2184 static int
2185 SendPlay(RTMP *r)
2187 RTMPPacket packet;
2188 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2189 char *enc;
2191 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2192 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2193 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2194 packet.m_nTimeStamp = 0;
2195 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2196 packet.m_hasAbsTimestamp = 0;
2197 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2199 enc = packet.m_body;
2200 enc = AMF_EncodeString(enc, pend, &av_play);
2201 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2202 *enc++ = AMF_NULL;
2204 RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
2205 __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
2206 r->Link.playpath.av_val);
2207 enc = AMF_EncodeString(enc, pend, &r->Link.playpath);
2208 if (!enc)
2209 return FALSE;
2211 /* Optional parameters start and len.
2213 * start: -2, -1, 0, positive number
2214 * -2: looks for a live stream, then a recorded stream,
2215 * if not found any open a live stream
2216 * -1: plays a live stream
2217 * >=0: plays a recorded streams from 'start' milliseconds
2219 if (r->Link.lFlags & RTMP_LF_LIVE)
2220 enc = AMF_EncodeNumber(enc, pend, -1000.0);
2221 else
2223 if (r->Link.seekTime > 0.0)
2224 enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
2225 else
2226 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 */
2228 if (!enc)
2229 return FALSE;
2231 /* len: -1, 0, positive number
2232 * -1: plays live or recorded stream to the end (default)
2233 * 0: plays a frame 'start' ms away from the beginning
2234 * >0: plays a live or recoded stream for 'len' milliseconds
2236 /*enc += EncodeNumber(enc, -1.0); */ /* len */
2237 if (r->Link.stopTime)
2239 enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
2240 if (!enc)
2241 return FALSE;
2244 packet.m_nBodySize = enc - packet.m_body;
2246 return RTMP_SendPacket(r, &packet, TRUE);
2249 SAVC(set_playlist);
2250 SAVC(0);
2252 static int
2253 SendPlaylist(RTMP *r)
2255 RTMPPacket packet;
2256 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2257 char *enc;
2259 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2260 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2261 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2262 packet.m_nTimeStamp = 0;
2263 packet.m_nInfoField2 = r->m_stream_id; /*0x01000000; */
2264 packet.m_hasAbsTimestamp = 0;
2265 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2267 enc = packet.m_body;
2268 enc = AMF_EncodeString(enc, pend, &av_set_playlist);
2269 enc = AMF_EncodeNumber(enc, pend, 0);
2270 *enc++ = AMF_NULL;
2271 *enc++ = AMF_ECMA_ARRAY;
2272 *enc++ = 0;
2273 *enc++ = 0;
2274 *enc++ = 0;
2275 *enc++ = AMF_OBJECT;
2276 enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.playpath);
2277 if (!enc)
2278 return FALSE;
2279 if (enc + 3 >= pend)
2280 return FALSE;
2281 *enc++ = 0;
2282 *enc++ = 0;
2283 *enc++ = AMF_OBJECT_END;
2285 packet.m_nBodySize = enc - packet.m_body;
2287 return RTMP_SendPacket(r, &packet, TRUE);
2290 static int
2291 SendSecureTokenResponse(RTMP *r, AVal *resp)
2293 RTMPPacket packet;
2294 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2295 char *enc;
2297 packet.m_nChannel = 0x03; /* control channel (invoke) */
2298 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2299 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2300 packet.m_nTimeStamp = 0;
2301 packet.m_nInfoField2 = 0;
2302 packet.m_hasAbsTimestamp = 0;
2303 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2305 enc = packet.m_body;
2306 enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
2307 enc = AMF_EncodeNumber(enc, pend, 0.0);
2308 *enc++ = AMF_NULL;
2309 enc = AMF_EncodeString(enc, pend, resp);
2310 if (!enc)
2311 return FALSE;
2313 packet.m_nBodySize = enc - packet.m_body;
2315 return RTMP_SendPacket(r, &packet, FALSE);
2319 from http://jira.red5.org/confluence/display/docs/Ping:
2321 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.
2323 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.
2325 * 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.
2326 * type 1: Tell the stream to clear the playing buffer.
2327 * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
2328 * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
2329 * type 6: Ping the client from server. The second parameter is the current time.
2330 * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
2331 * type 26: SWFVerification request
2332 * type 27: SWFVerification response
2335 RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
2337 RTMPPacket packet;
2338 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2339 int nSize;
2340 char *buf;
2342 RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
2344 packet.m_nChannel = 0x02; /* control channel (ping) */
2345 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2346 packet.m_packetType = RTMP_PACKET_TYPE_CONTROL;
2347 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2348 packet.m_nInfoField2 = 0;
2349 packet.m_hasAbsTimestamp = 0;
2350 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2352 switch(nType) {
2353 case 0x03: nSize = 10; break; /* buffer time */
2354 case 0x1A: nSize = 3; break; /* SWF verify request */
2355 case 0x1B: nSize = 44; break; /* SWF verify response */
2356 default: nSize = 6; break;
2359 packet.m_nBodySize = nSize;
2361 buf = packet.m_body;
2362 buf = AMF_EncodeInt16(buf, pend, nType);
2364 if (nType == 0x1B)
2366 #ifdef CRYPTO
2367 memcpy(buf, r->Link.SWFVerificationResponse, 42);
2368 RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
2369 RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
2370 #endif
2372 else if (nType == 0x1A)
2374 *buf = nObject & 0xff;
2376 else
2378 if (nSize > 2)
2379 buf = AMF_EncodeInt32(buf, pend, nObject);
2381 if (nSize > 6)
2382 buf = AMF_EncodeInt32(buf, pend, nTime);
2385 return RTMP_SendPacket(r, &packet, FALSE);
2388 static void
2389 AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
2391 if (freeit)
2392 free(vals[i].name.av_val);
2393 (*num)--;
2394 for (; i < *num; i++)
2396 vals[i] = vals[i + 1];
2398 vals[i].name.av_val = NULL;
2399 vals[i].name.av_len = 0;
2400 vals[i].num = 0;
2403 void
2404 RTMP_DropRequest(RTMP *r, int i, int freeit)
2406 AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
2409 static void
2410 AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
2412 char *tmp;
2413 if (!(*num & 0x0f))
2414 *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
2415 tmp = malloc(av->av_len + 1);
2416 memcpy(tmp, av->av_val, av->av_len);
2417 tmp[av->av_len] = '\0';
2418 (*vals)[*num].num = txn;
2419 (*vals)[*num].name.av_len = av->av_len;
2420 (*vals)[(*num)++].name.av_val = tmp;
2423 static void
2424 AV_clear(RTMP_METHOD *vals, int num)
2426 int i;
2427 for (i = 0; i < num; i++)
2428 free(vals[i].name.av_val);
2429 free(vals);
2433 #ifdef CRYPTO
2434 static int
2435 b64enc(const unsigned char *input, int length, char *output, int maxsize)
2437 #ifdef USE_POLARSSL
2438 int buf_size = maxsize;
2439 if(base64_encode((unsigned char *) output, &buf_size, input, length) == 0)
2441 output[buf_size] = '\0';
2442 return 1;
2444 else
2446 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2447 return 0;
2449 #elif defined(USE_GNUTLS)
2450 if (BASE64_ENCODE_RAW_LENGTH(length) <= maxsize)
2451 base64_encode_raw((uint8_t*) output, length, input);
2452 else
2454 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2455 return 0;
2457 #else /* USE_OPENSSL */
2458 BIO *bmem, *b64;
2459 BUF_MEM *bptr;
2461 b64 = BIO_new(BIO_f_base64());
2462 bmem = BIO_new(BIO_s_mem());
2463 b64 = BIO_push(b64, bmem);
2464 BIO_write(b64, input, length);
2465 if (BIO_flush(b64) == 1)
2467 BIO_get_mem_ptr(b64, &bptr);
2468 memcpy(output, bptr->data, bptr->length-1);
2469 output[bptr->length-1] = '\0';
2471 else
2473 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2474 return 0;
2476 BIO_free_all(b64);
2477 #endif
2478 return 1;
2481 #ifdef USE_POLARSSL
2482 #define MD5_CTX md5_context
2483 #define MD5_Init(ctx) md5_starts(ctx)
2484 #define MD5_Update(ctx,data,len) md5_update(ctx,data,len)
2485 #define MD5_Final(dig,ctx) md5_finish(ctx,dig)
2486 #elif defined(USE_GNUTLS)
2487 typedef struct md5_ctx MD5_CTX
2488 #define MD5_Init(ctx) md5_init(ctx)
2489 #define MD5_Update(ctx,data,len) md5_update(ctx,len,data)
2490 #define MD5_Final(dig,ctx) md5_digest(ctx,MD5_DIGEST_LENGTH,dig)
2491 #else
2492 #endif
2494 static const AVal av_authmod_adobe = AVC("authmod=adobe");
2495 static const AVal av_authmod_llnw = AVC("authmod=llnw");
2497 static void hexenc(unsigned char *inbuf, int len, char *dst)
2499 char *ptr = dst;
2500 while(len--) {
2501 sprintf(ptr, "%02x", *inbuf++);
2502 ptr += 2;
2504 *ptr = '\0';
2507 static int
2508 PublisherAuth(RTMP *r, AVal *description)
2510 char *token_in = NULL;
2511 char *ptr;
2512 unsigned char md5sum_val[MD5_DIGEST_LENGTH+1];
2513 MD5_CTX md5ctx;
2514 int challenge2_data;
2515 #define RESPONSE_LEN 32
2516 #define CHALLENGE2_LEN 16
2517 #define SALTED2_LEN (32+8+8+8)
2518 #define B64DIGEST_LEN 22 /* 16 byte digest => 22 b64 chars */
2519 #define B64INT_LEN 6 /* 4 byte int => 6 b64 chars */
2520 #define HEXHASH_LEN (2*MD5_DIGEST_LENGTH)
2521 char response[RESPONSE_LEN];
2522 char challenge2[CHALLENGE2_LEN];
2523 char salted2[SALTED2_LEN];
2524 AVal pubToken;
2526 if (strstr(description->av_val, av_authmod_adobe.av_val) != NULL)
2528 if(strstr(description->av_val, "code=403 need auth") != NULL)
2530 if (strstr(r->Link.app.av_val, av_authmod_adobe.av_val) != NULL) {
2531 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2532 r->Link.pFlags |= RTMP_PUB_CLEAN;
2533 return 0;
2534 } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
2535 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8);
2536 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2537 av_authmod_adobe.av_val,
2538 r->Link.pubUser.av_val);
2539 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2540 r->Link.pFlags |= RTMP_PUB_NAME;
2541 } else {
2542 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2543 r->Link.pFlags |= RTMP_PUB_CLEAN;
2544 return 0;
2547 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2549 char *par, *val = NULL, *orig_ptr;
2550 AVal user, salt, opaque, challenge, *aptr = NULL;
2551 opaque.av_len = 0;
2552 challenge.av_len = 0;
2554 ptr = orig_ptr = strdup(token_in);
2555 while (ptr)
2557 par = ptr;
2558 ptr = strchr(par, '&');
2559 if(ptr)
2560 *ptr++ = '\0';
2562 val = strchr(par, '=');
2563 if(val)
2564 *val++ = '\0';
2566 if (aptr) {
2567 aptr->av_len = par - aptr->av_val - 1;
2568 aptr = NULL;
2570 if (strcmp(par, "user") == 0){
2571 user.av_val = val;
2572 aptr = &user;
2573 } else if (strcmp(par, "salt") == 0){
2574 salt.av_val = val;
2575 aptr = &salt;
2576 } else if (strcmp(par, "opaque") == 0){
2577 opaque.av_val = val;
2578 aptr = &opaque;
2579 } else if (strcmp(par, "challenge") == 0){
2580 challenge.av_val = val;
2581 aptr = &challenge;
2584 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2586 if (aptr)
2587 aptr->av_len = strlen(aptr->av_val);
2589 /* hash1 = base64enc(md5(user + _aodbeAuthSalt + password)) */
2590 MD5_Init(&md5ctx);
2591 MD5_Update(&md5ctx, user.av_val, user.av_len);
2592 MD5_Update(&md5ctx, salt.av_val, salt.av_len);
2593 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2594 MD5_Final(md5sum_val, &md5ctx);
2595 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2596 user.av_val, salt.av_val, r->Link.pubPasswd.av_val);
2597 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2599 b64enc(md5sum_val, MD5_DIGEST_LENGTH, salted2, SALTED2_LEN);
2600 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_1) = %s", __FUNCTION__, salted2);
2602 /* FIXME: what byte order does this depend on? */
2603 challenge2_data = rand();
2605 b64enc((unsigned char *) &challenge2_data, sizeof(int), challenge2, CHALLENGE2_LEN);
2606 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(%d) = %s", __FUNCTION__, challenge2_data, challenge2);
2608 MD5_Init(&md5ctx);
2609 MD5_Update(&md5ctx, salted2, B64DIGEST_LEN);
2610 /* response = base64enc(md5(hash1 + opaque + challenge2)) */
2611 if (opaque.av_len)
2612 MD5_Update(&md5ctx, opaque.av_val, opaque.av_len);
2613 if (challenge.av_len)
2614 MD5_Update(&md5ctx, challenge.av_val, challenge.av_len);
2615 MD5_Update(&md5ctx, challenge2, B64INT_LEN);
2616 MD5_Final(md5sum_val, &md5ctx);
2618 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2619 salted2, opaque.av_len ? opaque.av_val : "", challenge2);
2620 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2622 b64enc(md5sum_val, MD5_DIGEST_LENGTH, response, RESPONSE_LEN);
2623 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response);
2625 /* have all hashes, create auth token for the end of app */
2626 pubToken.av_val = malloc(32 + B64INT_LEN + B64DIGEST_LEN + opaque.av_len);
2627 pubToken.av_len = sprintf(pubToken.av_val,
2628 "&challenge=%s&response=%s&opaque=%s",
2629 challenge2,
2630 response,
2631 opaque.av_len ? opaque.av_val : "");
2632 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2633 free(orig_ptr);
2634 r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
2636 else if(strstr(description->av_val, "?reason=authfailed") != NULL)
2638 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: wrong password", __FUNCTION__);
2639 r->Link.pFlags |= RTMP_PUB_CLEAN;
2640 return 0;
2642 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
2644 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
2645 r->Link.pFlags |= RTMP_PUB_CLEAN;
2646 return 0;
2648 else
2650 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
2651 __FUNCTION__, description->av_val);
2652 r->Link.pFlags |= RTMP_PUB_CLEAN;
2653 return 0;
2656 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
2657 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
2658 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
2659 r->Link.app.av_len += pubToken.av_len;
2660 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2661 free(r->Link.app.av_val);
2662 r->Link.app.av_val = ptr;
2664 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
2665 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
2666 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
2667 r->Link.tcUrl.av_len += pubToken.av_len;
2668 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2669 free(r->Link.tcUrl.av_val);
2670 r->Link.tcUrl.av_val = ptr;
2672 free(pubToken.av_val);
2673 r->Link.pFlags |= RTMP_PUB_ALLOC;
2675 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
2676 r->Link.app.av_len, r->Link.app.av_val,
2677 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
2678 r->Link.playpath.av_val);
2680 else if (strstr(description->av_val, av_authmod_llnw.av_val) != NULL)
2682 if(strstr(description->av_val, "code=403 need auth") != NULL)
2684 /* This part seems to be the same for llnw and adobe */
2686 if (strstr(r->Link.app.av_val, av_authmod_llnw.av_val) != NULL) {
2687 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2688 r->Link.pFlags |= RTMP_PUB_CLEAN;
2689 return 0;
2690 } else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len) {
2691 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8);
2692 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2693 av_authmod_llnw.av_val,
2694 r->Link.pubUser.av_val);
2695 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2696 r->Link.pFlags |= RTMP_PUB_NAME;
2697 } else {
2698 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2699 r->Link.pFlags |= RTMP_PUB_CLEAN;
2700 return 0;
2703 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2705 char *orig_ptr;
2706 char *par, *val = NULL;
2707 char hash1[HEXHASH_LEN+1], hash2[HEXHASH_LEN+1], hash3[HEXHASH_LEN+1];
2708 AVal user, nonce, *aptr = NULL;
2709 AVal apptmp;
2711 /* llnw auth method
2712 * Seems to be closely based on HTTP Digest Auth:
2713 * http://tools.ietf.org/html/rfc2617
2714 * http://en.wikipedia.org/wiki/Digest_access_authentication
2717 const char authmod[] = "llnw";
2718 const char realm[] = "live";
2719 const char method[] = "publish";
2720 const char qop[] = "auth";
2721 /* nc = 1..connection count (or rather, number of times cnonce has been reused) */
2722 int nc = 1;
2723 /* nchex = hexenc(nc) (8 hex digits according to RFC 2617) */
2724 char nchex[9];
2725 /* cnonce = hexenc(4 random bytes) (initialized on first connection) */
2726 char cnonce[9];
2728 ptr = orig_ptr = strdup(token_in);
2729 /* Extract parameters (we need user and nonce) */
2730 while (ptr)
2732 par = ptr;
2733 ptr = strchr(par, '&');
2734 if(ptr)
2735 *ptr++ = '\0';
2737 val = strchr(par, '=');
2738 if(val)
2739 *val++ = '\0';
2741 if (aptr) {
2742 aptr->av_len = par - aptr->av_val - 1;
2743 aptr = NULL;
2745 if (strcmp(par, "user") == 0){
2746 user.av_val = val;
2747 aptr = &user;
2748 } else if (strcmp(par, "nonce") == 0){
2749 nonce.av_val = val;
2750 aptr = &nonce;
2753 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2755 if (aptr)
2756 aptr->av_len = strlen(aptr->av_val);
2758 /* FIXME: handle case where user==NULL or nonce==NULL */
2760 sprintf(nchex, "%08x", nc);
2761 sprintf(cnonce, "%08x", rand());
2763 /* hash1 = hexenc(md5(user + ":" + realm + ":" + password)) */
2764 MD5_Init(&md5ctx);
2765 MD5_Update(&md5ctx, user.av_val, user.av_len);
2766 MD5_Update(&md5ctx, ":", 1);
2767 MD5_Update(&md5ctx, realm, sizeof(realm)-1);
2768 MD5_Update(&md5ctx, ":", 1);
2769 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2770 MD5_Final(md5sum_val, &md5ctx);
2771 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s) =>", __FUNCTION__,
2772 user.av_val, realm, r->Link.pubPasswd.av_val);
2773 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2774 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash1);
2776 /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */
2777 /* Extract appname + appinstance without query parameters */
2778 apptmp = r->Link.app;
2779 ptr = strchr(apptmp.av_val, '?');
2780 if (ptr)
2781 apptmp.av_len = ptr - apptmp.av_val;
2783 MD5_Init(&md5ctx);
2784 MD5_Update(&md5ctx, method, sizeof(method)-1);
2785 MD5_Update(&md5ctx, ":/", 2);
2786 MD5_Update(&md5ctx, apptmp.av_val, apptmp.av_len);
2787 MD5_Final(md5sum_val, &md5ctx);
2788 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:/%.*s) =>", __FUNCTION__,
2789 method, apptmp.av_len, apptmp.av_val);
2790 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2791 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash2);
2793 /* hash3 = hexenc(md5(hash1 + ":" + nonce + ":" + nchex + ":" + cnonce + ":" + qop + ":" + hash2)) */
2794 MD5_Init(&md5ctx);
2795 MD5_Update(&md5ctx, hash1, HEXHASH_LEN);
2796 MD5_Update(&md5ctx, ":", 1);
2797 MD5_Update(&md5ctx, nonce.av_val, nonce.av_len);
2798 MD5_Update(&md5ctx, ":", 1);
2799 MD5_Update(&md5ctx, nchex, sizeof(nchex)-1);
2800 MD5_Update(&md5ctx, ":", 1);
2801 MD5_Update(&md5ctx, cnonce, sizeof(cnonce)-1);
2802 MD5_Update(&md5ctx, ":", 1);
2803 MD5_Update(&md5ctx, qop, sizeof(qop)-1);
2804 MD5_Update(&md5ctx, ":", 1);
2805 MD5_Update(&md5ctx, hash2, HEXHASH_LEN);
2806 MD5_Final(md5sum_val, &md5ctx);
2807 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s:%s:%s:%s) =>", __FUNCTION__,
2808 hash1, nonce.av_val, nchex, cnonce, qop, hash2);
2809 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2810 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash3);
2812 /* pubToken = &authmod=<authmod>&user=<username>&nonce=<nonce>&cnonce=<cnonce>&nc=<nchex>&response=<hash3> */
2813 /* Append nonces and response to query string which already contains
2814 * user + authmod */
2815 pubToken.av_val = malloc(64 + sizeof(authmod)-1 + user.av_len + nonce.av_len + sizeof(cnonce)-1 + sizeof(nchex)-1 + HEXHASH_LEN);
2816 sprintf(pubToken.av_val,
2817 "&nonce=%s&cnonce=%s&nc=%s&response=%s",
2818 nonce.av_val, cnonce, nchex, hash3);
2819 pubToken.av_len = strlen(pubToken.av_val);
2820 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2821 r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
2823 free(orig_ptr);
2825 else if(strstr(description->av_val, "?reason=authfail") != NULL)
2827 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed", __FUNCTION__);
2828 r->Link.pFlags |= RTMP_PUB_CLEAN;
2829 return 0;
2831 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
2833 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
2834 r->Link.pFlags |= RTMP_PUB_CLEAN;
2835 return 0;
2837 else
2839 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
2840 __FUNCTION__, description->av_val);
2841 r->Link.pFlags |= RTMP_PUB_CLEAN;
2842 return 0;
2845 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
2846 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
2847 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
2848 r->Link.app.av_len += pubToken.av_len;
2849 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2850 free(r->Link.app.av_val);
2851 r->Link.app.av_val = ptr;
2853 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
2854 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
2855 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
2856 r->Link.tcUrl.av_len += pubToken.av_len;
2857 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2858 free(r->Link.tcUrl.av_val);
2859 r->Link.tcUrl.av_val = ptr;
2861 free(pubToken.av_val);
2862 r->Link.pFlags |= RTMP_PUB_ALLOC;
2864 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
2865 r->Link.app.av_len, r->Link.app.av_val,
2866 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
2867 r->Link.playpath.av_val);
2869 else
2871 return 0;
2873 return 1;
2875 #endif
2878 SAVC(onBWDone);
2879 SAVC(onFCSubscribe);
2880 SAVC(onFCUnsubscribe);
2881 SAVC(_onbwcheck);
2882 SAVC(_onbwdone);
2883 SAVC(_error);
2884 SAVC(close);
2885 SAVC(code);
2886 SAVC(level);
2887 SAVC(description);
2888 SAVC(onStatus);
2889 SAVC(playlist_ready);
2890 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
2891 static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
2892 static const AVal av_NetStream_Play_StreamNotFound =
2893 AVC("NetStream.Play.StreamNotFound");
2894 static const AVal av_NetConnection_Connect_InvalidApp =
2895 AVC("NetConnection.Connect.InvalidApp");
2896 static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
2897 static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
2898 static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
2899 static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
2900 static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
2901 static const AVal av_NetStream_Play_PublishNotify =
2902 AVC("NetStream.Play.PublishNotify");
2903 static const AVal av_NetStream_Play_UnpublishNotify =
2904 AVC("NetStream.Play.UnpublishNotify");
2905 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
2906 static const AVal av_NetConnection_Connect_Rejected =
2907 AVC("NetConnection.Connect.Rejected");
2909 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
2910 static int
2911 HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
2913 AMFObject obj;
2914 AVal method;
2915 double txn;
2916 int ret = 0, nRes;
2917 if (body[0] != 0x02) /* make sure it is a string method name we start with */
2919 RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
2920 __FUNCTION__);
2921 return 0;
2924 nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
2925 if (nRes < 0)
2927 RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
2928 return 0;
2931 AMF_Dump(&obj);
2932 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
2933 txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
2934 RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
2936 if (AVMATCH(&method, &av__result))
2938 AVal methodInvoked = {0};
2939 int i;
2941 for (i=0; i<r->m_numCalls; i++) {
2942 if (r->m_methodCalls[i].num == (int)txn) {
2943 methodInvoked = r->m_methodCalls[i].name;
2944 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
2945 break;
2948 if (!methodInvoked.av_val) {
2949 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
2950 __FUNCTION__, txn);
2951 goto leave;
2954 RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
2955 methodInvoked.av_val);
2957 if (AVMATCH(&methodInvoked, &av_connect))
2959 if (r->Link.token.av_len)
2961 AMFObjectProperty p;
2962 if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
2964 DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
2965 SendSecureTokenResponse(r, &p.p_vu.p_aval);
2968 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2970 SendReleaseStream(r);
2971 SendFCPublish(r);
2973 else
2975 RTMP_SendServerBW(r);
2976 RTMP_SendCtrl(r, 3, 0, 300);
2978 RTMP_SendCreateStream(r);
2980 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
2982 /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
2983 if (r->Link.usherToken.av_len)
2984 SendUsherToken(r, &r->Link.usherToken);
2985 /* Send the FCSubscribe if live stream or if subscribepath is set */
2986 if (r->Link.subscribepath.av_len)
2987 SendFCSubscribe(r, &r->Link.subscribepath);
2988 else if (r->Link.lFlags & RTMP_LF_LIVE)
2989 SendFCSubscribe(r, &r->Link.playpath);
2992 else if (AVMATCH(&methodInvoked, &av_createStream))
2994 r->m_stream_id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
2996 if (r->Link.protocol & RTMP_FEATURE_WRITE)
2998 SendPublish(r);
3000 else
3002 if (r->Link.lFlags & RTMP_LF_PLST)
3003 SendPlaylist(r);
3004 SendPlay(r);
3005 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
3008 else if (AVMATCH(&methodInvoked, &av_play) ||
3009 AVMATCH(&methodInvoked, &av_publish))
3011 r->m_bPlaying = TRUE;
3013 free(methodInvoked.av_val);
3015 else if (AVMATCH(&method, &av_onBWDone))
3017 if (!r->m_nBWCheckCounter)
3018 SendCheckBW(r);
3020 else if (AVMATCH(&method, &av_onFCSubscribe))
3022 /* SendOnFCSubscribe(); */
3024 else if (AVMATCH(&method, &av_onFCUnsubscribe))
3026 RTMP_Close(r);
3027 ret = 1;
3029 else if (AVMATCH(&method, &av_ping))
3031 SendPong(r, txn);
3033 else if (AVMATCH(&method, &av__onbwcheck))
3035 SendCheckBWResult(r, txn);
3037 else if (AVMATCH(&method, &av__onbwdone))
3039 int i;
3040 for (i = 0; i < r->m_numCalls; i++)
3041 if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
3043 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3044 break;
3047 else if (AVMATCH(&method, &av__error))
3049 #ifdef CRYPTO
3050 AVal methodInvoked = {0};
3051 int i;
3053 if (r->Link.protocol & RTMP_FEATURE_WRITE)
3055 for (i=0; i<r->m_numCalls; i++)
3057 if (r->m_methodCalls[i].num == txn)
3059 methodInvoked = r->m_methodCalls[i].name;
3060 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
3061 break;
3064 if (!methodInvoked.av_val)
3066 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
3067 __FUNCTION__, txn);
3068 goto leave;
3071 RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__,
3072 methodInvoked.av_val);
3074 if (AVMATCH(&methodInvoked, &av_connect))
3076 AMFObject obj2;
3077 AVal code, level, description;
3078 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3079 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3080 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3081 AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
3082 RTMP_Log(RTMP_LOGDEBUG, "%s, error description: %s", __FUNCTION__, description.av_val);
3083 /* if PublisherAuth returns 1, then reconnect */
3084 PublisherAuth(r, &description);
3087 else
3089 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3091 free(methodInvoked.av_val);
3092 #else
3093 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3094 #endif
3096 else if (AVMATCH(&method, &av_close))
3098 RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
3099 RTMP_Close(r);
3100 #ifdef CRYPTO
3101 if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
3102 !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
3103 ( !(r->Link.pFlags & RTMP_PUB_NAME) ||
3104 !(r->Link.pFlags & RTMP_PUB_RESP) ||
3105 (r->Link.pFlags & RTMP_PUB_CLATE) ) )
3107 /* clean later */
3108 if(r->Link.pFlags & RTMP_PUB_CLATE)
3109 r->Link.pFlags |= RTMP_PUB_CLEAN;
3110 RTMP_Log(RTMP_LOGERROR, "authenticating publisher");
3112 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
3113 goto leave;
3115 #endif
3117 else if (AVMATCH(&method, &av_onStatus))
3119 AMFObject obj2;
3120 AVal code, level;
3121 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3122 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3123 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3125 RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
3126 if (AVMATCH(&code, &av_NetStream_Failed)
3127 || AVMATCH(&code, &av_NetStream_Play_Failed)
3128 || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
3129 || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp))
3131 r->m_stream_id = -1;
3132 RTMP_Close(r);
3133 RTMP_Log(RTMP_LOGERROR, "Closing connection: %s", code.av_val);
3136 else if (AVMATCH(&code, &av_NetStream_Play_Start)
3137 || AVMATCH(&code, &av_NetStream_Play_PublishNotify))
3139 int i;
3140 r->m_bPlaying = TRUE;
3141 for (i = 0; i < r->m_numCalls; i++)
3143 if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
3145 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3146 break;
3151 else if (AVMATCH(&code, &av_NetStream_Publish_Start))
3153 int i;
3154 r->m_bPlaying = TRUE;
3155 for (i = 0; i < r->m_numCalls; i++)
3157 if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
3159 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3160 break;
3165 /* Return 1 if this is a Play.Complete or Play.Stop */
3166 else if (AVMATCH(&code, &av_NetStream_Play_Complete)
3167 || AVMATCH(&code, &av_NetStream_Play_Stop)
3168 || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
3170 RTMP_Close(r);
3171 ret = 1;
3174 else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
3176 r->m_read.flags &= ~RTMP_READ_SEEKING;
3179 else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
3181 if (r->m_pausing == 1 || r->m_pausing == 2)
3183 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3184 r->m_pausing = 3;
3188 else if (AVMATCH(&method, &av_playlist_ready))
3190 int i;
3191 for (i = 0; i < r->m_numCalls; i++)
3193 if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
3195 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3196 break;
3200 else
3204 leave:
3205 AMF_Reset(&obj);
3206 return ret;
3210 RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
3211 AMFObjectProperty * p)
3213 int n;
3214 /* this is a small object search to locate the "duration" property */
3215 for (n = 0; n < obj->o_num; n++)
3217 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3219 if (AVMATCH(&prop->p_name, name))
3221 memcpy(p, prop, sizeof(*prop));
3222 return TRUE;
3225 if (prop->p_type == AMF_OBJECT)
3227 if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
3228 return TRUE;
3231 return FALSE;
3234 /* Like above, but only check if name is a prefix of property */
3236 RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
3237 AMFObjectProperty * p)
3239 int n;
3240 for (n = 0; n < obj->o_num; n++)
3242 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3244 if (prop->p_name.av_len > name->av_len &&
3245 !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
3247 memcpy(p, prop, sizeof(*prop));
3248 return TRUE;
3251 if (prop->p_type == AMF_OBJECT)
3253 if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
3254 return TRUE;
3257 return FALSE;
3260 static int
3261 DumpMetaData(AMFObject *obj)
3263 AMFObjectProperty *prop;
3264 int n;
3265 for (n = 0; n < obj->o_num; n++)
3267 prop = AMF_GetProp(obj, NULL, n);
3268 if (prop->p_type != AMF_OBJECT)
3270 char str[256] = "";
3271 switch (prop->p_type)
3273 case AMF_NUMBER:
3274 snprintf(str, 255, "%.2f", prop->p_vu.p_number);
3275 break;
3276 case AMF_BOOLEAN:
3277 snprintf(str, 255, "%s",
3278 prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
3279 break;
3280 case AMF_STRING:
3281 snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
3282 prop->p_vu.p_aval.av_val);
3283 break;
3284 case AMF_DATE:
3285 snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
3286 break;
3287 default:
3288 snprintf(str, 255, "INVALID TYPE 0x%02x",
3289 (unsigned char)prop->p_type);
3291 if (prop->p_name.av_len)
3293 /* chomp */
3294 if (strlen(str) >= 1 && str[strlen(str) - 1] == '\n')
3295 str[strlen(str) - 1] = '\0';
3296 RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
3297 prop->p_name.av_val, str);
3300 else
3302 if (prop->p_name.av_len)
3303 RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
3304 DumpMetaData(&prop->p_vu.p_object);
3307 return FALSE;
3310 SAVC(onMetaData);
3311 SAVC(duration);
3312 SAVC(video);
3313 SAVC(audio);
3315 static int
3316 HandleMetadata(RTMP *r, char *body, unsigned int len)
3318 /* allright we get some info here, so parse it and print it */
3319 /* also keep duration or filesize to make a nice progress bar */
3321 AMFObject obj;
3322 AVal metastring;
3323 int ret = FALSE;
3325 int nRes = AMF_Decode(&obj, body, len, FALSE);
3326 if (nRes < 0)
3328 RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
3329 return FALSE;
3332 AMF_Dump(&obj);
3333 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
3335 if (AVMATCH(&metastring, &av_onMetaData))
3337 AMFObjectProperty prop;
3338 /* Show metadata */
3339 RTMP_Log(RTMP_LOGINFO, "Metadata:");
3340 DumpMetaData(&obj);
3341 if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
3343 r->m_fDuration = prop.p_vu.p_number;
3344 /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
3346 /* Search for audio or video tags */
3347 if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
3348 r->m_read.dataType |= 1;
3349 if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
3350 r->m_read.dataType |= 4;
3351 ret = TRUE;
3353 AMF_Reset(&obj);
3354 return ret;
3357 static void
3358 HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
3360 if (packet->m_nBodySize >= 4)
3362 r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
3363 RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
3364 r->m_inChunkSize);
3368 static void
3369 HandleAudio(RTMP *r, const RTMPPacket *packet)
3373 static void
3374 HandleVideo(RTMP *r, const RTMPPacket *packet)
3378 static void
3379 HandleCtrl(RTMP *r, const RTMPPacket *packet)
3381 short nType = -1;
3382 unsigned int tmp;
3383 if (packet->m_body && packet->m_nBodySize >= 2)
3384 nType = AMF_DecodeInt16(packet->m_body);
3385 RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
3386 packet->m_nBodySize);
3387 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3389 if (packet->m_nBodySize >= 6)
3391 switch (nType)
3393 case 0:
3394 tmp = AMF_DecodeInt32(packet->m_body + 2);
3395 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
3396 break;
3398 case 1:
3399 tmp = AMF_DecodeInt32(packet->m_body + 2);
3400 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
3401 if (r->m_pausing == 1)
3402 r->m_pausing = 2;
3403 break;
3405 case 2:
3406 tmp = AMF_DecodeInt32(packet->m_body + 2);
3407 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
3408 break;
3410 case 4:
3411 tmp = AMF_DecodeInt32(packet->m_body + 2);
3412 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
3413 break;
3415 case 6: /* server ping. reply with pong. */
3416 tmp = AMF_DecodeInt32(packet->m_body + 2);
3417 RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
3418 RTMP_SendCtrl(r, 0x07, tmp, 0);
3419 break;
3421 /* FMS 3.5 servers send the following two controls to let the client
3422 * know when the server has sent a complete buffer. I.e., when the
3423 * server has sent an amount of data equal to m_nBufferMS in duration.
3424 * The server meters its output so that data arrives at the client
3425 * in realtime and no faster.
3427 * The rtmpdump program tries to set m_nBufferMS as large as
3428 * possible, to force the server to send data as fast as possible.
3429 * In practice, the server appears to cap this at about 1 hour's
3430 * worth of data. After the server has sent a complete buffer, and
3431 * sends this BufferEmpty message, it will wait until the play
3432 * duration of that buffer has passed before sending a new buffer.
3433 * The BufferReady message will be sent when the new buffer starts.
3434 * (There is no BufferReady message for the very first buffer;
3435 * presumably the Stream Begin message is sufficient for that
3436 * purpose.)
3438 * If the network speed is much faster than the data bitrate, then
3439 * there may be long delays between the end of one buffer and the
3440 * start of the next.
3442 * Since usually the network allows data to be sent at
3443 * faster than realtime, and rtmpdump wants to download the data
3444 * as fast as possible, we use this RTMP_LF_BUFX hack: when we
3445 * get the BufferEmpty message, we send a Pause followed by an
3446 * Unpause. This causes the server to send the next buffer immediately
3447 * instead of waiting for the full duration to elapse. (That's
3448 * also the purpose of the ToggleStream function, which rtmpdump
3449 * calls if we get a read timeout.)
3451 * Media player apps don't need this hack since they are just
3452 * going to play the data in realtime anyway. It also doesn't work
3453 * for live streams since they obviously can only be sent in
3454 * realtime. And it's all moot if the network speed is actually
3455 * slower than the media bitrate.
3457 case 31:
3458 tmp = AMF_DecodeInt32(packet->m_body + 2);
3459 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
3460 if (!(r->Link.lFlags & RTMP_LF_BUFX))
3461 break;
3462 if (!r->m_pausing)
3464 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
3465 r->m_channelTimestamp[r->m_mediaChannel] : 0;
3466 RTMP_SendPause(r, TRUE, r->m_pauseStamp);
3467 r->m_pausing = 1;
3469 else if (r->m_pausing == 2)
3471 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3472 r->m_pausing = 3;
3474 break;
3476 case 32:
3477 tmp = AMF_DecodeInt32(packet->m_body + 2);
3478 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
3479 break;
3481 default:
3482 tmp = AMF_DecodeInt32(packet->m_body + 2);
3483 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
3484 break;
3489 if (nType == 0x1A)
3491 RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
3492 if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
3494 RTMP_Log(RTMP_LOGERROR,
3495 "%s: SWFVerification Type %d request not supported! Patches welcome...",
3496 __FUNCTION__, packet->m_body[2]);
3498 #ifdef CRYPTO
3499 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3501 /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
3502 else if (r->Link.SWFSize)
3504 RTMP_SendCtrl(r, 0x1B, 0, 0);
3506 else
3508 RTMP_Log(RTMP_LOGERROR,
3509 "%s: Ignoring SWFVerification request, use --swfVfy!",
3510 __FUNCTION__);
3512 #else
3513 RTMP_Log(RTMP_LOGERROR,
3514 "%s: Ignoring SWFVerification request, no CRYPTO support!",
3515 __FUNCTION__);
3516 #endif
3520 static void
3521 HandleServerBW(RTMP *r, const RTMPPacket *packet)
3523 r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
3524 RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
3527 static void
3528 HandleClientBW(RTMP *r, const RTMPPacket *packet)
3530 r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
3531 if (packet->m_nBodySize > 4)
3532 r->m_nClientBW2 = packet->m_body[4];
3533 else
3534 r->m_nClientBW2 = -1;
3535 RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
3536 r->m_nClientBW2);
3539 static int
3540 DecodeInt32LE(const char *data)
3542 unsigned char *c = (unsigned char *)data;
3543 unsigned int val;
3545 val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
3546 return val;
3549 static int
3550 EncodeInt32LE(char *output, int nVal)
3552 output[0] = nVal;
3553 nVal >>= 8;
3554 output[1] = nVal;
3555 nVal >>= 8;
3556 output[2] = nVal;
3557 nVal >>= 8;
3558 output[3] = nVal;
3559 return 4;
3563 RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
3565 uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
3566 char *header = (char *)hbuf;
3567 int nSize, hSize, nToRead, nChunk;
3568 int didAlloc = FALSE;
3570 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, r->m_sb.sb_socket);
3572 if (ReadN(r, (char *)hbuf, 1) == 0)
3574 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header", __FUNCTION__);
3575 return FALSE;
3578 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3579 packet->m_nChannel = (hbuf[0] & 0x3f);
3580 header++;
3581 if (packet->m_nChannel == 0)
3583 if (ReadN(r, (char *)&hbuf[1], 1) != 1)
3585 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
3586 __FUNCTION__);
3587 return FALSE;
3589 packet->m_nChannel = hbuf[1];
3590 packet->m_nChannel += 64;
3591 header++;
3593 else if (packet->m_nChannel == 1)
3595 int tmp;
3596 if (ReadN(r, (char *)&hbuf[1], 2) != 2)
3598 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
3599 __FUNCTION__);
3600 return FALSE;
3602 tmp = (hbuf[2] << 8) + hbuf[1];
3603 packet->m_nChannel = tmp + 64;
3604 RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
3605 header += 2;
3608 nSize = packetSize[packet->m_headerType];
3610 if (packet->m_nChannel >= r->m_channelsAllocatedIn)
3612 int n = packet->m_nChannel + 10;
3613 int *timestamp = realloc(r->m_channelTimestamp, sizeof(int) * n);
3614 RTMPPacket **packets = realloc(r->m_vecChannelsIn, sizeof(RTMPPacket*) * n);
3615 if (!timestamp)
3616 free(r->m_channelTimestamp);
3617 if (!packets)
3618 free(r->m_vecChannelsIn);
3619 r->m_channelTimestamp = timestamp;
3620 r->m_vecChannelsIn = packets;
3621 if (!timestamp || !packets) {
3622 r->m_channelsAllocatedIn = 0;
3623 return FALSE;
3625 memset(r->m_channelTimestamp + r->m_channelsAllocatedIn, 0, sizeof(int) * (n - r->m_channelsAllocatedIn));
3626 memset(r->m_vecChannelsIn + r->m_channelsAllocatedIn, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedIn));
3627 r->m_channelsAllocatedIn = n;
3630 if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
3631 packet->m_hasAbsTimestamp = TRUE;
3633 else if (nSize < RTMP_LARGE_HEADER_SIZE)
3634 { /* using values from the last message of this channel */
3635 if (r->m_vecChannelsIn[packet->m_nChannel])
3636 memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
3637 sizeof(RTMPPacket));
3640 nSize--;
3642 if (nSize > 0 && ReadN(r, header, nSize) != nSize)
3644 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
3645 __FUNCTION__, (unsigned int)hbuf[0]);
3646 return FALSE;
3649 hSize = nSize + (header - (char *)hbuf);
3651 if (nSize >= 3)
3653 packet->m_nTimeStamp = AMF_DecodeInt24(header);
3655 /*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); */
3657 if (nSize >= 6)
3659 packet->m_nBodySize = AMF_DecodeInt24(header + 3);
3660 packet->m_nBytesRead = 0;
3661 RTMPPacket_Free(packet);
3663 if (nSize > 6)
3665 packet->m_packetType = header[6];
3667 if (nSize == 11)
3668 packet->m_nInfoField2 = DecodeInt32LE(header + 7);
3671 if (packet->m_nTimeStamp == 0xffffff)
3673 if (ReadN(r, header + nSize, 4) != 4)
3675 RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
3676 __FUNCTION__);
3677 return FALSE;
3679 packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
3680 hSize += 4;
3684 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
3686 if (packet->m_nBodySize > 0 && packet->m_body == NULL)
3688 if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
3690 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
3691 return FALSE;
3693 didAlloc = TRUE;
3694 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3697 nToRead = packet->m_nBodySize - packet->m_nBytesRead;
3698 nChunk = r->m_inChunkSize;
3699 if (nToRead < nChunk)
3700 nChunk = nToRead;
3702 /* Does the caller want the raw chunk? */
3703 if (packet->m_chunk)
3705 packet->m_chunk->c_headerSize = hSize;
3706 memcpy(packet->m_chunk->c_header, hbuf, hSize);
3707 packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
3708 packet->m_chunk->c_chunkSize = nChunk;
3711 if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
3713 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %u",
3714 __FUNCTION__, packet->m_nBodySize);
3715 return FALSE;
3718 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
3720 packet->m_nBytesRead += nChunk;
3722 /* keep the packet as ref for other packets on this channel */
3723 if (!r->m_vecChannelsIn[packet->m_nChannel])
3724 r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3725 memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
3727 if (RTMPPacket_IsReady(packet))
3729 /* make packet's timestamp absolute */
3730 if (!packet->m_hasAbsTimestamp)
3731 packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
3733 r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
3735 /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
3736 /* arrives and requests to re-use some info (small packet header) */
3737 r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
3738 r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
3739 r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
3741 else
3743 packet->m_body = NULL; /* so it won't be erased on free */
3746 return TRUE;
3749 #ifndef CRYPTO
3750 static int
3751 HandShake(RTMP *r, int FP9HandShake)
3753 int i;
3754 uint32_t uptime, suptime;
3755 int bMatch;
3756 char type;
3757 char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
3758 char serversig[RTMP_SIG_SIZE];
3760 clientbuf[0] = 0x03; /* not encrypted */
3762 uptime = htonl(RTMP_GetTime());
3763 memcpy(clientsig, &uptime, 4);
3765 memset(&clientsig[4], 0, 4);
3767 #ifdef _DEBUG
3768 for (i = 8; i < RTMP_SIG_SIZE; i++)
3769 clientsig[i] = 0xff;
3770 #else
3771 for (i = 8; i < RTMP_SIG_SIZE; i++)
3772 clientsig[i] = (char)(rand() % 256);
3773 #endif
3775 if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
3776 return FALSE;
3778 if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
3779 return FALSE;
3781 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
3783 if (type != clientbuf[0])
3784 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
3785 __FUNCTION__, clientbuf[0], type);
3787 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3788 return FALSE;
3790 /* decode server response */
3792 memcpy(&suptime, serversig, 4);
3793 suptime = ntohl(suptime);
3795 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
3796 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
3797 serversig[4], serversig[5], serversig[6], serversig[7]);
3799 /* 2nd part of handshake */
3800 if (!WriteN(r, serversig, RTMP_SIG_SIZE))
3801 return FALSE;
3803 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3804 return FALSE;
3806 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3807 if (!bMatch)
3809 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3811 return TRUE;
3814 static int
3815 SHandShake(RTMP *r)
3817 int i;
3818 char serverbuf[RTMP_SIG_SIZE + 1], *serversig = serverbuf + 1;
3819 char clientsig[RTMP_SIG_SIZE];
3820 uint32_t uptime;
3821 int bMatch;
3823 if (ReadN(r, serverbuf, 1) != 1) /* 0x03 or 0x06 */
3824 return FALSE;
3826 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Request : %02X", __FUNCTION__, serverbuf[0]);
3828 if (serverbuf[0] != 3)
3830 RTMP_Log(RTMP_LOGERROR, "%s: Type unknown: client sent %02X",
3831 __FUNCTION__, serverbuf[0]);
3832 return FALSE;
3835 uptime = htonl(RTMP_GetTime());
3836 memcpy(serversig, &uptime, 4);
3838 memset(&serversig[4], 0, 4);
3839 #ifdef _DEBUG
3840 for (i = 8; i < RTMP_SIG_SIZE; i++)
3841 serversig[i] = 0xff;
3842 #else
3843 for (i = 8; i < RTMP_SIG_SIZE; i++)
3844 serversig[i] = (char)(rand() % 256);
3845 #endif
3847 if (!WriteN(r, serverbuf, RTMP_SIG_SIZE + 1))
3848 return FALSE;
3850 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3851 return FALSE;
3853 /* decode client response */
3855 memcpy(&uptime, clientsig, 4);
3856 uptime = ntohl(uptime);
3858 RTMP_Log(RTMP_LOGDEBUG, "%s: Client Uptime : %d", __FUNCTION__, uptime);
3859 RTMP_Log(RTMP_LOGDEBUG, "%s: Player Version: %d.%d.%d.%d", __FUNCTION__,
3860 clientsig[4], clientsig[5], clientsig[6], clientsig[7]);
3862 /* 2nd part of handshake */
3863 if (!WriteN(r, clientsig, RTMP_SIG_SIZE))
3864 return FALSE;
3866 if (ReadN(r, clientsig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
3867 return FALSE;
3869 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
3870 if (!bMatch)
3872 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
3874 return TRUE;
3876 #endif
3879 RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
3881 int wrote;
3882 char hbuf[RTMP_MAX_HEADER_SIZE];
3884 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
3885 chunk->c_chunkSize);
3886 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
3887 if (chunk->c_chunkSize)
3889 char *ptr = chunk->c_chunk - chunk->c_headerSize;
3890 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
3891 /* save header bytes we're about to overwrite */
3892 memcpy(hbuf, ptr, chunk->c_headerSize);
3893 memcpy(ptr, chunk->c_header, chunk->c_headerSize);
3894 wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
3895 memcpy(ptr, hbuf, chunk->c_headerSize);
3897 else
3898 wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
3899 return wrote;
3903 RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
3905 const RTMPPacket *prevPacket;
3906 uint32_t last = 0;
3907 int nSize;
3908 int hSize, cSize;
3909 char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
3910 uint32_t t;
3911 char *buffer, *tbuf = NULL, *toff = NULL;
3912 int nChunkSize;
3913 int tlen;
3915 if (packet->m_nChannel >= r->m_channelsAllocatedOut)
3917 int n = packet->m_nChannel + 10;
3918 RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket*) * n);
3919 if (!packets) {
3920 free(r->m_vecChannelsOut);
3921 r->m_vecChannelsOut = NULL;
3922 r->m_channelsAllocatedOut = 0;
3923 return FALSE;
3925 r->m_vecChannelsOut = packets;
3926 memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedOut));
3927 r->m_channelsAllocatedOut = n;
3930 prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
3931 if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
3933 /* compress a bit by using the prev packet's attributes */
3934 if (prevPacket->m_nBodySize == packet->m_nBodySize
3935 && prevPacket->m_packetType == packet->m_packetType
3936 && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
3937 packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
3939 if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
3940 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
3941 packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
3942 last = prevPacket->m_nTimeStamp;
3945 if (packet->m_headerType > 3) /* sanity */
3947 RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
3948 (unsigned char)packet->m_headerType);
3949 return FALSE;
3952 nSize = packetSize[packet->m_headerType];
3953 hSize = nSize; cSize = 0;
3954 t = packet->m_nTimeStamp - last;
3956 if (packet->m_body)
3958 header = packet->m_body - nSize;
3959 hend = packet->m_body;
3961 else
3963 header = hbuf + 6;
3964 hend = hbuf + sizeof(hbuf);
3967 if (packet->m_nChannel > 319)
3968 cSize = 2;
3969 else if (packet->m_nChannel > 63)
3970 cSize = 1;
3971 if (cSize)
3973 header -= cSize;
3974 hSize += cSize;
3977 if (nSize > 1 && t >= 0xffffff)
3979 header -= 4;
3980 hSize += 4;
3983 hptr = header;
3984 c = packet->m_headerType << 6;
3985 switch (cSize)
3987 case 0:
3988 c |= packet->m_nChannel;
3989 break;
3990 case 1:
3991 break;
3992 case 2:
3993 c |= 1;
3994 break;
3996 *hptr++ = c;
3997 if (cSize)
3999 int tmp = packet->m_nChannel - 64;
4000 *hptr++ = tmp & 0xff;
4001 if (cSize == 2)
4002 *hptr++ = tmp >> 8;
4005 if (nSize > 1)
4007 hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
4010 if (nSize > 4)
4012 hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
4013 *hptr++ = packet->m_packetType;
4016 if (nSize > 8)
4017 hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
4019 if (nSize > 1 && t >= 0xffffff)
4020 hptr = AMF_EncodeInt32(hptr, hend, t);
4022 nSize = packet->m_nBodySize;
4023 buffer = packet->m_body;
4024 nChunkSize = r->m_outChunkSize;
4026 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, r->m_sb.sb_socket,
4027 nSize);
4028 /* send all chunks in one HTTP request */
4029 if (r->Link.protocol & RTMP_FEATURE_HTTP)
4031 int chunks = (nSize+nChunkSize-1) / nChunkSize;
4032 if (chunks > 1)
4034 tlen = chunks * (cSize + 1) + nSize + hSize;
4035 tbuf = malloc(tlen);
4036 if (!tbuf)
4037 return FALSE;
4038 toff = tbuf;
4041 while (nSize + hSize)
4043 int wrote;
4045 if (nSize < nChunkSize)
4046 nChunkSize = nSize;
4048 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
4049 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
4050 if (tbuf)
4052 memcpy(toff, header, nChunkSize + hSize);
4053 toff += nChunkSize + hSize;
4055 else
4057 wrote = WriteN(r, header, nChunkSize + hSize);
4058 if (!wrote)
4059 return FALSE;
4061 nSize -= nChunkSize;
4062 buffer += nChunkSize;
4063 hSize = 0;
4065 if (nSize > 0)
4067 header = buffer - 1;
4068 hSize = 1;
4069 if (cSize)
4071 header -= cSize;
4072 hSize += cSize;
4074 *header = (0xc0 | c);
4075 if (cSize)
4077 int tmp = packet->m_nChannel - 64;
4078 header[1] = tmp & 0xff;
4079 if (cSize == 2)
4080 header[2] = tmp >> 8;
4084 if (tbuf)
4086 int wrote = WriteN(r, tbuf, toff-tbuf);
4087 free(tbuf);
4088 tbuf = NULL;
4089 if (!wrote)
4090 return FALSE;
4093 /* we invoked a remote method */
4094 if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE)
4096 AVal method;
4097 char *ptr;
4098 ptr = packet->m_body + 1;
4099 AMF_DecodeString(ptr, &method);
4100 RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
4101 /* keep it in call queue till result arrives */
4102 if (queue) {
4103 int txn;
4104 ptr += 3 + method.av_len;
4105 txn = (int)AMF_DecodeNumber(ptr);
4106 AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
4110 if (!r->m_vecChannelsOut[packet->m_nChannel])
4111 r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
4112 memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
4113 return TRUE;
4117 RTMP_Serve(RTMP *r)
4119 return SHandShake(r);
4122 void
4123 RTMP_Close(RTMP *r)
4125 int i;
4127 if (RTMP_IsConnected(r))
4129 if (r->m_stream_id > 0)
4131 i = r->m_stream_id;
4132 r->m_stream_id = 0;
4133 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
4134 SendFCUnpublish(r);
4135 SendDeleteStream(r, i);
4137 if (r->m_clientID.av_val)
4139 HTTP_Post(r, RTMPT_CLOSE, "", 1);
4140 free(r->m_clientID.av_val);
4141 r->m_clientID.av_val = NULL;
4142 r->m_clientID.av_len = 0;
4144 RTMPSockBuf_Close(&r->m_sb);
4147 r->m_stream_id = -1;
4148 r->m_sb.sb_socket = -1;
4149 r->m_nBWCheckCounter = 0;
4150 r->m_nBytesIn = 0;
4151 r->m_nBytesInSent = 0;
4153 if (r->m_read.flags & RTMP_READ_HEADER) {
4154 free(r->m_read.buf);
4155 r->m_read.buf = NULL;
4157 r->m_read.dataType = 0;
4158 r->m_read.flags = 0;
4159 r->m_read.status = 0;
4160 r->m_read.nResumeTS = 0;
4161 r->m_read.nIgnoredFrameCounter = 0;
4162 r->m_read.nIgnoredFlvFrameCounter = 0;
4164 r->m_write.m_nBytesRead = 0;
4165 RTMPPacket_Free(&r->m_write);
4167 for (i = 0; i < r->m_channelsAllocatedIn; i++)
4169 if (r->m_vecChannelsIn[i])
4171 RTMPPacket_Free(r->m_vecChannelsIn[i]);
4172 free(r->m_vecChannelsIn[i]);
4173 r->m_vecChannelsIn[i] = NULL;
4176 free(r->m_vecChannelsIn);
4177 r->m_vecChannelsIn = NULL;
4178 free(r->m_channelTimestamp);
4179 r->m_channelTimestamp = NULL;
4180 r->m_channelsAllocatedIn = 0;
4181 for (i = 0; i < r->m_channelsAllocatedOut; i++)
4183 if (r->m_vecChannelsOut[i])
4185 free(r->m_vecChannelsOut[i]);
4186 r->m_vecChannelsOut[i] = NULL;
4189 free(r->m_vecChannelsOut);
4190 r->m_vecChannelsOut = NULL;
4191 r->m_channelsAllocatedOut = 0;
4192 AV_clear(r->m_methodCalls, r->m_numCalls);
4193 r->m_methodCalls = NULL;
4194 r->m_numCalls = 0;
4195 r->m_numInvokes = 0;
4197 r->m_bPlaying = FALSE;
4198 r->m_sb.sb_size = 0;
4200 r->m_msgCounter = 0;
4201 r->m_resplen = 0;
4202 r->m_unackd = 0;
4204 if (r->Link.lFlags & RTMP_LF_FTCU)
4206 free(r->Link.tcUrl.av_val);
4207 r->Link.tcUrl.av_val = NULL;
4208 r->Link.lFlags ^= RTMP_LF_FTCU;
4211 #ifdef CRYPTO
4212 if (!(r->Link.protocol & RTMP_FEATURE_WRITE) || (r->Link.pFlags & RTMP_PUB_CLEAN))
4214 free(r->Link.playpath0.av_val);
4215 r->Link.playpath0.av_val = NULL;
4217 if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
4218 (r->Link.pFlags & RTMP_PUB_CLEAN) &&
4219 (r->Link.pFlags & RTMP_PUB_ALLOC))
4221 free(r->Link.app.av_val);
4222 r->Link.app.av_val = NULL;
4223 free(r->Link.tcUrl.av_val);
4224 r->Link.tcUrl.av_val = NULL;
4226 if (r->Link.dh)
4228 MDH_free(r->Link.dh);
4229 r->Link.dh = NULL;
4231 if (r->Link.rc4keyIn)
4233 RC4_free(r->Link.rc4keyIn);
4234 r->Link.rc4keyIn = NULL;
4236 if (r->Link.rc4keyOut)
4238 RC4_free(r->Link.rc4keyOut);
4239 r->Link.rc4keyOut = NULL;
4241 #else
4242 free(r->Link.playpath0.av_val);
4243 r->Link.playpath0.av_val = NULL;
4244 #endif
4248 RTMPSockBuf_Fill(RTMPSockBuf *sb)
4250 int nBytes;
4252 if (!sb->sb_size)
4253 sb->sb_start = sb->sb_buf;
4255 while (1)
4257 nBytes = sizeof(sb->sb_buf) - 1 - sb->sb_size - (sb->sb_start - sb->sb_buf);
4258 #if defined(CRYPTO) && !defined(NO_SSL)
4259 if (sb->sb_ssl)
4261 nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
4263 else
4264 #endif
4266 nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, 0);
4268 if (nBytes != -1)
4270 sb->sb_size += nBytes;
4272 else
4274 int sockerr = GetSockError();
4275 RTMP_Log(RTMP_LOGDEBUG, "%s, recv returned %d. GetSockError(): %d (%s)",
4276 __FUNCTION__, nBytes, sockerr, strerror(sockerr));
4277 if (sockerr == EINTR && !RTMP_ctrlC)
4278 continue;
4280 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
4282 sb->sb_timedout = TRUE;
4283 nBytes = 0;
4286 break;
4289 return nBytes;
4293 RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
4295 int rc;
4297 #ifdef _DEBUG
4298 fwrite(buf, 1, len, netstackdump);
4299 #endif
4301 #if defined(CRYPTO) && !defined(NO_SSL)
4302 if (sb->sb_ssl)
4304 rc = TLS_write(sb->sb_ssl, buf, len);
4306 else
4307 #endif
4309 rc = send(sb->sb_socket, buf, len, 0);
4311 return rc;
4315 RTMPSockBuf_Close(RTMPSockBuf *sb)
4317 #if defined(CRYPTO) && !defined(NO_SSL)
4318 if (sb->sb_ssl)
4320 TLS_shutdown(sb->sb_ssl);
4321 TLS_close(sb->sb_ssl);
4322 sb->sb_ssl = NULL;
4324 #endif
4325 if (sb->sb_socket != -1)
4326 return closesocket(sb->sb_socket);
4327 return 0;
4330 #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
4332 static void
4333 DecodeTEA(AVal *key, AVal *text)
4335 uint32_t *v, k[4] = { 0 }, u;
4336 uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
4337 int32_t p, q;
4338 int i, n;
4339 unsigned char *ptr, *out;
4341 /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
4342 ptr = (unsigned char *)key->av_val;
4343 u = 0;
4344 n = 0;
4345 v = k;
4346 p = key->av_len > 16 ? 16 : key->av_len;
4347 for (i = 0; i < p; i++)
4349 u |= ptr[i] << (n * 8);
4350 if (n == 3)
4352 *v++ = u;
4353 u = 0;
4354 n = 0;
4356 else
4358 n++;
4361 /* any trailing chars */
4362 if (u)
4363 *v = u;
4365 /* prep text: hex2bin, multiples of 4 */
4366 n = (text->av_len + 7) / 8;
4367 out = malloc(n * 8);
4368 ptr = (unsigned char *)text->av_val;
4369 v = (uint32_t *) out;
4370 for (i = 0; i < n; i++)
4372 u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
4373 u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
4374 u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
4375 u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
4376 *v++ = u;
4377 ptr += 8;
4379 v = (uint32_t *) out;
4381 /* http://www.movable-type.co.uk/scripts/tea-block.html */
4382 #define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
4383 z = v[n - 1];
4384 y = v[0];
4385 q = 6 + 52 / n;
4386 sum = q * DELTA;
4387 while (sum != 0)
4389 e = sum >> 2 & 3;
4390 for (p = n - 1; p > 0; p--)
4391 z = v[p - 1], y = v[p] -= MX;
4392 z = v[n - 1];
4393 y = v[0] -= MX;
4394 sum -= DELTA;
4397 text->av_len /= 2;
4398 memcpy(text->av_val, out, text->av_len);
4399 free(out);
4402 static int
4403 HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
4405 char hbuf[512];
4406 int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
4407 "Host: %.*s:%d\r\n"
4408 "Accept: */*\r\n"
4409 "User-Agent: Shockwave Flash\r\n"
4410 "Connection: Keep-Alive\r\n"
4411 "Cache-Control: no-cache\r\n"
4412 "Content-type: application/x-fcs\r\n"
4413 "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
4414 r->m_clientID.av_val ? r->m_clientID.av_val : "",
4415 r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
4416 r->Link.port, len);
4417 RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
4418 hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
4419 r->m_msgCounter++;
4420 r->m_unackd++;
4421 return hlen;
4424 static int
4425 HTTP_read(RTMP *r, int fill)
4427 char *ptr;
4428 int hlen;
4430 restart:
4431 if (fill)
4432 RTMPSockBuf_Fill(&r->m_sb);
4433 if (r->m_sb.sb_size < 13) {
4434 if (fill)
4435 goto restart;
4436 return -2;
4438 if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
4439 return -1;
4440 r->m_sb.sb_start[r->m_sb.sb_size] = '\0';
4441 if (!strstr(r->m_sb.sb_start, "\r\n\r\n")) {
4442 if (fill)
4443 goto restart;
4444 return -2;
4447 ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
4448 while ((ptr = strstr(ptr, "Content-"))) {
4449 if (!strncasecmp(ptr+8, "length:", 7)) break;
4450 ptr += 8;
4452 if (!ptr)
4453 return -1;
4454 hlen = atoi(ptr+16);
4455 ptr = strstr(ptr+16, "\r\n\r\n");
4456 if (!ptr)
4457 return -1;
4458 ptr += 4;
4459 if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size)
4461 if (fill)
4462 goto restart;
4463 return -2;
4465 r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
4466 r->m_sb.sb_start = ptr;
4467 r->m_unackd--;
4469 if (!r->m_clientID.av_val)
4471 r->m_clientID.av_len = hlen;
4472 r->m_clientID.av_val = malloc(hlen+1);
4473 if (!r->m_clientID.av_val)
4474 return -1;
4475 r->m_clientID.av_val[0] = '/';
4476 memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
4477 r->m_clientID.av_val[hlen] = 0;
4478 r->m_sb.sb_size = 0;
4480 else
4482 r->m_polling = *ptr++;
4483 r->m_resplen = hlen - 1;
4484 r->m_sb.sb_start++;
4485 r->m_sb.sb_size--;
4487 return 0;
4490 #define MAX_IGNORED_FRAMES 50
4492 /* Read from the stream until we get a media packet.
4493 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
4494 * packets, 0 if ignorable error, >0 if there is a media packet
4496 static int
4497 Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
4499 uint32_t prevTagSize = 0;
4500 int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
4501 RTMPPacket packet = { 0 };
4502 int recopy = FALSE;
4503 unsigned int size;
4504 char *ptr, *pend;
4505 uint32_t nTimeStamp = 0;
4506 unsigned int len;
4508 rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
4509 while (rtnGetNextMediaPacket)
4511 char *packetBody = packet.m_body;
4512 unsigned int nPacketLen = packet.m_nBodySize;
4514 /* Return RTMP_READ_COMPLETE if this was completed nicely with
4515 * invoke message Play.Stop or Play.Complete
4517 if (rtnGetNextMediaPacket == 2)
4519 RTMP_Log(RTMP_LOGDEBUG,
4520 "Got Play.Complete or Play.Stop from server. "
4521 "Assuming stream is complete");
4522 ret = RTMP_READ_COMPLETE;
4523 break;
4526 r->m_read.dataType |= (((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) << 2) |
4527 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO));
4529 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO && nPacketLen <= 5)
4531 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
4532 nPacketLen);
4533 ret = RTMP_READ_IGNORE;
4534 break;
4536 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO && nPacketLen <= 1)
4538 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
4539 nPacketLen);
4540 ret = RTMP_READ_IGNORE;
4541 break;
4544 if (r->m_read.flags & RTMP_READ_SEEKING)
4546 ret = RTMP_READ_IGNORE;
4547 break;
4549 #ifdef _DEBUG
4550 RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
4551 packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
4552 packet.m_hasAbsTimestamp);
4553 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
4554 RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
4555 #endif
4557 if (r->m_read.flags & RTMP_READ_RESUME)
4559 /* check the header if we get one */
4560 if (packet.m_nTimeStamp == 0)
4562 if (r->m_read.nMetaHeaderSize > 0
4563 && packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4565 AMFObject metaObj;
4566 int nRes =
4567 AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
4568 if (nRes >= 0)
4570 AVal metastring;
4571 AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
4572 &metastring);
4574 if (AVMATCH(&metastring, &av_onMetaData))
4576 /* compare */
4577 if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
4578 (memcmp
4579 (r->m_read.metaHeader, packetBody,
4580 r->m_read.nMetaHeaderSize) != 0))
4582 ret = RTMP_READ_ERROR;
4585 AMF_Reset(&metaObj);
4586 if (ret == RTMP_READ_ERROR)
4587 break;
4591 /* check first keyframe to make sure we got the right position
4592 * in the stream! (the first non ignored frame)
4594 if (r->m_read.nInitialFrameSize > 0)
4596 /* video or audio data */
4597 if (packet.m_packetType == r->m_read.initialFrameType
4598 && r->m_read.nInitialFrameSize == nPacketLen)
4600 /* we don't compare the sizes since the packet can
4601 * contain several FLV packets, just make sure the
4602 * first frame is our keyframe (which we are going
4603 * to rewrite)
4605 if (memcmp
4606 (r->m_read.initialFrame, packetBody,
4607 r->m_read.nInitialFrameSize) == 0)
4609 RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
4610 r->m_read.flags |= RTMP_READ_GOTKF;
4611 /* ignore it! (what about audio data after it? it is
4612 * handled by ignoring all 0ms frames, see below)
4614 ret = RTMP_READ_IGNORE;
4615 break;
4619 /* hande FLV streams, even though the server resends the
4620 * keyframe as an extra video packet it is also included
4621 * in the first FLV stream chunk and we have to compare
4622 * it and filter it out !!
4624 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4626 /* basically we have to find the keyframe with the
4627 * correct TS being nResumeTS
4629 unsigned int pos = 0;
4630 uint32_t ts = 0;
4632 while (pos + 11 < nPacketLen)
4634 /* size without header (11) and prevTagSize (4) */
4635 uint32_t dataSize =
4636 AMF_DecodeInt24(packetBody + pos + 1);
4637 ts = AMF_DecodeInt24(packetBody + pos + 4);
4638 ts |= (packetBody[pos + 7] << 24);
4640 #ifdef _DEBUG
4641 RTMP_Log(RTMP_LOGDEBUG,
4642 "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
4643 packetBody[pos], dataSize, ts);
4644 #endif
4645 /* ok, is it a keyframe?:
4646 * well doesn't work for audio!
4648 if (packetBody[pos /*6928, test 0 */ ] ==
4649 r->m_read.initialFrameType
4650 /* && (packetBody[11]&0xf0) == 0x10 */ )
4652 if (ts == r->m_read.nResumeTS)
4654 RTMP_Log(RTMP_LOGDEBUG,
4655 "Found keyframe with resume-keyframe timestamp!");
4656 if (r->m_read.nInitialFrameSize != dataSize
4657 || memcmp(r->m_read.initialFrame,
4658 packetBody + pos + 11,
4659 r->m_read.
4660 nInitialFrameSize) != 0)
4662 RTMP_Log(RTMP_LOGERROR,
4663 "FLV Stream: Keyframe doesn't match!");
4664 ret = RTMP_READ_ERROR;
4665 break;
4667 r->m_read.flags |= RTMP_READ_GOTFLVK;
4669 /* skip this packet?
4670 * check whether skippable:
4672 if (pos + 11 + dataSize + 4 > nPacketLen)
4674 RTMP_Log(RTMP_LOGWARNING,
4675 "Non skipable packet since it doesn't end with chunk, stream corrupt!");
4676 ret = RTMP_READ_ERROR;
4677 break;
4679 packetBody += (pos + 11 + dataSize + 4);
4680 nPacketLen -= (pos + 11 + dataSize + 4);
4682 goto stopKeyframeSearch;
4685 else if (r->m_read.nResumeTS < ts)
4687 /* the timestamp ts will only increase with
4688 * further packets, wait for seek
4690 goto stopKeyframeSearch;
4693 pos += (11 + dataSize + 4);
4695 if (ts < r->m_read.nResumeTS)
4697 RTMP_Log(RTMP_LOGERROR,
4698 "First packet does not contain keyframe, all "
4699 "timestamps are smaller than the keyframe "
4700 "timestamp; probably the resume seek failed?");
4702 stopKeyframeSearch:
4704 if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
4706 RTMP_Log(RTMP_LOGERROR,
4707 "Couldn't find the seeked keyframe in this chunk!");
4708 ret = RTMP_READ_IGNORE;
4709 break;
4715 if (packet.m_nTimeStamp > 0
4716 && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
4718 /* another problem is that the server can actually change from
4719 * 09/08 video/audio packets to an FLV stream or vice versa and
4720 * our keyframe check will prevent us from going along with the
4721 * new stream if we resumed.
4723 * in this case set the 'found keyframe' variables to true.
4724 * We assume that if we found one keyframe somewhere and were
4725 * already beyond TS > 0 we have written data to the output
4726 * which means we can accept all forthcoming data including the
4727 * change between 08/09 <-> FLV packets
4729 r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
4732 /* skip till we find our keyframe
4733 * (seeking might put us somewhere before it)
4735 if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
4736 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4738 RTMP_Log(RTMP_LOGWARNING,
4739 "Stream does not start with requested frame, ignoring data... ");
4740 r->m_read.nIgnoredFrameCounter++;
4741 if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
4742 ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
4743 else
4744 ret = RTMP_READ_IGNORE;
4745 break;
4747 /* ok, do the same for FLV streams */
4748 if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
4749 packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4751 RTMP_Log(RTMP_LOGWARNING,
4752 "Stream does not start with requested FLV frame, ignoring data... ");
4753 r->m_read.nIgnoredFlvFrameCounter++;
4754 if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
4755 ret = RTMP_READ_ERROR;
4756 else
4757 ret = RTMP_READ_IGNORE;
4758 break;
4761 /* we have to ignore the 0ms frames since these are the first
4762 * keyframes; we've got these so don't mess around with multiple
4763 * copies sent by the server to us! (if the keyframe is found at a
4764 * later position there is only one copy and it will be ignored by
4765 * the preceding if clause)
4767 if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
4768 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4770 /* exclude type RTMP_PACKET_TYPE_FLASH_VIDEO since it can
4771 * contain several FLV packets
4773 if (packet.m_nTimeStamp == 0)
4775 ret = RTMP_READ_IGNORE;
4776 break;
4778 else
4780 /* stop ignoring packets */
4781 r->m_read.flags |= RTMP_READ_NO_IGNORE;
4786 /* calculate packet size and allocate slop buffer if necessary */
4787 size = nPacketLen +
4788 ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4789 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4790 || packet.m_packetType == RTMP_PACKET_TYPE_INFO) ? 11 : 0) +
4791 (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO ? 4 : 0);
4793 if (size + 4 > buflen)
4795 /* the extra 4 is for the case of an FLV stream without a last
4796 * prevTagSize (we need extra 4 bytes to append it) */
4797 r->m_read.buf = malloc(size + 4);
4798 if (r->m_read.buf == 0)
4800 RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
4801 ret = RTMP_READ_ERROR; /* fatal error */
4802 break;
4804 recopy = TRUE;
4805 ptr = r->m_read.buf;
4807 else
4809 ptr = buf;
4811 pend = ptr + size + 4;
4813 /* use to return timestamp of last processed packet */
4815 /* audio (0x08), video (0x09) or metadata (0x12) packets :
4816 * construct 11 byte header then add rtmp packet's data */
4817 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4818 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4819 || packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4821 nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
4822 prevTagSize = 11 + nPacketLen;
4824 *ptr = packet.m_packetType;
4825 ptr++;
4826 ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
4828 #if 0
4829 if(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) {
4831 /* H264 fix: */
4832 if((packetBody[0] & 0x0f) == 7) { /* CodecId = H264 */
4833 uint8_t packetType = *(packetBody+1);
4835 uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
4836 int32_t cts = (ts+0xff800000)^0xff800000;
4837 RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
4839 nTimeStamp -= cts;
4840 /* get rid of the composition time */
4841 CRTMP::EncodeInt24(packetBody+2, 0);
4843 RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
4845 #endif
4847 ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
4848 *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
4849 ptr++;
4851 /* stream id */
4852 ptr = AMF_EncodeInt24(ptr, pend, 0);
4855 memcpy(ptr, packetBody, nPacketLen);
4856 len = nPacketLen;
4858 /* correct tagSize and obtain timestamp if we have an FLV stream */
4859 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4861 unsigned int pos = 0;
4862 int delta;
4864 /* grab first timestamp and see if it needs fixing */
4865 nTimeStamp = AMF_DecodeInt24(packetBody + 4);
4866 nTimeStamp |= (packetBody[7] << 24);
4867 delta = packet.m_nTimeStamp - nTimeStamp + r->m_read.nResumeTS;
4869 while (pos + 11 < nPacketLen)
4871 /* size without header (11) and without prevTagSize (4) */
4872 uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
4873 nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
4874 nTimeStamp |= (packetBody[pos + 7] << 24);
4876 if (delta)
4878 nTimeStamp += delta;
4879 AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
4880 ptr[pos+7] = nTimeStamp>>24;
4883 /* set data type */
4884 r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
4885 (*(packetBody + pos) == 0x09));
4887 if (pos + 11 + dataSize + 4 > nPacketLen)
4889 if (pos + 11 + dataSize > nPacketLen)
4891 RTMP_Log(RTMP_LOGERROR,
4892 "Wrong data size (%u), stream corrupted, aborting!",
4893 dataSize);
4894 ret = RTMP_READ_ERROR;
4895 break;
4897 RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
4899 /* we have to append a last tagSize! */
4900 prevTagSize = dataSize + 11;
4901 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4902 prevTagSize);
4903 size += 4;
4904 len += 4;
4906 else
4908 prevTagSize =
4909 AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
4911 #ifdef _DEBUG
4912 RTMP_Log(RTMP_LOGDEBUG,
4913 "FLV Packet: type %02X, dataSize: %lu, tagSize: %lu, timeStamp: %lu ms",
4914 (unsigned char)packetBody[pos], dataSize, prevTagSize,
4915 nTimeStamp);
4916 #endif
4918 if (prevTagSize != (dataSize + 11))
4920 #ifdef _DEBUG
4921 RTMP_Log(RTMP_LOGWARNING,
4922 "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
4923 dataSize + 11);
4924 #endif
4926 prevTagSize = dataSize + 11;
4927 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
4928 prevTagSize);
4932 pos += prevTagSize + 4; /*(11+dataSize+4); */
4935 ptr += len;
4937 if (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4939 /* FLV tag packets contain their own prevTagSize */
4940 AMF_EncodeInt32(ptr, pend, prevTagSize);
4943 /* In non-live this nTimeStamp can contain an absolute TS.
4944 * Update ext timestamp with this absolute offset in non-live mode
4945 * otherwise report the relative one
4947 /* 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); */
4948 r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
4950 ret = size;
4951 break;
4954 if (rtnGetNextMediaPacket)
4955 RTMPPacket_Free(&packet);
4957 if (recopy)
4959 len = ret > buflen ? buflen : ret;
4960 memcpy(buf, r->m_read.buf, len);
4961 r->m_read.bufpos = r->m_read.buf + len;
4962 r->m_read.buflen = ret - len;
4964 return ret;
4967 static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
4968 0x00, /* 0x04 == audio, 0x01 == video */
4969 0x00, 0x00, 0x00, 0x09,
4970 0x00, 0x00, 0x00, 0x00
4973 #define HEADERBUF (128*1024)
4975 RTMP_Read(RTMP *r, char *buf, int size)
4977 int nRead = 0, total = 0;
4979 /* can't continue */
4980 fail:
4981 switch (r->m_read.status) {
4982 case RTMP_READ_EOF:
4983 case RTMP_READ_COMPLETE:
4984 return 0;
4985 case RTMP_READ_ERROR: /* corrupted stream, resume failed */
4986 SetSockError(EINVAL);
4987 return -1;
4988 default:
4989 break;
4992 /* first time thru */
4993 if (!(r->m_read.flags & RTMP_READ_HEADER))
4995 if (!(r->m_read.flags & RTMP_READ_RESUME))
4997 char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
4998 int cnt = 0;
4999 r->m_read.buf = mybuf;
5000 r->m_read.buflen = HEADERBUF;
5002 memcpy(mybuf, flvHeader, sizeof(flvHeader));
5003 r->m_read.buf += sizeof(flvHeader);
5004 r->m_read.buflen -= sizeof(flvHeader);
5006 while (r->m_read.timestamp == 0)
5008 nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
5009 if (nRead < 0)
5011 free(mybuf);
5012 r->m_read.buf = NULL;
5013 r->m_read.buflen = 0;
5014 r->m_read.status = nRead;
5015 goto fail;
5017 /* buffer overflow, fix buffer and give up */
5018 if (r->m_read.buf < mybuf || r->m_read.buf > end) {
5019 mybuf = realloc(mybuf, cnt + nRead);
5020 memcpy(mybuf+cnt, r->m_read.buf, nRead);
5021 r->m_read.buf = mybuf+cnt+nRead;
5022 break;
5024 cnt += nRead;
5025 r->m_read.buf += nRead;
5026 r->m_read.buflen -= nRead;
5027 if (r->m_read.dataType == 5)
5028 break;
5030 mybuf[4] = r->m_read.dataType;
5031 r->m_read.buflen = r->m_read.buf - mybuf;
5032 r->m_read.buf = mybuf;
5033 r->m_read.bufpos = mybuf;
5035 r->m_read.flags |= RTMP_READ_HEADER;
5038 if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
5040 /* drop whatever's here */
5041 free(r->m_read.buf);
5042 r->m_read.buf = NULL;
5043 r->m_read.bufpos = NULL;
5044 r->m_read.buflen = 0;
5047 /* If there's leftover data buffered, use it up */
5048 if (r->m_read.buf)
5050 nRead = r->m_read.buflen;
5051 if (nRead > size)
5052 nRead = size;
5053 memcpy(buf, r->m_read.bufpos, nRead);
5054 r->m_read.buflen -= nRead;
5055 if (!r->m_read.buflen)
5057 free(r->m_read.buf);
5058 r->m_read.buf = NULL;
5059 r->m_read.bufpos = NULL;
5061 else
5063 r->m_read.bufpos += nRead;
5065 buf += nRead;
5066 total += nRead;
5067 size -= nRead;
5070 while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
5072 if (!nRead) continue;
5073 buf += nRead;
5074 total += nRead;
5075 size -= nRead;
5076 break;
5078 if (nRead < 0)
5079 r->m_read.status = nRead;
5081 if (size < 0)
5082 total += size;
5083 return total;
5086 static const AVal av_setDataFrame = AVC("@setDataFrame");
5089 RTMP_Write(RTMP *r, const char *buf, int size)
5091 RTMPPacket *pkt = &r->m_write;
5092 char *pend, *enc;
5093 int s2 = size, ret, num;
5095 pkt->m_nChannel = 0x04; /* source channel */
5096 pkt->m_nInfoField2 = r->m_stream_id;
5098 while (s2)
5100 if (!pkt->m_nBytesRead)
5102 if (size < 11) {
5103 /* FLV pkt too small */
5104 return 0;
5107 if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
5109 buf += 13;
5110 s2 -= 13;
5113 pkt->m_packetType = *buf++;
5114 pkt->m_nBodySize = AMF_DecodeInt24(buf);
5115 buf += 3;
5116 pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
5117 buf += 3;
5118 pkt->m_nTimeStamp |= *buf++ << 24;
5119 buf += 3;
5120 s2 -= 11;
5122 if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
5123 || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
5124 !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5126 pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
5127 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5128 pkt->m_nBodySize += 16;
5130 else
5132 pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
5135 if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
5137 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
5138 return FALSE;
5140 enc = pkt->m_body;
5141 pend = enc + pkt->m_nBodySize;
5142 if (pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5144 enc = AMF_EncodeString(enc, pend, &av_setDataFrame);
5145 pkt->m_nBytesRead = enc - pkt->m_body;
5148 else
5150 enc = pkt->m_body + pkt->m_nBytesRead;
5152 num = pkt->m_nBodySize - pkt->m_nBytesRead;
5153 if (num > s2)
5154 num = s2;
5155 memcpy(enc, buf, num);
5156 pkt->m_nBytesRead += num;
5157 s2 -= num;
5158 buf += num;
5159 if (pkt->m_nBytesRead == pkt->m_nBodySize)
5161 ret = RTMP_SendPacket(r, pkt, FALSE);
5162 RTMPPacket_Free(pkt);
5163 pkt->m_nBytesRead = 0;
5164 if (!ret)
5165 return -1;
5166 buf += 4;
5167 s2 -= 4;
5168 if (s2 < 0)
5169 break;
5172 return size+s2;