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
6 *
7 * This file is part of librtmp.
8 *
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.
13 *
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.
18 *
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
24 */
25
26 #ifndef NO_AUTH
27 #ifndef CRYPTO
28 #define USE_ONLY_MD5
29 #endif
30 #endif
31
32 #include "rtmp_sys.h"
33 #include "log.h"
34
35 #include <util/platform.h>
36
37 #if !defined(MSG_NOSIGNAL)
38 #define MSG_NOSIGNAL 0
39 #endif
40
41 #ifdef CRYPTO
42
43 #ifdef __APPLE__
44 #pragma GCC diagnostic ignored "-Wdeprecated-declarations"
45 #endif
46
47 #if defined(USE_MBEDTLS)
48 #if defined(_WIN32)
49 #include <windows.h>
50 #include <wincrypt.h>
51 #elif defined(__APPLE__)
52 #include <Security/Security.h>
53 #endif
54
55 #include <mbedtls/ctr_drbg.h>
56 #include <mbedtls/md5.h>
57 #include <mbedtls/base64.h>
58 #define MD5_DIGEST_LENGTH 16
59
60 #elif defined(USE_POLARSSL)
61 #include <polarssl/havege.h>
62 #include <polarssl/md5.h>
63 #include <polarssl/base64.h>
64 #define MD5_DIGEST_LENGTH 16
65
66 static const char *my_dhm_P =
67 "E4004C1F94182000103D883A448B3F80" \
68 "2CE4B44A83301270002C20D0321CFD00" \
69 "11CCEF784C26A400F43DFB901BCA7538" \
70 "F2C6B176001CF5A0FD16D2C48B1D0C1C" \
71 "F6AC8E1DA6BCC3B4E1F96B0564965300" \
72 "FFA1D0B601EB2800F489AA512C4B248C" \
73 "01F76949A60BB7F00A40B1EAB64BDD48" \
74 "E8A700D60B7F1200FA8E77B0A979DABF";
75
76 static const char *my_dhm_G = "4";
77 #elif defined(USE_GNUTLS)
78 #include <gnutls/gnutls.h>
79 #define MD5_DIGEST_LENGTH 16
80 #include <nettle/base64.h>
81 #include <nettle/md5.h>
82 #else /* USE_OPENSSL */
83 #include <openssl/ssl.h>
84 #include <openssl/rc4.h>
85 #include <openssl/md5.h>
86 #include <openssl/bio.h>
87 #include <openssl/buffer.h>
88 #endif
89
90 #endif
91
92 #define RTMP_SIG_SIZE 1536
93 #define RTMP_LARGE_HEADER_SIZE 12
94
95 static const int packetSize[] = { 12, 8, 4, 1 };
96
97 int RTMP_ctrlC;
98
99 const char RTMPProtocolStrings[][7] =
100 {
101 "RTMP",
102 "RTMPT",
103 "RTMPE",
104 "RTMPTE",
105 "RTMPS",
106 "RTMPTS",
107 "",
108 "",
109 "RTMFP"
110 };
111
112 const char RTMPProtocolStringsLower[][7] =
113 {
114 "rtmp",
115 "rtmpt",
116 "rtmpe",
117 "rtmpte",
118 "rtmps",
119 "rtmpts",
120 "",
121 "",
122 "rtmfp"
123 };
124
125 static const char *RTMPT_cmds[] =
126 {
127 "open",
128 "send",
129 "idle",
130 "close"
131 };
132
133 typedef enum
134 {
135 RTMPT_OPEN=0, RTMPT_SEND, RTMPT_IDLE, RTMPT_CLOSE
136 } RTMPTCmd;
137
138 static int DumpMetaData(AMFObject *obj);
139 static int HandShake(RTMP *r, int FP9HandShake);
140 static int SocksNegotiate(RTMP *r);
141
142 static int SendConnectPacket(RTMP *r, RTMPPacket *cp);
143 static int SendCheckBW(RTMP *r);
144 static int SendCheckBWResult(RTMP *r, double txn);
145 static int SendDeleteStream(RTMP *r, double dStreamId);
146 static int SendFCSubscribe(RTMP *r, AVal *subscribepath);
147 static int SendPlay(RTMP *r, int streamIdx);
148 static int SendBytesReceived(RTMP *r);
149 static int SendUsherToken(RTMP *r, AVal *usherToken);
150 static int SendFCUnpublish(RTMP *r, int streamIdx);
151
152 #if 0 /* unused */
153 static int SendBGHasStream(RTMP *r, double dId, AVal *playpath);
154 #endif
155
156 static int HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize);
157 static int HandleMetadata(RTMP *r, char *body, unsigned int len);
158 static void HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet);
159 static void HandleAudio(RTMP *r, const RTMPPacket *packet);
160 static void HandleVideo(RTMP *r, const RTMPPacket *packet);
161 static void HandleCtrl(RTMP *r, const RTMPPacket *packet);
162 static void HandleServerBW(RTMP *r, const RTMPPacket *packet);
163 static void HandleClientBW(RTMP *r, const RTMPPacket *packet);
164
165 static int ReadN(RTMP *r, char *buffer, int n);
166 static int WriteN(RTMP *r, const char *buffer, int n);
167
168 static void DecodeTEA(AVal *key, AVal *text);
169
170 static int HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len);
171 static int HTTP_read(RTMP *r, int fill);
172
173 #if !defined(_WIN32) && !defined(_DEBUG)
174 static int clk_tck;
175 #endif
176
177 #ifdef CRYPTO
178 #include "handshake.h"
179 #endif
180
181 uint32_t
RTMP_GetTime()182 RTMP_GetTime()
183 {
184 #ifdef _DEBUG
185 return 0;
186 #elif defined(_WIN32)
187 return timeGetTime();
188 #else
189 struct tms t;
190 if (!clk_tck) clk_tck = sysconf(_SC_CLK_TCK);
191 return times(&t) * 1000 / clk_tck;
192 #endif
193 }
194
195 const char *
socketerror(int err)196 socketerror(int err)
197 {
198 static char buff[1024];
199
200 #ifdef _WIN32
201 if (FormatMessageA (FORMAT_MESSAGE_FROM_SYSTEM, NULL, err, 0, buff, sizeof(buff), NULL))
202 {
203 int i, len;
204 buff[sizeof(buff)-1] = '\0';
205 len = (int)strlen (buff);
206 for (i = 0; i < len; i++)
207 {
208 if (buff[i] == '\r' || buff[i] == '\n')
209 {
210 memmove (buff + i, buff + i + 1, len - i);
211 i--;
212 len--;
213 }
214 }
215 return buff;
216 }
217 #else
218 (void)err;
219 #endif
220
221 strcpy (buff, "unknown error");
222 return buff;
223 }
224
225 void
RTMP_UserInterrupt()226 RTMP_UserInterrupt()
227 {
228 RTMP_ctrlC = TRUE;
229 }
230
231 void
RTMPPacket_Reset(RTMPPacket * p)232 RTMPPacket_Reset(RTMPPacket *p)
233 {
234 p->m_headerType = 0;
235 p->m_packetType = 0;
236 p->m_nChannel = 0;
237 p->m_nTimeStamp = 0;
238 p->m_nInfoField2 = 0;
239 p->m_hasAbsTimestamp = FALSE;
240 p->m_nBodySize = 0;
241 p->m_nBytesRead = 0;
242 }
243
244 int
RTMPPacket_Alloc(RTMPPacket * p,uint32_t nSize)245 RTMPPacket_Alloc(RTMPPacket *p, uint32_t nSize)
246 {
247 char *ptr;
248 #if ARCH_BITS == 32
249 if (nSize > SIZE_MAX - RTMP_MAX_HEADER_SIZE)
250 return FALSE;
251 #endif
252
253 ptr = calloc(1, nSize + RTMP_MAX_HEADER_SIZE);
254 if (!ptr)
255 return FALSE;
256 p->m_body = ptr + RTMP_MAX_HEADER_SIZE;
257 p->m_nBytesRead = 0;
258 return TRUE;
259 }
260
261 void
RTMPPacket_Free(RTMPPacket * p)262 RTMPPacket_Free(RTMPPacket *p)
263 {
264 if (p->m_body)
265 {
266 free(p->m_body - RTMP_MAX_HEADER_SIZE);
267 p->m_body = NULL;
268 }
269 }
270
271 void
RTMPPacket_Dump(RTMPPacket * p)272 RTMPPacket_Dump(RTMPPacket *p)
273 {
274 RTMP_Log(RTMP_LOGDEBUG,
275 "RTMP PACKET: packet type: 0x%02x. channel: 0x%02x. info 1: %d info 2: %d. Body size: %u. body: 0x%02x",
276 p->m_packetType, p->m_nChannel, p->m_nTimeStamp, p->m_nInfoField2,
277 p->m_nBodySize, p->m_body ? (unsigned char)p->m_body[0] : 0);
278 }
279
280 int
RTMP_LibVersion()281 RTMP_LibVersion()
282 {
283 return RTMP_LIB_VERSION;
284 }
285
286 void
RTMP_TLS_LoadCerts(RTMP * r)287 RTMP_TLS_LoadCerts(RTMP *r) {
288 #ifdef USE_MBEDTLS
289 mbedtls_x509_crt *chain = r->RTMP_TLS_ctx->cacert = calloc(1, sizeof(struct mbedtls_x509_crt));
290 mbedtls_x509_crt_init(chain);
291
292 #if defined(_WIN32)
293 HCERTSTORE hCertStore;
294 PCCERT_CONTEXT pCertContext = NULL;
295
296 if (!(hCertStore = CertOpenSystemStore((HCRYPTPROV)NULL, L"ROOT"))) {
297 goto error;
298 }
299
300 while (pCertContext = CertEnumCertificatesInStore(hCertStore, pCertContext)) {
301 mbedtls_x509_crt_parse_der(chain,
302 (unsigned char *)pCertContext->pbCertEncoded,
303 pCertContext->cbCertEncoded);
304 }
305
306 CertFreeCertificateContext(pCertContext);
307 CertCloseStore(hCertStore, 0);
308 #elif defined(__APPLE__)
309 SecKeychainRef keychain_ref;
310 CFMutableDictionaryRef search_settings_ref;
311 CFArrayRef result_ref;
312
313 if (SecKeychainOpen("/System/Library/Keychains/SystemRootCertificates.keychain",
314 &keychain_ref)
315 != errSecSuccess) {
316 goto error;
317 }
318
319 search_settings_ref = CFDictionaryCreateMutable(NULL, 0, NULL, NULL);
320 CFDictionarySetValue(search_settings_ref, kSecClass, kSecClassCertificate);
321 CFDictionarySetValue(search_settings_ref, kSecMatchLimit, kSecMatchLimitAll);
322 CFDictionarySetValue(search_settings_ref, kSecReturnRef, kCFBooleanTrue);
323 CFDictionarySetValue(search_settings_ref, kSecMatchSearchList,
324 CFArrayCreate(NULL, (const void **)&keychain_ref, 1, NULL));
325
326 if (SecItemCopyMatching(search_settings_ref, (CFTypeRef *)&result_ref)
327 != errSecSuccess) {
328 goto error;
329 }
330
331 for (CFIndex i = 0; i < CFArrayGetCount(result_ref); i++) {
332 SecCertificateRef item_ref = (SecCertificateRef)
333 CFArrayGetValueAtIndex(result_ref, i);
334 CFDataRef data_ref;
335
336 if ((data_ref = SecCertificateCopyData(item_ref))) {
337 mbedtls_x509_crt_parse_der(chain,
338 (unsigned char *)CFDataGetBytePtr(data_ref),
339 CFDataGetLength(data_ref));
340 CFRelease(data_ref);
341 }
342 }
343
344 CFRelease(keychain_ref);
345 #elif defined(__linux__)
346 if (mbedtls_x509_crt_parse_path(chain, "/etc/ssl/certs/") < 0) {
347 RTMP_Log(RTMP_LOGERROR, "mbedtls_x509_crt_parse_path: Couldn't parse "
348 "/etc/ssl/certs");
349 goto error;
350 }
351 #elif defined(__OpenBSD__)
352 if (mbedtls_x509_crt_parse_file(chain, "/etc/ssl/cert.pem") < 0) {
353 RTMP_Log(RTMP_LOGERROR, "mbedtls_x509_crt_parse_file: Couldn't parse "
354 "/etc/ssl/cert.pem");
355 goto error;
356 }
357 #endif
358
359 mbedtls_ssl_conf_ca_chain(&r->RTMP_TLS_ctx->conf, chain, NULL);
360 return;
361
362 error:
363 RTMP_Log(RTMP_LOGERROR, "RTMP_TLS_LoadCerts: Failed to load "
364 "root certificate chains, RTMPS connections will likely "
365 "fail");
366 mbedtls_x509_crt_free(chain);
367 free(chain);
368 r->RTMP_TLS_ctx->cacert = NULL;
369 #else /* USE_MBEDTLS */
370 UNUSED_PARAMETER(r);
371 #endif /* USE_MBEDTLS */
372 }
373
374 void
RTMP_TLS_Init(RTMP * r)375 RTMP_TLS_Init(RTMP *r)
376 {
377 #ifdef CRYPTO
378 #if defined(USE_MBEDTLS)
379 const char * pers = "RTMP_TLS";
380 r->RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
381
382 mbedtls_ssl_config_init(&r->RTMP_TLS_ctx->conf);
383 mbedtls_ctr_drbg_init(&r->RTMP_TLS_ctx->ctr_drbg);
384 mbedtls_entropy_init(&r->RTMP_TLS_ctx->entropy);
385
386 mbedtls_ctr_drbg_seed(&r->RTMP_TLS_ctx->ctr_drbg,
387 mbedtls_entropy_func,
388 &r->RTMP_TLS_ctx->entropy,
389 (const unsigned char *)pers,
390 strlen(pers));
391
392 RTMP_TLS_LoadCerts(r);
393 #elif defined(USE_POLARSSL)
394 /* Do this regardless of NO_SSL, we use havege for rtmpe too */
395 RTMP_TLS_ctx = calloc(1,sizeof(struct tls_ctx));
396 havege_init(&RTMP_TLS_ctx->hs);
397 #elif defined(USE_GNUTLS) && !defined(NO_SSL)
398 /* Technically we need to initialize libgcrypt ourselves if
399 * we're not going to call gnutls_global_init(). Ignoring this
400 * for now.
401 */
402 gnutls_global_init();
403 RTMP_TLS_ctx = malloc(sizeof(struct tls_ctx));
404 gnutls_certificate_allocate_credentials(&RTMP_TLS_ctx->cred);
405 gnutls_priority_init(&RTMP_TLS_ctx->prios, "NORMAL", NULL);
406 gnutls_certificate_set_x509_trust_file(RTMP_TLS_ctx->cred,
407 "ca.pem", GNUTLS_X509_FMT_PEM);
408 #elif !defined(NO_SSL) /* USE_OPENSSL */
409 /* libcrypto doesn't need anything special */
410 SSL_load_error_strings();
411 SSL_library_init();
412 OpenSSL_add_all_digests();
413 RTMP_TLS_ctx = SSL_CTX_new(SSLv23_method());
414 SSL_CTX_set_options(RTMP_TLS_ctx, SSL_OP_ALL);
415 SSL_CTX_set_default_verify_paths(RTMP_TLS_ctx);
416 #endif
417 #else
418 UNUSED_PARAMETER(r);
419 #endif
420 }
421
422 void
RTMP_TLS_Free(RTMP * r)423 RTMP_TLS_Free(RTMP *r) {
424 #ifdef USE_MBEDTLS
425
426 if (!r->RTMP_TLS_ctx)
427 return;
428 mbedtls_ssl_config_free(&r->RTMP_TLS_ctx->conf);
429 mbedtls_ctr_drbg_free(&r->RTMP_TLS_ctx->ctr_drbg);
430 mbedtls_entropy_free(&r->RTMP_TLS_ctx->entropy);
431
432 if (r->RTMP_TLS_ctx->cacert) {
433 mbedtls_x509_crt_free(r->RTMP_TLS_ctx->cacert);
434 free(r->RTMP_TLS_ctx->cacert);
435 r->RTMP_TLS_ctx->cacert = NULL;
436 }
437
438 // NO mbedtls_net_free() BECAUSE WE SET IT UP BY HAND!
439 free(r->RTMP_TLS_ctx);
440 r->RTMP_TLS_ctx = NULL;
441 #else
442 UNUSED_PARAMETER(r);
443 #endif
444 }
445
446 RTMP *
RTMP_Alloc()447 RTMP_Alloc()
448 {
449 return calloc(1, sizeof(RTMP));
450 }
451
452 void
RTMP_Free(RTMP * r)453 RTMP_Free(RTMP *r)
454 {
455 #if defined(CRYPTO) && defined(USE_MBEDTLS)
456 RTMP_TLS_Free(r);
457 #endif
458 free(r);
459 }
460
461 void
RTMP_Init(RTMP * r)462 RTMP_Init(RTMP *r)
463 {
464 memset(r, 0, sizeof(RTMP));
465 r->m_sb.sb_socket = -1;
466 RTMP_Reset(r);
467
468 #ifdef CRYPTO
469 RTMP_TLS_Init(r);
470 #endif
471
472 }
473
474 void
RTMP_Reset(RTMP * r)475 RTMP_Reset(RTMP *r)
476 {
477 r->m_inChunkSize = RTMP_DEFAULT_CHUNKSIZE;
478 r->m_outChunkSize = RTMP_DEFAULT_CHUNKSIZE;
479 r->m_bSendChunkSizeInfo = 1;
480 r->m_nBufferMS = 30000;
481 r->m_nClientBW = 2500000;
482 r->m_nClientBW2 = 2;
483 r->m_nServerBW = 2500000;
484 r->m_fAudioCodecs = 3191.0;
485 r->m_fVideoCodecs = 252.0;
486 r->Link.curStreamIdx = 0;
487 r->Link.nStreams = 0;
488 r->Link.timeout = 30;
489 r->Link.swfAge = 30;
490 }
491
492 void
RTMP_EnableWrite(RTMP * r)493 RTMP_EnableWrite(RTMP *r)
494 {
495 r->Link.protocol |= RTMP_FEATURE_WRITE;
496 }
497
498 double
RTMP_GetDuration(RTMP * r)499 RTMP_GetDuration(RTMP *r)
500 {
501 return r->m_fDuration;
502 }
503
504 int
RTMP_IsConnected(RTMP * r)505 RTMP_IsConnected(RTMP *r)
506 {
507 return r->m_sb.sb_socket != INVALID_SOCKET;
508 }
509
510 SOCKET
RTMP_Socket(RTMP * r)511 RTMP_Socket(RTMP *r)
512 {
513 return r->m_sb.sb_socket;
514 }
515
516 int
RTMP_IsTimedout(RTMP * r)517 RTMP_IsTimedout(RTMP *r)
518 {
519 return r->m_sb.sb_timedout;
520 }
521
522 void
RTMP_SetBufferMS(RTMP * r,int size)523 RTMP_SetBufferMS(RTMP *r, int size)
524 {
525 r->m_nBufferMS = size;
526 }
527
528 void
RTMP_UpdateBufferMS(RTMP * r)529 RTMP_UpdateBufferMS(RTMP *r)
530 {
531 RTMP_SendCtrl(r, 3, r->m_stream_id, r->m_nBufferMS);
532 }
533
534 #undef OSS
535 #ifdef _WIN32
536 #define OSS "WIN"
537 #elif defined(__sun__)
538 #define OSS "SOL"
539 #elif defined(__APPLE__)
540 #define OSS "MAC"
541 #elif defined(__linux__)
542 #define OSS "LNX"
543 #else
544 #define OSS "GNU"
545 #endif
546 #define DEF_VERSTR OSS " 10,0,32,18"
547 static const char DEFAULT_FLASH_VER[] = DEF_VERSTR;
548 const AVal RTMP_DefaultFlashVer =
549 { (char *)DEFAULT_FLASH_VER, sizeof(DEFAULT_FLASH_VER) - 1 };
550
551 static void
SocksSetup(RTMP * r,AVal * sockshost)552 SocksSetup(RTMP *r, AVal *sockshost)
553 {
554 if (sockshost->av_len)
555 {
556 const char *socksport = strchr(sockshost->av_val, ':');
557 char *hostname = strdup(sockshost->av_val);
558
559 if (socksport)
560 hostname[socksport - sockshost->av_val] = '\0';
561 r->Link.sockshost.av_val = hostname;
562 r->Link.sockshost.av_len = (int)strlen(hostname);
563
564 r->Link.socksport = socksport ? atoi(socksport + 1) : 1080;
565 RTMP_Log(RTMP_LOGDEBUG, "Connecting via SOCKS proxy: %s:%d", r->Link.sockshost.av_val,
566 r->Link.socksport);
567 }
568 else
569 {
570 r->Link.sockshost.av_val = NULL;
571 r->Link.sockshost.av_len = 0;
572 r->Link.socksport = 0;
573 }
574 }
575
576 static int
parseAMF(AMFObject * obj,AVal * av,int * depth)577 parseAMF(AMFObject *obj, AVal *av, int *depth)
578 {
579 AMFObjectProperty prop = {{0,0}};
580 int i;
581 char *p, *arg = av->av_val;
582
583 if (arg[1] == ':')
584 {
585 p = (char *)arg+2;
586 switch(arg[0])
587 {
588 case 'B':
589 prop.p_type = AMF_BOOLEAN;
590 prop.p_vu.p_number = atoi(p);
591 break;
592 case 'S':
593 prop.p_type = AMF_STRING;
594 prop.p_vu.p_aval.av_val = p;
595 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
596 break;
597 case 'N':
598 prop.p_type = AMF_NUMBER;
599 prop.p_vu.p_number = strtod(p, NULL);
600 break;
601 case 'Z':
602 prop.p_type = AMF_NULL;
603 break;
604 case 'O':
605 i = atoi(p);
606 if (i)
607 {
608 prop.p_type = AMF_OBJECT;
609 }
610 else
611 {
612 (*depth)--;
613 return 0;
614 }
615 break;
616 default:
617 return -1;
618 }
619 }
620 else if (arg[2] == ':' && arg[0] == 'N')
621 {
622 p = strchr(arg+3, ':');
623 if (!p || !*depth)
624 return -1;
625 prop.p_name.av_val = (char *)arg+3;
626 prop.p_name.av_len = p - (arg+3);
627
628 p++;
629 switch(arg[1])
630 {
631 case 'B':
632 prop.p_type = AMF_BOOLEAN;
633 prop.p_vu.p_number = atoi(p);
634 break;
635 case 'S':
636 prop.p_type = AMF_STRING;
637 prop.p_vu.p_aval.av_val = p;
638 prop.p_vu.p_aval.av_len = av->av_len - (p-arg);
639 break;
640 case 'N':
641 prop.p_type = AMF_NUMBER;
642 prop.p_vu.p_number = strtod(p, NULL);
643 break;
644 case 'O':
645 prop.p_type = AMF_OBJECT;
646 break;
647 default:
648 return -1;
649 }
650 }
651 else
652 return -1;
653
654 if (*depth)
655 {
656 AMFObject *o2;
657 for (i=0; i<*depth; i++)
658 {
659 o2 = &obj->o_props[obj->o_num-1].p_vu.p_object;
660 obj = o2;
661 }
662 }
663 AMF_AddProp(obj, &prop);
664 if (prop.p_type == AMF_OBJECT)
665 (*depth)++;
666 return 0;
667 }
668
RTMP_SetupURL(RTMP * r,char * url)669 int RTMP_SetupURL(RTMP *r, char *url)
670 {
671 int ret, len;
672 unsigned int port = 0;
673
674 len = (int)strlen(url);
675 ret = RTMP_ParseURL(url, &r->Link.protocol, &r->Link.hostname,
676 &port, &r->Link.app);
677 if (!ret)
678 return ret;
679 r->Link.port = port;
680
681 if (!r->Link.tcUrl.av_len)
682 {
683 r->Link.tcUrl.av_val = url;
684 if (r->Link.app.av_len)
685 {
686 if (r->Link.app.av_val < url + len)
687 {
688 /* if app is part of original url, just use it */
689 r->Link.tcUrl.av_len = r->Link.app.av_len + (r->Link.app.av_val - url);
690 }
691 else
692 {
693 len = r->Link.hostname.av_len + r->Link.app.av_len +
694 sizeof("rtmpte://:65535/");
695 r->Link.tcUrl.av_val = malloc(len);
696 r->Link.tcUrl.av_len = snprintf(r->Link.tcUrl.av_val, len,
697 "%s://%.*s:%d/%.*s",
698 RTMPProtocolStringsLower[r->Link.protocol],
699 r->Link.hostname.av_len, r->Link.hostname.av_val,
700 r->Link.port,
701 r->Link.app.av_len, r->Link.app.av_val);
702 r->Link.lFlags |= RTMP_LF_FTCU;
703 }
704 }
705 else
706 {
707 r->Link.tcUrl.av_len = (int)strlen(url);
708 }
709 }
710
711 #ifdef CRYPTO
712 if ((r->Link.lFlags & RTMP_LF_SWFV) && r->Link.swfUrl.av_len)
713 #ifdef USE_HASHSWF
714 RTMP_HashSWF(r->Link.swfUrl.av_val, &r->Link.SWFSize,
715 (unsigned char *)r->Link.SWFHash, r->Link.swfAge);
716 #else
717 return FALSE;
718 #endif
719 #endif
720
721 SocksSetup(r, &r->Link.sockshost);
722
723 if (r->Link.port == 0)
724 {
725 if (r->Link.protocol & RTMP_FEATURE_SSL)
726 r->Link.port = 443;
727 else if (r->Link.protocol & RTMP_FEATURE_HTTP)
728 r->Link.port = 80;
729 else
730 r->Link.port = 1935;
731 }
732 return TRUE;
733 }
734
RTMP_AddStream(RTMP * r,const char * playpath)735 int RTMP_AddStream(RTMP *r, const char *playpath)
736 {
737 int idx = -1;
738 AVal pp = { (char*)playpath, playpath?(int)strlen(playpath):0 };
739
740 RTMP_ParsePlaypath(&pp, &r->Link.streams[r->Link.nStreams].playpath);
741 r->Link.streams[r->Link.nStreams].id = -1;
742
743 idx = r->Link.nStreams;
744 r->Link.nStreams++;
745
746 return idx;
747 }
748
749 static int
add_addr_info(struct sockaddr_storage * service,socklen_t * addrlen,AVal * host,int port,socklen_t addrlen_hint,int * socket_error)750 add_addr_info(struct sockaddr_storage *service, socklen_t *addrlen, AVal *host, int port, socklen_t addrlen_hint, int *socket_error)
751 {
752 char *hostname;
753 int ret = TRUE;
754 if (host->av_val[host->av_len] || host->av_val[0] == '[')
755 {
756 int v6 = host->av_val[0] == '[';
757 hostname = malloc(host->av_len+1 - v6 * 2);
758 memcpy(hostname, host->av_val + v6, host->av_len - v6 * 2);
759 hostname[host->av_len - v6 * 2] = '\0';
760 }
761 else
762 {
763 hostname = host->av_val;
764 }
765
766 struct addrinfo hints;
767 struct addrinfo *result = NULL;
768 struct addrinfo *ptr = NULL;
769
770 memset(&hints, 0, sizeof(hints));
771
772 hints.ai_family = AF_UNSPEC;
773 hints.ai_socktype = SOCK_STREAM;
774 hints.ai_protocol = IPPROTO_TCP;
775
776 service->ss_family = AF_UNSPEC;
777 *addrlen = 0;
778
779 char portStr[8];
780
781 sprintf(portStr, "%d", port);
782
783 int err = getaddrinfo(hostname, portStr, &hints, &result);
784
785 if (err)
786 {
787 #ifndef _WIN32
788 #define gai_strerrorA gai_strerror
789 #endif
790 RTMP_Log(RTMP_LOGERROR, "Could not resolve %s: %s (%d)", hostname, gai_strerrorA(GetSockError()), GetSockError());
791 *socket_error = GetSockError();
792 ret = FALSE;
793 goto finish;
794 }
795
796 // prefer ipv4 results, since lots of ISPs have broken ipv6 connectivity
797 for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
798 {
799 if (ptr->ai_family == AF_INET && (!addrlen_hint || ptr->ai_addrlen == addrlen_hint))
800 {
801 memcpy(service, ptr->ai_addr, ptr->ai_addrlen);
802 *addrlen = (socklen_t)ptr->ai_addrlen;
803 break;
804 }
805 }
806
807 if (!*addrlen)
808 {
809 for (ptr = result; ptr != NULL; ptr = ptr->ai_next)
810 {
811 if (ptr->ai_family == AF_INET6 && (!addrlen_hint || ptr->ai_addrlen == addrlen_hint))
812 {
813 memcpy(service, ptr->ai_addr, ptr->ai_addrlen);
814 *addrlen = (socklen_t)ptr->ai_addrlen;
815 break;
816 }
817 }
818 }
819
820 freeaddrinfo(result);
821
822 if (service->ss_family == AF_UNSPEC || *addrlen == 0)
823 {
824 // since we're handling multiple addresses internally, fake the correct error response
825 #ifdef _WIN32
826 *socket_error = WSANO_DATA;
827 #elif __FreeBSD__
828 *socket_error = ENOATTR;
829 #elif defined(ENODATA)
830 *socket_error = ENODATA;
831 #else
832 *socket_error = EAFNOSUPPORT;
833 #endif
834
835 RTMP_Log(RTMP_LOGERROR, "Could not resolve server '%s': no valid address found", hostname);
836 ret = FALSE;
837 goto finish;
838 }
839
840 finish:
841 if (hostname != host->av_val)
842 free(hostname);
843 return ret;
844 }
845
846 #ifdef _WIN32
847 #define E_TIMEDOUT WSAETIMEDOUT
848 #define E_CONNREFUSED WSAECONNREFUSED
849 #define E_ACCES WSAEACCES
850 #else
851 #define E_TIMEDOUT ETIMEDOUT
852 #define E_CONNREFUSED ECONNREFUSED
853 #define E_ACCES EACCES
854 #endif
855
856 int
RTMP_Connect0(RTMP * r,struct sockaddr * service,socklen_t addrlen)857 RTMP_Connect0(RTMP *r, struct sockaddr * service, socklen_t addrlen)
858 {
859 int on = 1;
860 r->m_sb.sb_timedout = FALSE;
861 r->m_pausing = 0;
862 r->m_fDuration = 0.0;
863
864 //best to be explicit, we need overlapped socket
865 #ifdef _WIN32
866 r->m_sb.sb_socket = WSASocket(service->sa_family, SOCK_STREAM, IPPROTO_TCP, NULL, 0, WSA_FLAG_OVERLAPPED);
867 #else
868 r->m_sb.sb_socket = socket(service->sa_family, SOCK_STREAM, IPPROTO_TCP);
869 #endif
870
871 if (r->m_sb.sb_socket != INVALID_SOCKET)
872 {
873 #ifndef _WIN32
874 #ifdef SO_NOSIGPIPE
875 setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_NOSIGPIPE, &(int){ 1 }, sizeof(int));
876 #endif
877 #endif
878 if(r->m_bindIP.addrLen)
879 {
880 if (bind(r->m_sb.sb_socket, (const struct sockaddr *)&r->m_bindIP.addr, r->m_bindIP.addrLen) < 0)
881 {
882 int err = GetSockError();
883 RTMP_Log(RTMP_LOGERROR, "%s, failed to bind socket: %s (%d)",
884 __FUNCTION__, socketerror(err), err);
885 r->last_error_code = err;
886 RTMP_Close(r);
887 return FALSE;
888 }
889 }
890
891 uint64_t connect_start = os_gettime_ns();
892
893 if (connect(r->m_sb.sb_socket, service, addrlen) < 0)
894 {
895 int err = GetSockError();
896 if (err == E_CONNREFUSED)
897 RTMP_Log(RTMP_LOGERROR, "%s is offline. Try a different server (ECONNREFUSED).", r->Link.hostname.av_val);
898 else if (err == E_ACCES)
899 RTMP_Log(RTMP_LOGERROR, "The connection is being blocked by a firewall or other security software (EACCES).");
900 else if (err == E_TIMEDOUT)
901 RTMP_Log(RTMP_LOGERROR, "The connection timed out. Try a different server, or check that the connection is not being blocked by a firewall or other security software (ETIMEDOUT).");
902 else
903 RTMP_Log(RTMP_LOGERROR, "%s, failed to connect socket: %s (%d)",
904 __FUNCTION__, socketerror(err), err);
905 r->last_error_code = err;
906 RTMP_Close(r);
907 return FALSE;
908 }
909
910 r->connect_time_ms = (int)((os_gettime_ns() - connect_start) / 1000000);
911
912 if (r->Link.socksport)
913 {
914 RTMP_Log(RTMP_LOGDEBUG, "%s ... SOCKS negotiation", __FUNCTION__);
915 if (!SocksNegotiate(r))
916 {
917 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS negotiation failed.", __FUNCTION__);
918 RTMP_Close(r);
919 return FALSE;
920 }
921 }
922 }
923 else
924 {
925 RTMP_Log(RTMP_LOGERROR, "%s, failed to create socket. Error: %d", __FUNCTION__,
926 GetSockError());
927 return FALSE;
928 }
929
930 /* set timeout */
931 {
932 SET_RCVTIMEO(tv, r->Link.timeout);
933 if (setsockopt
934 (r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)))
935 {
936 RTMP_Log(RTMP_LOGERROR, "%s, Setting socket timeout to %ds failed!",
937 __FUNCTION__, r->Link.timeout);
938 }
939 }
940
941 if(!r->m_bUseNagle)
942 setsockopt(r->m_sb.sb_socket, IPPROTO_TCP, TCP_NODELAY, (char *) &on, sizeof(on));
943
944 return TRUE;
945 }
946
947 int
RTMP_Connect1(RTMP * r,RTMPPacket * cp)948 RTMP_Connect1(RTMP *r, RTMPPacket *cp)
949 {
950 if (r->Link.protocol & RTMP_FEATURE_SSL)
951 {
952 #if defined(CRYPTO) && !defined(NO_SSL)
953 TLS_client(r->RTMP_TLS_ctx, r->m_sb.sb_ssl);
954
955 #if defined(USE_MBEDTLS)
956 mbedtls_net_context *server_fd = &r->RTMP_TLS_ctx->net;
957 server_fd->fd = r->m_sb.sb_socket;
958 TLS_setfd(r->m_sb.sb_ssl, server_fd);
959
960 // make sure we verify the certificate hostname
961 char hostname[MBEDTLS_SSL_MAX_HOST_NAME_LEN + 1];
962
963 if (r->Link.hostname.av_len >= MBEDTLS_SSL_MAX_HOST_NAME_LEN)
964 return FALSE;
965
966 memcpy(hostname, r->Link.hostname.av_val, r->Link.hostname.av_len);
967 hostname[r->Link.hostname.av_len] = 0;
968
969 if (mbedtls_ssl_set_hostname(r->m_sb.sb_ssl, hostname))
970 return FALSE;
971 #else
972 TLS_setfd(r->m_sb.sb_ssl, r->m_sb.sb_socket);
973 #endif
974
975 int connect_return = TLS_connect(r->m_sb.sb_ssl);
976 if (connect_return < 0)
977 {
978 #if defined(USE_MBEDTLS)
979 r->last_error_code = connect_return;
980 if (connect_return == MBEDTLS_ERR_X509_CERT_VERIFY_FAILED)
981 {
982 // show a more detailed error in the log if possible
983 int verify_result = mbedtls_ssl_get_verify_result(r->m_sb.sb_ssl);
984 if (verify_result)
985 {
986 char err[256], *e;
987 if (mbedtls_x509_crt_verify_info(err, sizeof(err), "", verify_result) > 0)
988 {
989 e = strchr(err, '\n');
990 if (e)
991 *e = '\0';
992 }
993 else
994 {
995 strcpy(err, "unknown error");
996 }
997 RTMP_Log(RTMP_LOGERROR, "%s, Cert verify failed: %d (%s)", __FUNCTION__, verify_result, err);
998 RTMP_Close(r);
999 return FALSE;
1000 }
1001 }
1002 #endif
1003 // output the error in a format that matches mbedTLS
1004 connect_return = abs(connect_return);
1005 RTMP_Log(RTMP_LOGERROR, "%s, TLS_Connect failed: -0x%x", __FUNCTION__, connect_return);
1006 RTMP_Close(r);
1007 return FALSE;
1008 }
1009 #else
1010 RTMP_Log(RTMP_LOGERROR, "%s, no SSL/TLS support", __FUNCTION__);
1011 RTMP_Close(r);
1012 return FALSE;
1013 #endif
1014 }
1015 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1016 {
1017 r->m_msgCounter = 1;
1018 r->m_clientID.av_val = NULL;
1019 r->m_clientID.av_len = 0;
1020 HTTP_Post(r, RTMPT_OPEN, "", 1);
1021 if (HTTP_read(r, 1) != 0)
1022 {
1023 r->m_msgCounter = 0;
1024 RTMP_Log(RTMP_LOGDEBUG, "%s, Could not connect for handshake", __FUNCTION__);
1025 RTMP_Close(r);
1026 return 0;
1027 }
1028 r->m_msgCounter = 0;
1029 }
1030 RTMP_Log(RTMP_LOGDEBUG, "%s, ... connected, handshaking", __FUNCTION__);
1031 if (!HandShake(r, TRUE))
1032 {
1033 RTMP_Log(RTMP_LOGERROR, "%s, handshake failed.", __FUNCTION__);
1034 RTMP_Close(r);
1035 return FALSE;
1036 }
1037 RTMP_Log(RTMP_LOGDEBUG, "%s, handshaked", __FUNCTION__);
1038
1039 if (!SendConnectPacket(r, cp))
1040 {
1041 RTMP_Log(RTMP_LOGERROR, "%s, RTMP connect failed.", __FUNCTION__);
1042 RTMP_Close(r);
1043 return FALSE;
1044 }
1045 return TRUE;
1046 }
1047
1048 int
RTMP_Connect(RTMP * r,RTMPPacket * cp)1049 RTMP_Connect(RTMP *r, RTMPPacket *cp)
1050 {
1051 #ifdef _WIN32
1052 HOSTENT *h;
1053 #endif
1054 struct sockaddr_storage service;
1055 socklen_t addrlen = 0;
1056 socklen_t addrlen_hint = 0;
1057 int socket_error = 0;
1058
1059 if (!r->Link.hostname.av_len)
1060 return FALSE;
1061
1062 #ifdef _WIN32
1063 //COMODO security software sandbox blocks all DNS by returning "host not found"
1064 h = gethostbyname("localhost");
1065 if (!h && GetLastError() == WSAHOST_NOT_FOUND)
1066 {
1067 r->last_error_code = WSAHOST_NOT_FOUND;
1068 RTMP_Log(RTMP_LOGERROR, "RTMP_Connect: Connection test failed. This error is likely caused by Comodo Internet Security running OBS in sandbox mode. Please add OBS to the Comodo automatic sandbox exclusion list, restart OBS and try again (11001).");
1069 return FALSE;
1070 }
1071 #endif
1072
1073 memset(&service, 0, sizeof(service));
1074
1075 if (r->m_bindIP.addrLen)
1076 addrlen_hint = r->m_bindIP.addrLen;
1077
1078 if (r->Link.socksport)
1079 {
1080 /* Connect via SOCKS */
1081 if (!add_addr_info(&service, &addrlen, &r->Link.sockshost, r->Link.socksport, addrlen_hint, &socket_error))
1082 {
1083 r->last_error_code = socket_error;
1084 return FALSE;
1085 }
1086 }
1087 else
1088 {
1089 /* Connect directly */
1090 if (!add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, addrlen_hint, &socket_error))
1091 {
1092 r->last_error_code = socket_error;
1093 return FALSE;
1094 }
1095 }
1096
1097 if (!RTMP_Connect0(r, (struct sockaddr *)&service, addrlen))
1098 return FALSE;
1099
1100 r->m_bSendCounter = TRUE;
1101
1102 return RTMP_Connect1(r, cp);
1103 }
1104
1105 static int
SocksNegotiate(RTMP * r)1106 SocksNegotiate(RTMP *r)
1107 {
1108 unsigned long addr;
1109 struct sockaddr_storage service;
1110 socklen_t addrlen = 0;
1111 int socket_error = 0;
1112 memset(&service, 0, sizeof(service));
1113
1114 add_addr_info(&service, &addrlen, &r->Link.hostname, r->Link.port, 0, &socket_error);
1115
1116 // not doing IPv6 socks
1117 if (service.ss_family == AF_INET6)
1118 return FALSE;
1119
1120 addr = htonl((*(struct sockaddr_in *)&service).sin_addr.s_addr);
1121
1122 {
1123 char packet[] =
1124 {
1125 4, 1, /* SOCKS 4, connect */
1126 (r->Link.port >> 8) & 0xFF,
1127 (r->Link.port) & 0xFF,
1128 (char)(addr >> 24) & 0xFF, (char)(addr >> 16) & 0xFF,
1129 (char)(addr >> 8) & 0xFF, (char)addr & 0xFF,
1130 0
1131 }; /* NULL terminate */
1132
1133 WriteN(r, packet, sizeof packet);
1134
1135 if (ReadN(r, packet, 8) != 8)
1136 return FALSE;
1137
1138 if (packet[0] == 0 && packet[1] == 90)
1139 {
1140 return TRUE;
1141 }
1142 else
1143 {
1144 RTMP_Log(RTMP_LOGERROR, "%s, SOCKS returned error code %d", __FUNCTION__, packet[1]);
1145 return FALSE;
1146 }
1147 }
1148 }
1149
1150 int
RTMP_ConnectStream(RTMP * r,int seekTime)1151 RTMP_ConnectStream(RTMP *r, int seekTime)
1152 {
1153 RTMPPacket packet = { 0 };
1154
1155 /* seekTime was already set by SetupStream / SetupURL.
1156 * This is only needed by ReconnectStream.
1157 */
1158 if (seekTime > 0)
1159 r->Link.seekTime = seekTime;
1160
1161 r->m_mediaChannel = 0;
1162
1163 while (!r->m_bPlaying && RTMP_IsConnected(r) && RTMP_ReadPacket(r, &packet))
1164 {
1165 if (RTMPPacket_IsReady(&packet))
1166 {
1167 if (!packet.m_nBodySize)
1168 continue;
1169 if ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) ||
1170 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO) ||
1171 (packet.m_packetType == RTMP_PACKET_TYPE_INFO))
1172 {
1173 RTMP_Log(RTMP_LOGWARNING, "Received FLV packet before play()! Ignoring.");
1174 RTMPPacket_Free(&packet);
1175 continue;
1176 }
1177
1178 RTMP_ClientPacket(r, &packet);
1179 RTMPPacket_Free(&packet);
1180 }
1181 }
1182
1183 return r->m_bPlaying;
1184 }
1185
1186 int
RTMP_ReconnectStream(RTMP * r,int seekTime,int streamIdx)1187 RTMP_ReconnectStream(RTMP *r, int seekTime, int streamIdx)
1188 {
1189 RTMP_DeleteStream(r, streamIdx);
1190
1191 RTMP_SendCreateStream(r);
1192
1193 return RTMP_ConnectStream(r, seekTime);
1194 }
1195
1196 int
RTMP_ToggleStream(RTMP * r)1197 RTMP_ToggleStream(RTMP *r)
1198 {
1199 int res;
1200
1201 if (!r->m_pausing)
1202 {
1203 if (RTMP_IsTimedout(r) && r->m_read.status == RTMP_READ_EOF)
1204 r->m_read.status = 0;
1205
1206 res = RTMP_SendPause(r, TRUE, r->m_pauseStamp);
1207 if (!res)
1208 return res;
1209
1210 r->m_pausing = 1;
1211 sleep(1);
1212 }
1213 res = RTMP_SendPause(r, FALSE, r->m_pauseStamp);
1214 r->m_pausing = 3;
1215 return res;
1216 }
1217
1218 void
RTMP_DeleteStream(RTMP * r,int streamIdx)1219 RTMP_DeleteStream(RTMP *r, int streamIdx)
1220 {
1221 if (r->m_stream_id < 0)
1222 return;
1223
1224 r->m_bPlaying = FALSE;
1225
1226 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
1227 SendFCUnpublish(r, streamIdx);
1228
1229 SendDeleteStream(r, r->m_stream_id);
1230 r->m_stream_id = -1;
1231 }
1232
1233 int
RTMP_GetNextMediaPacket(RTMP * r,RTMPPacket * packet)1234 RTMP_GetNextMediaPacket(RTMP *r, RTMPPacket *packet)
1235 {
1236 int bHasMediaPacket = 0;
1237
1238 while (!bHasMediaPacket && RTMP_IsConnected(r)
1239 && RTMP_ReadPacket(r, packet))
1240 {
1241 if (!RTMPPacket_IsReady(packet) || !packet->m_nBodySize)
1242 {
1243 continue;
1244 }
1245
1246 bHasMediaPacket = RTMP_ClientPacket(r, packet);
1247
1248 if (!bHasMediaPacket)
1249 {
1250 RTMPPacket_Free(packet);
1251 }
1252 else if (r->m_pausing == 3)
1253 {
1254 if (packet->m_nTimeStamp <= r->m_mediaStamp)
1255 {
1256 bHasMediaPacket = 0;
1257 #ifdef _DEBUG
1258 RTMP_Log(RTMP_LOGDEBUG,
1259 "Skipped type: %02X, size: %d, TS: %d ms, abs TS: %d, pause: %d ms",
1260 packet->m_packetType, packet->m_nBodySize,
1261 packet->m_nTimeStamp, packet->m_hasAbsTimestamp,
1262 r->m_mediaStamp);
1263 #endif
1264 RTMPPacket_Free(packet);
1265 continue;
1266 }
1267 r->m_pausing = 0;
1268 }
1269 }
1270
1271 if (bHasMediaPacket)
1272 r->m_bPlaying = TRUE;
1273 else if (r->m_sb.sb_timedout && !r->m_pausing)
1274 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
1275 r->m_channelTimestamp[r->m_mediaChannel] : 0;
1276
1277 return bHasMediaPacket;
1278 }
1279
1280 int
RTMP_ClientPacket(RTMP * r,RTMPPacket * packet)1281 RTMP_ClientPacket(RTMP *r, RTMPPacket *packet)
1282 {
1283 int bHasMediaPacket = 0;
1284 switch (packet->m_packetType)
1285 {
1286 case RTMP_PACKET_TYPE_CHUNK_SIZE:
1287 /* chunk size */
1288 HandleChangeChunkSize(r, packet);
1289 break;
1290
1291 case RTMP_PACKET_TYPE_BYTES_READ_REPORT:
1292 /* bytes read report */
1293 RTMP_Log(RTMP_LOGDEBUG, "%s, received: bytes read report", __FUNCTION__);
1294 break;
1295
1296 case RTMP_PACKET_TYPE_CONTROL:
1297 /* ctrl */
1298 HandleCtrl(r, packet);
1299 break;
1300
1301 case RTMP_PACKET_TYPE_SERVER_BW:
1302 /* server bw */
1303 HandleServerBW(r, packet);
1304 break;
1305
1306 case RTMP_PACKET_TYPE_CLIENT_BW:
1307 /* client bw */
1308 HandleClientBW(r, packet);
1309 break;
1310
1311 case RTMP_PACKET_TYPE_AUDIO:
1312 /* audio data */
1313 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: audio %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1314 HandleAudio(r, packet);
1315 bHasMediaPacket = 1;
1316 if (!r->m_mediaChannel)
1317 r->m_mediaChannel = packet->m_nChannel;
1318 if (!r->m_pausing)
1319 r->m_mediaStamp = packet->m_nTimeStamp;
1320 break;
1321
1322 case RTMP_PACKET_TYPE_VIDEO:
1323 /* video data */
1324 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: video %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1325 HandleVideo(r, packet);
1326 bHasMediaPacket = 1;
1327 if (!r->m_mediaChannel)
1328 r->m_mediaChannel = packet->m_nChannel;
1329 if (!r->m_pausing)
1330 r->m_mediaStamp = packet->m_nTimeStamp;
1331 break;
1332
1333 case RTMP_PACKET_TYPE_FLEX_STREAM_SEND:
1334 /* flex stream send */
1335 RTMP_Log(RTMP_LOGDEBUG,
1336 "%s, flex stream send, size %u bytes, not supported, ignoring",
1337 __FUNCTION__, packet->m_nBodySize);
1338 break;
1339
1340 case RTMP_PACKET_TYPE_FLEX_SHARED_OBJECT:
1341 /* flex shared object */
1342 RTMP_Log(RTMP_LOGDEBUG,
1343 "%s, flex shared object, size %u bytes, not supported, ignoring",
1344 __FUNCTION__, packet->m_nBodySize);
1345 break;
1346
1347 case RTMP_PACKET_TYPE_FLEX_MESSAGE:
1348 /* flex message */
1349 {
1350 RTMP_Log(RTMP_LOGDEBUG,
1351 "%s, flex message, size %u bytes, not fully supported",
1352 __FUNCTION__, packet->m_nBodySize);
1353 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1354
1355 /* some DEBUG code */
1356 #if 0
1357 RTMP_LIB_AMFObject obj;
1358 int nRes = obj.Decode(packet.m_body+1, packet.m_nBodySize-1);
1359 if(nRes < 0)
1360 {
1361 RTMP_Log(RTMP_LOGERROR, "%s, error decoding AMF3 packet", __FUNCTION__);
1362 /*return; */
1363 }
1364
1365 obj.Dump();
1366 #endif
1367
1368 if (HandleInvoke(r, packet->m_body + 1, packet->m_nBodySize - 1) == 1)
1369 bHasMediaPacket = 2;
1370 break;
1371 }
1372 case RTMP_PACKET_TYPE_INFO:
1373 /* metadata (notify) */
1374 RTMP_Log(RTMP_LOGDEBUG, "%s, received: notify %u bytes", __FUNCTION__,
1375 packet->m_nBodySize);
1376 if (HandleMetadata(r, packet->m_body, packet->m_nBodySize))
1377 bHasMediaPacket = 1;
1378 break;
1379
1380 case RTMP_PACKET_TYPE_SHARED_OBJECT:
1381 RTMP_Log(RTMP_LOGDEBUG, "%s, shared object, not supported, ignoring",
1382 __FUNCTION__);
1383 break;
1384
1385 case RTMP_PACKET_TYPE_INVOKE:
1386 /* invoke */
1387 RTMP_Log(RTMP_LOGDEBUG, "%s, received: invoke %u bytes", __FUNCTION__,
1388 packet->m_nBodySize);
1389 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
1390
1391 if (HandleInvoke(r, packet->m_body, packet->m_nBodySize) == 1)
1392 bHasMediaPacket = 2;
1393 break;
1394
1395 case RTMP_PACKET_TYPE_FLASH_VIDEO:
1396 {
1397 /* go through FLV packets and handle metadata packets */
1398 unsigned int pos = 0;
1399 uint32_t nTimeStamp = packet->m_nTimeStamp;
1400
1401 while (pos + 11 < packet->m_nBodySize)
1402 {
1403 uint32_t dataSize = AMF_DecodeInt24(packet->m_body + pos + 1); /* size without header (11) and prevTagSize (4) */
1404
1405 if (pos + 11 + dataSize + 4 > packet->m_nBodySize)
1406 {
1407 RTMP_Log(RTMP_LOGWARNING, "Stream corrupt?!");
1408 break;
1409 }
1410 if (packet->m_body[pos] == 0x12)
1411 {
1412 HandleMetadata(r, packet->m_body + pos + 11, dataSize);
1413 }
1414 else if (packet->m_body[pos] == 8 || packet->m_body[pos] == 9)
1415 {
1416 nTimeStamp = AMF_DecodeInt24(packet->m_body + pos + 4);
1417 nTimeStamp |= (packet->m_body[pos + 7] << 24);
1418 }
1419 pos += (11 + dataSize + 4);
1420 }
1421 if (!r->m_pausing)
1422 r->m_mediaStamp = nTimeStamp;
1423
1424 /* FLV tag(s) */
1425 /*RTMP_Log(RTMP_LOGDEBUG, "%s, received: FLV tag(s) %lu bytes", __FUNCTION__, packet.m_nBodySize); */
1426 bHasMediaPacket = 1;
1427 break;
1428 }
1429 default:
1430 RTMP_Log(RTMP_LOGDEBUG, "%s, unknown packet type received: 0x%02x", __FUNCTION__,
1431 packet->m_packetType);
1432 #ifdef _DEBUG
1433 RTMP_LogHex(RTMP_LOGDEBUG, (const uint8_t*)packet->m_body, packet->m_nBodySize);
1434 #endif
1435 }
1436
1437 return bHasMediaPacket;
1438 }
1439
1440 #if defined(RTMP_NETSTACK_DUMP)
1441 extern FILE *netstackdump;
1442 extern FILE *netstackdump_read;
1443 #endif
1444
1445 static int
ReadN(RTMP * r,char * buffer,int n)1446 ReadN(RTMP *r, char *buffer, int n)
1447 {
1448 int nOriginalSize = n;
1449 int avail;
1450 char *ptr;
1451
1452 r->m_sb.sb_timedout = FALSE;
1453
1454 #ifdef _DEBUG
1455 memset(buffer, 0, n);
1456 #endif
1457
1458 ptr = buffer;
1459 while (n > 0)
1460 {
1461 int nBytes = 0, nRead;
1462 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1463 {
1464 int refill = 0;
1465 while (!r->m_resplen)
1466 {
1467 int ret;
1468 if (r->m_sb.sb_size < 13 || refill)
1469 {
1470 if (!r->m_unackd)
1471 HTTP_Post(r, RTMPT_IDLE, "", 1);
1472 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1473 {
1474 if (!r->m_sb.sb_timedout)
1475 RTMP_Close(r);
1476 return 0;
1477 }
1478 }
1479 if ((ret = HTTP_read(r, 0)) == -1)
1480 {
1481 RTMP_Log(RTMP_LOGDEBUG, "%s, No valid HTTP response found", __FUNCTION__);
1482 RTMP_Close(r);
1483 return 0;
1484 }
1485 else if (ret == -2)
1486 {
1487 refill = 1;
1488 }
1489 else
1490 {
1491 refill = 0;
1492 }
1493 }
1494 if (r->m_resplen && !r->m_sb.sb_size)
1495 RTMPSockBuf_Fill(&r->m_sb);
1496 avail = r->m_sb.sb_size;
1497 if (avail > r->m_resplen)
1498 avail = r->m_resplen;
1499 }
1500 else
1501 {
1502 avail = r->m_sb.sb_size;
1503 if (avail == 0)
1504 {
1505 if (RTMPSockBuf_Fill(&r->m_sb) < 1)
1506 {
1507 if (!r->m_sb.sb_timedout)
1508 RTMP_Close(r);
1509 return 0;
1510 }
1511 avail = r->m_sb.sb_size;
1512 }
1513 }
1514 nRead = ((n < avail) ? n : avail);
1515 if (nRead > 0)
1516 {
1517 memcpy(ptr, r->m_sb.sb_start, nRead);
1518 r->m_sb.sb_start += nRead;
1519 r->m_sb.sb_size -= nRead;
1520 nBytes = nRead;
1521 r->m_nBytesIn += nRead;
1522 if (r->m_bSendCounter
1523 && r->m_nBytesIn > ( r->m_nBytesInSent + r->m_nClientBW / 10))
1524 if (!SendBytesReceived(r))
1525 return FALSE;
1526 }
1527 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d bytes\n", __FUNCTION__, nBytes); */
1528 #if defined(RTMP_NETSTACK_DUMP)
1529 fwrite(ptr, 1, nBytes, netstackdump_read);
1530 #endif
1531
1532 if (nBytes == 0)
1533 {
1534 RTMP_Log(RTMP_LOGDEBUG, "%s, RTMP socket closed by peer", __FUNCTION__);
1535 /*goto again; */
1536 RTMP_Close(r);
1537 break;
1538 }
1539
1540 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1541 r->m_resplen -= nBytes;
1542
1543 #ifdef CRYPTO
1544 if (r->Link.rc4keyIn)
1545 {
1546 RC4_encrypt(r->Link.rc4keyIn, nBytes, ptr);
1547 }
1548 #endif
1549
1550 n -= nBytes;
1551 ptr += nBytes;
1552 }
1553
1554 return nOriginalSize - n;
1555 }
1556
1557 static int
WriteN(RTMP * r,const char * buffer,int n)1558 WriteN(RTMP *r, const char *buffer, int n)
1559 {
1560 const char *ptr = buffer;
1561 #ifdef CRYPTO
1562 char *encrypted = 0;
1563 char buf[RTMP_BUFFER_CACHE_SIZE];
1564
1565 if (r->Link.rc4keyOut)
1566 {
1567 if (n > (int)sizeof(buf))
1568 encrypted = (char *)malloc(n);
1569 else
1570 encrypted = (char *)buf;
1571 ptr = encrypted;
1572 RC4_encrypt2(r->Link.rc4keyOut, n, buffer, ptr);
1573 }
1574 #endif
1575
1576 while (n > 0)
1577 {
1578 int nBytes;
1579
1580 if (r->Link.protocol & RTMP_FEATURE_HTTP)
1581 nBytes = HTTP_Post(r, RTMPT_SEND, ptr, n);
1582 else if(r->m_bCustomSend && r->m_customSendFunc)
1583 nBytes = r->m_customSendFunc(&r->m_sb, ptr, n, r->m_customSendParam);
1584 else
1585 nBytes = RTMPSockBuf_Send(&r->m_sb, ptr, n);
1586 /*RTMP_Log(RTMP_LOGDEBUG, "%s: %d\n", __FUNCTION__, nBytes); */
1587
1588 if (nBytes < 0)
1589 {
1590 int sockerr = GetSockError();
1591 RTMP_Log(RTMP_LOGERROR, "%s, RTMP send error %d (%d bytes)", __FUNCTION__,
1592 sockerr, n);
1593
1594 if (sockerr == EINTR && !RTMP_ctrlC)
1595 continue;
1596
1597 r->last_error_code = sockerr;
1598
1599 RTMP_Close(r);
1600 n = 1;
1601 break;
1602 }
1603
1604 if (nBytes == 0)
1605 break;
1606
1607 n -= nBytes;
1608 ptr += nBytes;
1609 }
1610
1611 #ifdef CRYPTO
1612 if (encrypted && encrypted != buf)
1613 free(encrypted);
1614 #endif
1615
1616 return n == 0;
1617 }
1618
1619 #define SAVC(x) static const AVal av_##x = AVC(#x)
1620
1621 SAVC(app);
1622 SAVC(connect);
1623 SAVC(flashVer);
1624 SAVC(swfUrl);
1625 SAVC(pageUrl);
1626 SAVC(tcUrl);
1627 SAVC(fpad);
1628 SAVC(capabilities);
1629 SAVC(audioCodecs);
1630 SAVC(videoCodecs);
1631 SAVC(videoFunction);
1632 SAVC(objectEncoding);
1633 SAVC(secureToken);
1634 SAVC(secureTokenResponse);
1635 SAVC(type);
1636 SAVC(nonprivate);
1637
1638 static int
SendConnectPacket(RTMP * r,RTMPPacket * cp)1639 SendConnectPacket(RTMP *r, RTMPPacket *cp)
1640 {
1641 RTMPPacket packet;
1642 char pbuf[4096], *pend = pbuf + sizeof(pbuf);
1643 char *enc;
1644
1645 if (cp)
1646 return RTMP_SendPacket(r, cp, TRUE);
1647
1648 if((r->Link.protocol & RTMP_FEATURE_WRITE) && r->m_bSendChunkSizeInfo)
1649 {
1650 packet.m_nChannel = 0x02;
1651 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1652 packet.m_packetType = RTMP_PACKET_TYPE_CHUNK_SIZE;
1653 packet.m_nTimeStamp = 0;
1654 packet.m_nInfoField2 = 0;
1655 packet.m_hasAbsTimestamp = 0;
1656 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1657 packet.m_nBodySize = 4;
1658
1659 enc = packet.m_body;
1660 AMF_EncodeInt32(enc, pend, r->m_outChunkSize);
1661
1662 if(!RTMP_SendPacket(r, &packet, FALSE))
1663 return 0;
1664 }
1665
1666 packet.m_nChannel = 0x03; /* control channel (invoke) */
1667 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1668 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1669 packet.m_nTimeStamp = 0;
1670 packet.m_nInfoField2 = 0;
1671 packet.m_hasAbsTimestamp = 0;
1672 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1673
1674 enc = packet.m_body;
1675 enc = AMF_EncodeString(enc, pend, &av_connect);
1676 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1677 *enc++ = AMF_OBJECT;
1678
1679 enc = AMF_EncodeNamedString(enc, pend, &av_app, &r->Link.app);
1680 if (!enc)
1681 return FALSE;
1682 if (r->Link.protocol & RTMP_FEATURE_WRITE)
1683 {
1684 enc = AMF_EncodeNamedString(enc, pend, &av_type, &av_nonprivate);
1685 if (!enc)
1686 return FALSE;
1687 }
1688 if (r->Link.flashVer.av_len)
1689 {
1690 enc = AMF_EncodeNamedString(enc, pend, &av_flashVer, &r->Link.flashVer);
1691 if (!enc)
1692 return FALSE;
1693 }
1694 if (r->Link.swfUrl.av_len)
1695 {
1696 enc = AMF_EncodeNamedString(enc, pend, &av_swfUrl, &r->Link.swfUrl);
1697 if (!enc)
1698 return FALSE;
1699 }
1700 if (r->Link.tcUrl.av_len)
1701 {
1702 enc = AMF_EncodeNamedString(enc, pend, &av_tcUrl, &r->Link.tcUrl);
1703 if (!enc)
1704 return FALSE;
1705 }
1706 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
1707 {
1708 enc = AMF_EncodeNamedBoolean(enc, pend, &av_fpad, FALSE);
1709 if (!enc)
1710 return FALSE;
1711 enc = AMF_EncodeNamedNumber(enc, pend, &av_capabilities, 15.0);
1712 if (!enc)
1713 return FALSE;
1714 enc = AMF_EncodeNamedNumber(enc, pend, &av_audioCodecs, r->m_fAudioCodecs);
1715 if (!enc)
1716 return FALSE;
1717 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoCodecs, r->m_fVideoCodecs);
1718 if (!enc)
1719 return FALSE;
1720 enc = AMF_EncodeNamedNumber(enc, pend, &av_videoFunction, 1.0);
1721 if (!enc)
1722 return FALSE;
1723 if (r->Link.pageUrl.av_len)
1724 {
1725 enc = AMF_EncodeNamedString(enc, pend, &av_pageUrl, &r->Link.pageUrl);
1726 if (!enc)
1727 return FALSE;
1728 }
1729 }
1730 if (r->m_fEncoding != 0.0 || r->m_bSendEncoding)
1731 {
1732 /* AMF0, AMF3 not fully supported yet */
1733 enc = AMF_EncodeNamedNumber(enc, pend, &av_objectEncoding, r->m_fEncoding);
1734 if (!enc)
1735 return FALSE;
1736 }
1737 if (enc + 3 >= pend)
1738 return FALSE;
1739 *enc++ = 0;
1740 *enc++ = 0; /* end of object - 0x00 0x00 0x09 */
1741 *enc++ = AMF_OBJECT_END;
1742
1743 /* add auth string */
1744 if (r->Link.auth.av_len)
1745 {
1746 enc = AMF_EncodeBoolean(enc, pend, r->Link.lFlags & RTMP_LF_AUTH);
1747 if (!enc)
1748 return FALSE;
1749 enc = AMF_EncodeString(enc, pend, &r->Link.auth);
1750 if (!enc)
1751 return FALSE;
1752 }
1753 if (r->Link.extras.o_num)
1754 {
1755 int i;
1756 for (i = 0; i < r->Link.extras.o_num; i++)
1757 {
1758 enc = AMFProp_Encode(&r->Link.extras.o_props[i], enc, pend);
1759 if (!enc)
1760 return FALSE;
1761 }
1762 }
1763 packet.m_nBodySize = enc - packet.m_body;
1764
1765 return RTMP_SendPacket(r, &packet, TRUE);
1766 }
1767
1768 #if 0 /* unused */
1769 SAVC(bgHasStream);
1770
1771 static int
1772 SendBGHasStream(RTMP *r, double dId, AVal *playpath)
1773 {
1774 RTMPPacket packet;
1775 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1776 char *enc;
1777
1778 packet.m_forceChannel = FALSE;
1779 packet.m_nChannel = 0x03; /* control channel (invoke) */
1780 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1781 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1782 packet.m_nTimeStamp = 0;
1783 packet.m_nInfoField2 = 0;
1784 packet.m_hasAbsTimestamp = 0;
1785 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1786
1787 enc = packet.m_body;
1788 enc = AMF_EncodeString(enc, pend, &av_bgHasStream);
1789 enc = AMF_EncodeNumber(enc, pend, dId);
1790 *enc++ = AMF_NULL;
1791
1792 enc = AMF_EncodeString(enc, pend, playpath);
1793 if (enc == NULL)
1794 return FALSE;
1795
1796 packet.m_nBodySize = enc - packet.m_body;
1797
1798 return RTMP_SendPacket(r, &packet, TRUE);
1799 }
1800 #endif
1801
1802 SAVC(createStream);
1803
1804 int
RTMP_SendCreateStream(RTMP * r)1805 RTMP_SendCreateStream(RTMP *r)
1806 {
1807 RTMPPacket packet;
1808 char pbuf[256], *pend = pbuf + sizeof(pbuf);
1809 char *enc;
1810
1811 packet.m_nChannel = 0x03; /* control channel (invoke) */
1812 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1813 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1814 packet.m_nTimeStamp = 0;
1815 packet.m_nInfoField2 = 0;
1816 packet.m_hasAbsTimestamp = 0;
1817 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1818
1819 enc = packet.m_body;
1820 enc = AMF_EncodeString(enc, pend, &av_createStream);
1821 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1822 *enc++ = AMF_NULL; /* NULL */
1823
1824 packet.m_nBodySize = enc - packet.m_body;
1825
1826 return RTMP_SendPacket(r, &packet, TRUE);
1827 }
1828
1829 SAVC(FCSubscribe);
1830
1831 static int
SendFCSubscribe(RTMP * r,AVal * subscribepath)1832 SendFCSubscribe(RTMP *r, AVal *subscribepath)
1833 {
1834 RTMPPacket packet;
1835 char pbuf[512], *pend = pbuf + sizeof(pbuf);
1836 char *enc;
1837 packet.m_nChannel = 0x03; /* control channel (invoke) */
1838 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1839 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1840 packet.m_nTimeStamp = 0;
1841 packet.m_nInfoField2 = 0;
1842 packet.m_hasAbsTimestamp = 0;
1843 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1844
1845 RTMP_Log(RTMP_LOGDEBUG, "FCSubscribe: %s", subscribepath->av_val);
1846 enc = packet.m_body;
1847 enc = AMF_EncodeString(enc, pend, &av_FCSubscribe);
1848 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1849 *enc++ = AMF_NULL;
1850 enc = AMF_EncodeString(enc, pend, subscribepath);
1851
1852 if (!enc)
1853 return FALSE;
1854
1855 packet.m_nBodySize = enc - packet.m_body;
1856
1857 return RTMP_SendPacket(r, &packet, TRUE);
1858 }
1859
1860 /* Justin.tv specific authentication */
1861 static const AVal av_NetStream_Authenticate_UsherToken = AVC("NetStream.Authenticate.UsherToken");
1862
1863 static int
SendUsherToken(RTMP * r,AVal * usherToken)1864 SendUsherToken(RTMP *r, AVal *usherToken)
1865 {
1866 RTMPPacket packet;
1867 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1868 char *enc;
1869 packet.m_nChannel = 0x03; /* control channel (invoke) */
1870 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1871 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1872 packet.m_nTimeStamp = 0;
1873 packet.m_nInfoField2 = 0;
1874 packet.m_hasAbsTimestamp = 0;
1875 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1876
1877 RTMP_Log(RTMP_LOGDEBUG, "UsherToken: %s", usherToken->av_val);
1878 enc = packet.m_body;
1879 enc = AMF_EncodeString(enc, pend, &av_NetStream_Authenticate_UsherToken);
1880 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1881 *enc++ = AMF_NULL;
1882 enc = AMF_EncodeString(enc, pend, usherToken);
1883
1884 if (!enc)
1885 return FALSE;
1886
1887 packet.m_nBodySize = enc - packet.m_body;
1888
1889 return RTMP_SendPacket(r, &packet, FALSE);
1890 }
1891 /******************************************/
1892
1893 SAVC(releaseStream);
1894
1895 static int
SendReleaseStream(RTMP * r,int streamIdx)1896 SendReleaseStream(RTMP *r, int streamIdx)
1897 {
1898 RTMPPacket packet;
1899 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1900 char *enc;
1901
1902 packet.m_nChannel = 0x03; /* control channel (invoke) */
1903 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1904 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1905 packet.m_nTimeStamp = 0;
1906 packet.m_nInfoField2 = 0;
1907 packet.m_hasAbsTimestamp = 0;
1908 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1909
1910 enc = packet.m_body;
1911 enc = AMF_EncodeString(enc, pend, &av_releaseStream);
1912 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1913 *enc++ = AMF_NULL;
1914 enc = AMF_EncodeString(enc, pend, &r->Link.streams[streamIdx].playpath);
1915 if (!enc)
1916 return FALSE;
1917
1918 packet.m_nBodySize = enc - packet.m_body;
1919
1920 return RTMP_SendPacket(r, &packet, FALSE);
1921 }
1922
1923 SAVC(FCPublish);
1924
1925 static int
SendFCPublish(RTMP * r,int streamIdx)1926 SendFCPublish(RTMP *r, int streamIdx)
1927 {
1928 RTMPPacket packet;
1929 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1930 char *enc;
1931
1932 packet.m_nChannel = 0x03; /* control channel (invoke) */
1933 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1934 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1935 packet.m_nTimeStamp = 0;
1936 packet.m_nInfoField2 = 0;
1937 packet.m_hasAbsTimestamp = 0;
1938 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1939
1940 enc = packet.m_body;
1941 enc = AMF_EncodeString(enc, pend, &av_FCPublish);
1942 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1943 *enc++ = AMF_NULL;
1944 enc = AMF_EncodeString(enc, pend, &r->Link.streams[streamIdx].playpath);
1945 if (!enc)
1946 return FALSE;
1947
1948 packet.m_nBodySize = enc - packet.m_body;
1949
1950 return RTMP_SendPacket(r, &packet, FALSE);
1951 }
1952
1953 SAVC(FCUnpublish);
1954
1955 static int
SendFCUnpublish(RTMP * r,int streamIdx)1956 SendFCUnpublish(RTMP *r, int streamIdx)
1957 {
1958 RTMPPacket packet;
1959 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1960 char *enc;
1961
1962 packet.m_nChannel = 0x03; /* control channel (invoke) */
1963 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
1964 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1965 packet.m_nTimeStamp = 0;
1966 packet.m_nInfoField2 = 0;
1967 packet.m_hasAbsTimestamp = 0;
1968 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
1969
1970 enc = packet.m_body;
1971 enc = AMF_EncodeString(enc, pend, &av_FCUnpublish);
1972 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
1973 *enc++ = AMF_NULL;
1974 enc = AMF_EncodeString(enc, pend, &r->Link.streams[streamIdx].playpath);
1975 if (!enc)
1976 return FALSE;
1977
1978 packet.m_nBodySize = enc - packet.m_body;
1979
1980 return RTMP_SendPacket(r, &packet, FALSE);
1981 }
1982
1983 SAVC(publish);
1984 SAVC(live);
1985
1986 static int
SendPublish(RTMP * r,int streamIdx)1987 SendPublish(RTMP *r, int streamIdx)
1988 {
1989 RTMPPacket packet;
1990 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
1991 char *enc;
1992
1993 packet.m_nChannel = 0x04; /* source channel (invoke) */
1994 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
1995 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
1996 packet.m_nTimeStamp = 0;
1997 packet.m_nInfoField2 = r->Link.streams[streamIdx].id;
1998 packet.m_hasAbsTimestamp = 0;
1999 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2000
2001 enc = packet.m_body;
2002 enc = AMF_EncodeString(enc, pend, &av_publish);
2003 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2004 *enc++ = AMF_NULL;
2005 enc = AMF_EncodeString(enc, pend, &r->Link.streams[streamIdx].playpath);
2006 if (!enc)
2007 return FALSE;
2008
2009 /* FIXME: should we choose live based on Link.lFlags & RTMP_LF_LIVE? */
2010 enc = AMF_EncodeString(enc, pend, &av_live);
2011 if (!enc)
2012 return FALSE;
2013
2014 packet.m_nBodySize = enc - packet.m_body;
2015
2016 return RTMP_SendPacket(r, &packet, TRUE);
2017 }
2018
2019 SAVC(deleteStream);
2020
2021 static int
SendDeleteStream(RTMP * r,double dStreamId)2022 SendDeleteStream(RTMP *r, double dStreamId)
2023 {
2024 RTMPPacket packet;
2025 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2026 char *enc;
2027
2028 packet.m_nChannel = 0x03; /* control channel (invoke) */
2029 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2030 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2031 packet.m_nTimeStamp = 0;
2032 packet.m_nInfoField2 = 0;
2033 packet.m_hasAbsTimestamp = 0;
2034 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2035
2036 enc = packet.m_body;
2037 enc = AMF_EncodeString(enc, pend, &av_deleteStream);
2038 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2039 *enc++ = AMF_NULL;
2040 enc = AMF_EncodeNumber(enc, pend, dStreamId);
2041
2042 packet.m_nBodySize = enc - packet.m_body;
2043
2044 /* no response expected */
2045 return RTMP_SendPacket(r, &packet, FALSE);
2046 }
2047
2048 SAVC(pause);
2049
2050 int
RTMP_SendPause(RTMP * r,int DoPause,int iTime)2051 RTMP_SendPause(RTMP *r, int DoPause, int iTime)
2052 {
2053 RTMPPacket packet;
2054 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2055 char *enc;
2056
2057 packet.m_nChannel = 0x08; /* video channel */
2058 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2059 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2060 packet.m_nTimeStamp = 0;
2061 packet.m_nInfoField2 = 0;
2062 packet.m_hasAbsTimestamp = 0;
2063 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2064
2065 enc = packet.m_body;
2066 enc = AMF_EncodeString(enc, pend, &av_pause);
2067 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2068 *enc++ = AMF_NULL;
2069 enc = AMF_EncodeBoolean(enc, pend, DoPause);
2070 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
2071
2072 packet.m_nBodySize = enc - packet.m_body;
2073
2074 RTMP_Log(RTMP_LOGDEBUG, "%s, %d, pauseTime=%d", __FUNCTION__, DoPause, iTime);
2075 return RTMP_SendPacket(r, &packet, TRUE);
2076 }
2077
RTMP_Pause(RTMP * r,int DoPause)2078 int RTMP_Pause(RTMP *r, int DoPause)
2079 {
2080 if (DoPause)
2081 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
2082 r->m_channelTimestamp[r->m_mediaChannel] : 0;
2083 return RTMP_SendPause(r, DoPause, r->m_pauseStamp);
2084 }
2085
2086 SAVC(seek);
2087
2088 int
RTMP_SendSeek(RTMP * r,int iTime)2089 RTMP_SendSeek(RTMP *r, int iTime)
2090 {
2091 RTMPPacket packet;
2092 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2093 char *enc;
2094
2095 packet.m_nChannel = 0x08; /* video channel */
2096 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2097 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2098 packet.m_nTimeStamp = 0;
2099 packet.m_nInfoField2 = 0;
2100 packet.m_hasAbsTimestamp = 0;
2101 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2102
2103 enc = packet.m_body;
2104 enc = AMF_EncodeString(enc, pend, &av_seek);
2105 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2106 *enc++ = AMF_NULL;
2107 enc = AMF_EncodeNumber(enc, pend, (double)iTime);
2108
2109 packet.m_nBodySize = enc - packet.m_body;
2110
2111 r->m_read.flags |= RTMP_READ_SEEKING;
2112 r->m_read.nResumeTS = 0;
2113
2114 return RTMP_SendPacket(r, &packet, TRUE);
2115 }
2116
2117 int
RTMP_SendServerBW(RTMP * r)2118 RTMP_SendServerBW(RTMP *r)
2119 {
2120 RTMPPacket packet;
2121 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2122
2123 packet.m_nChannel = 0x02; /* control channel (invoke) */
2124 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2125 packet.m_packetType = RTMP_PACKET_TYPE_SERVER_BW;
2126 packet.m_nTimeStamp = 0;
2127 packet.m_nInfoField2 = 0;
2128 packet.m_hasAbsTimestamp = 0;
2129 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2130
2131 packet.m_nBodySize = 4;
2132
2133 AMF_EncodeInt32(packet.m_body, pend, r->m_nServerBW);
2134 return RTMP_SendPacket(r, &packet, FALSE);
2135 }
2136
2137 int
RTMP_SendClientBW(RTMP * r)2138 RTMP_SendClientBW(RTMP *r)
2139 {
2140 RTMPPacket packet;
2141 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2142
2143 packet.m_nChannel = 0x02; /* control channel (invoke) */
2144 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2145 packet.m_packetType = RTMP_PACKET_TYPE_CLIENT_BW;
2146 packet.m_nTimeStamp = 0;
2147 packet.m_nInfoField2 = 0;
2148 packet.m_hasAbsTimestamp = 0;
2149 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2150
2151 packet.m_nBodySize = 5;
2152
2153 AMF_EncodeInt32(packet.m_body, pend, r->m_nClientBW);
2154 packet.m_body[4] = r->m_nClientBW2;
2155 return RTMP_SendPacket(r, &packet, FALSE);
2156 }
2157
2158 static int
SendBytesReceived(RTMP * r)2159 SendBytesReceived(RTMP *r)
2160 {
2161 RTMPPacket packet;
2162 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2163
2164 packet.m_nChannel = 0x02; /* control channel (invoke) */
2165 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2166 packet.m_packetType = RTMP_PACKET_TYPE_BYTES_READ_REPORT;
2167 packet.m_nTimeStamp = 0;
2168 packet.m_nInfoField2 = 0;
2169 packet.m_hasAbsTimestamp = 0;
2170 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2171
2172 packet.m_nBodySize = 4;
2173
2174 AMF_EncodeInt32(packet.m_body, pend, r->m_nBytesIn); /* hard coded for now */
2175 r->m_nBytesInSent = r->m_nBytesIn;
2176
2177 /*RTMP_Log(RTMP_LOGDEBUG, "Send bytes report. 0x%x (%d bytes)", (unsigned int)m_nBytesIn, m_nBytesIn); */
2178 return RTMP_SendPacket(r, &packet, FALSE);
2179 }
2180
2181 SAVC(_checkbw);
2182
2183 static int
SendCheckBW(RTMP * r)2184 SendCheckBW(RTMP *r)
2185 {
2186 RTMPPacket packet;
2187 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2188 char *enc;
2189
2190 packet.m_nChannel = 0x03; /* control channel (invoke) */
2191 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2192 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2193 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2194 packet.m_nInfoField2 = 0;
2195 packet.m_hasAbsTimestamp = 0;
2196 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2197
2198 enc = packet.m_body;
2199 enc = AMF_EncodeString(enc, pend, &av__checkbw);
2200 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2201 *enc++ = AMF_NULL;
2202
2203 packet.m_nBodySize = enc - packet.m_body;
2204
2205 /* triggers _onbwcheck and eventually results in _onbwdone */
2206 return RTMP_SendPacket(r, &packet, FALSE);
2207 }
2208
2209 SAVC(_result);
2210
2211 static int
SendCheckBWResult(RTMP * r,double txn)2212 SendCheckBWResult(RTMP *r, double txn)
2213 {
2214 RTMPPacket packet;
2215 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2216 char *enc;
2217
2218 packet.m_nChannel = 0x03; /* control channel (invoke) */
2219 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2220 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2221 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2222 packet.m_nInfoField2 = 0;
2223 packet.m_hasAbsTimestamp = 0;
2224 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2225
2226 enc = packet.m_body;
2227 enc = AMF_EncodeString(enc, pend, &av__result);
2228 enc = AMF_EncodeNumber(enc, pend, txn);
2229 *enc++ = AMF_NULL;
2230 enc = AMF_EncodeNumber(enc, pend, (double)r->m_nBWCheckCounter++);
2231
2232 packet.m_nBodySize = enc - packet.m_body;
2233
2234 return RTMP_SendPacket(r, &packet, FALSE);
2235 }
2236
2237 SAVC(ping);
2238 SAVC(pong);
2239
2240 static int
SendPong(RTMP * r,double txn)2241 SendPong(RTMP *r, double txn)
2242 {
2243 RTMPPacket packet;
2244 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2245 char *enc;
2246
2247 packet.m_nChannel = 0x03; /* control channel (invoke) */
2248 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2249 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2250 packet.m_nTimeStamp = 0x16 * r->m_nBWCheckCounter; /* temp inc value. till we figure it out. */
2251 packet.m_nInfoField2 = 0;
2252 packet.m_hasAbsTimestamp = 0;
2253 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2254
2255 enc = packet.m_body;
2256 enc = AMF_EncodeString(enc, pend, &av_pong);
2257 enc = AMF_EncodeNumber(enc, pend, txn);
2258 *enc++ = AMF_NULL;
2259
2260 packet.m_nBodySize = enc - packet.m_body;
2261
2262 return RTMP_SendPacket(r, &packet, FALSE);
2263 }
2264
2265 SAVC(play);
2266
2267 static int
SendPlay(RTMP * r,int streamIdx)2268 SendPlay(RTMP *r, int streamIdx)
2269 {
2270 RTMPPacket packet;
2271 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2272 char *enc;
2273
2274 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2275 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2276 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2277 packet.m_nTimeStamp = 0;
2278 packet.m_nInfoField2 = r->Link.streams[streamIdx].id; /*0x01000000; */
2279 packet.m_hasAbsTimestamp = 0;
2280 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2281
2282 enc = packet.m_body;
2283 enc = AMF_EncodeString(enc, pend, &av_play);
2284 enc = AMF_EncodeNumber(enc, pend, ++r->m_numInvokes);
2285 *enc++ = AMF_NULL;
2286
2287 RTMP_Log(RTMP_LOGDEBUG, "%s, seekTime=%d, stopTime=%d, sending play: %s",
2288 __FUNCTION__, r->Link.seekTime, r->Link.stopTime,
2289 r->Link.streams[streamIdx].playpath.av_val);
2290 enc = AMF_EncodeString(enc, pend, &r->Link.streams[streamIdx].playpath);
2291 if (!enc)
2292 return FALSE;
2293
2294 /* Optional parameters start and len.
2295 *
2296 * start: -2, -1, 0, positive number
2297 * -2: looks for a live stream, then a recorded stream,
2298 * if not found any open a live stream
2299 * -1: plays a live stream
2300 * >=0: plays a recorded streams from 'start' milliseconds
2301 */
2302 if (r->Link.lFlags & RTMP_LF_LIVE)
2303 enc = AMF_EncodeNumber(enc, pend, -1000.0);
2304 else
2305 {
2306 if (r->Link.seekTime > 0.0)
2307 enc = AMF_EncodeNumber(enc, pend, r->Link.seekTime); /* resume from here */
2308 else
2309 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 */
2310 }
2311 if (!enc)
2312 return FALSE;
2313
2314 /* len: -1, 0, positive number
2315 * -1: plays live or recorded stream to the end (default)
2316 * 0: plays a frame 'start' ms away from the beginning
2317 * >0: plays a live or recoded stream for 'len' milliseconds
2318 */
2319 /*enc += EncodeNumber(enc, -1.0); */ /* len */
2320 if (r->Link.stopTime)
2321 {
2322 enc = AMF_EncodeNumber(enc, pend, r->Link.stopTime - r->Link.seekTime);
2323 if (!enc)
2324 return FALSE;
2325 }
2326
2327 packet.m_nBodySize = enc - packet.m_body;
2328
2329 return RTMP_SendPacket(r, &packet, TRUE);
2330 }
2331
2332 SAVC(set_playlist);
2333 SAVC(0);
2334
2335 static int
SendPlaylist(RTMP * r,int streamIdx)2336 SendPlaylist(RTMP *r, int streamIdx)
2337 {
2338 RTMPPacket packet;
2339 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2340 char *enc;
2341
2342 packet.m_nChannel = 0x08; /* we make 8 our stream channel */
2343 packet.m_headerType = RTMP_PACKET_SIZE_LARGE;
2344 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2345 packet.m_nTimeStamp = 0;
2346 packet.m_nInfoField2 = r->Link.streams[streamIdx].id; /*0x01000000; */
2347 packet.m_hasAbsTimestamp = 0;
2348 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2349
2350 enc = packet.m_body;
2351 enc = AMF_EncodeString(enc, pend, &av_set_playlist);
2352 enc = AMF_EncodeNumber(enc, pend, 0);
2353 *enc++ = AMF_NULL;
2354 *enc++ = AMF_ECMA_ARRAY;
2355 *enc++ = 0;
2356 *enc++ = 0;
2357 *enc++ = 0;
2358 *enc++ = AMF_OBJECT;
2359 enc = AMF_EncodeNamedString(enc, pend, &av_0, &r->Link.streams[streamIdx].playpath);
2360 if (!enc)
2361 return FALSE;
2362 if (enc + 3 >= pend)
2363 return FALSE;
2364 *enc++ = 0;
2365 *enc++ = 0;
2366 *enc++ = AMF_OBJECT_END;
2367
2368 packet.m_nBodySize = enc - packet.m_body;
2369
2370 return RTMP_SendPacket(r, &packet, TRUE);
2371 }
2372
2373 static int
SendSecureTokenResponse(RTMP * r,AVal * resp)2374 SendSecureTokenResponse(RTMP *r, AVal *resp)
2375 {
2376 RTMPPacket packet;
2377 char pbuf[1024], *pend = pbuf + sizeof(pbuf);
2378 char *enc;
2379
2380 packet.m_nChannel = 0x03; /* control channel (invoke) */
2381 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2382 packet.m_packetType = RTMP_PACKET_TYPE_INVOKE;
2383 packet.m_nTimeStamp = 0;
2384 packet.m_nInfoField2 = 0;
2385 packet.m_hasAbsTimestamp = 0;
2386 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2387
2388 enc = packet.m_body;
2389 enc = AMF_EncodeString(enc, pend, &av_secureTokenResponse);
2390 enc = AMF_EncodeNumber(enc, pend, 0.0);
2391 *enc++ = AMF_NULL;
2392 enc = AMF_EncodeString(enc, pend, resp);
2393 if (!enc)
2394 return FALSE;
2395
2396 packet.m_nBodySize = enc - packet.m_body;
2397
2398 return RTMP_SendPacket(r, &packet, FALSE);
2399 }
2400
2401 /*
2402 from http://jira.red5.org/confluence/display/docs/Ping:
2403
2404 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.
2405
2406 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.
2407
2408 * 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.
2409 * type 1: Tell the stream to clear the playing buffer.
2410 * type 3: Buffer time of the client. The third parameter is the buffer time in millisecond.
2411 * type 4: Reset a stream. Used together with type 0 in the case of VOD. Often sent before type 0.
2412 * type 6: Ping the client from server. The second parameter is the current time.
2413 * type 7: Pong reply from client. The second parameter is the time the server sent with his ping request.
2414 * type 26: SWFVerification request
2415 * type 27: SWFVerification response
2416 */
2417 int
RTMP_SendCtrl(RTMP * r,short nType,unsigned int nObject,unsigned int nTime)2418 RTMP_SendCtrl(RTMP *r, short nType, unsigned int nObject, unsigned int nTime)
2419 {
2420 RTMPPacket packet;
2421 char pbuf[256], *pend = pbuf + sizeof(pbuf);
2422 int nSize;
2423 char *buf;
2424
2425 RTMP_Log(RTMP_LOGDEBUG, "sending ctrl. type: 0x%04x", (unsigned short)nType);
2426
2427 packet.m_nChannel = 0x02; /* control channel (ping) */
2428 packet.m_headerType = RTMP_PACKET_SIZE_MEDIUM;
2429 packet.m_packetType = RTMP_PACKET_TYPE_CONTROL;
2430 packet.m_nTimeStamp = 0; /* RTMP_GetTime(); */
2431 packet.m_nInfoField2 = 0;
2432 packet.m_hasAbsTimestamp = 0;
2433 packet.m_body = pbuf + RTMP_MAX_HEADER_SIZE;
2434
2435 switch(nType)
2436 {
2437 case 0x03:
2438 nSize = 10;
2439 break; /* buffer time */
2440 case 0x1A:
2441 nSize = 3;
2442 break; /* SWF verify request */
2443 case 0x1B:
2444 nSize = 44;
2445 break; /* SWF verify response */
2446 default:
2447 nSize = 6;
2448 break;
2449 }
2450
2451 packet.m_nBodySize = nSize;
2452
2453 buf = packet.m_body;
2454 buf = AMF_EncodeInt16(buf, pend, nType);
2455
2456 if (nType == 0x1B)
2457 {
2458 #ifdef CRYPTO
2459 memcpy(buf, r->Link.SWFVerificationResponse, 42);
2460 RTMP_Log(RTMP_LOGDEBUG, "Sending SWFVerification response: ");
2461 RTMP_LogHex(RTMP_LOGDEBUG, (uint8_t *)packet.m_body, packet.m_nBodySize);
2462 #endif
2463 }
2464 else if (nType == 0x1A)
2465 {
2466 *buf = nObject & 0xff;
2467 }
2468 else
2469 {
2470 if (nSize > 2)
2471 buf = AMF_EncodeInt32(buf, pend, nObject);
2472
2473 if (nSize > 6)
2474 buf = AMF_EncodeInt32(buf, pend, nTime);
2475 }
2476
2477 return RTMP_SendPacket(r, &packet, FALSE);
2478 }
2479
2480 static void
AV_erase(RTMP_METHOD * vals,int * num,int i,int freeit)2481 AV_erase(RTMP_METHOD *vals, int *num, int i, int freeit)
2482 {
2483 if (freeit)
2484 free(vals[i].name.av_val);
2485 (*num)--;
2486 for (; i < *num; i++)
2487 {
2488 vals[i] = vals[i + 1];
2489 }
2490 vals[i].name.av_val = NULL;
2491 vals[i].name.av_len = 0;
2492 vals[i].num = 0;
2493 }
2494
2495 void
RTMP_DropRequest(RTMP * r,int i,int freeit)2496 RTMP_DropRequest(RTMP *r, int i, int freeit)
2497 {
2498 AV_erase(r->m_methodCalls, &r->m_numCalls, i, freeit);
2499 }
2500
2501 static void
AV_queue(RTMP_METHOD ** vals,int * num,AVal * av,int txn)2502 AV_queue(RTMP_METHOD **vals, int *num, AVal *av, int txn)
2503 {
2504 char *tmp;
2505 if (!(*num & 0x0f))
2506 *vals = realloc(*vals, (*num + 16) * sizeof(RTMP_METHOD));
2507 tmp = malloc(av->av_len + 1);
2508 memcpy(tmp, av->av_val, av->av_len);
2509 tmp[av->av_len] = '\0';
2510 (*vals)[*num].num = txn;
2511 (*vals)[*num].name.av_len = av->av_len;
2512 (*vals)[(*num)++].name.av_val = tmp;
2513 }
2514
2515 static void
AV_clear(RTMP_METHOD * vals,int num)2516 AV_clear(RTMP_METHOD *vals, int num)
2517 {
2518 int i;
2519 for (i = 0; i < num; i++)
2520 free(vals[i].name.av_val);
2521 free(vals);
2522 }
2523
2524
2525 #if defined(CRYPTO) || defined(USE_ONLY_MD5)
2526 static int
b64enc(const unsigned char * input,int length,char * output,int maxsize)2527 b64enc(const unsigned char *input, int length, char *output, int maxsize)
2528 {
2529 (void)maxsize;
2530
2531 #if defined(USE_MBEDTLS)
2532 size_t osize;
2533 if(mbedtls_base64_encode((unsigned char *) output, maxsize, &osize, input, length) == 0)
2534 {
2535 output[osize] = '\0';
2536 return 1;
2537 }
2538 else
2539 {
2540 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2541 return 0;
2542 }
2543 #elif defined(USE_POLARSSL)
2544 size_t buf_size = maxsize;
2545 if(base64_encode((unsigned char *) output, &buf_size, input, length) == 0)
2546 {
2547 output[buf_size] = '\0';
2548 return 1;
2549 }
2550 else
2551 {
2552 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2553 return 0;
2554 }
2555 #elif defined(USE_GNUTLS)
2556 if (BASE64_ENCODE_RAW_LENGTH(length) <= maxsize)
2557 base64_encode_raw((uint8_t*) output, length, input);
2558 else
2559 {
2560 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2561 return 0;
2562 }
2563 #elif defined(USE_ONLY_MD5)
2564 if ((((length + 2) / 3) * 4) <= maxsize)
2565 {
2566 base64_encodestate state;
2567
2568 base64_init_encodestate(&state);
2569 output += base64_encode_block((const char *)input, length, output, &state);
2570 base64_encode_blockend(output, &state);
2571 }
2572 else
2573 {
2574 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2575 return 0;
2576 }
2577
2578 #else /* USE_OPENSSL */
2579 BIO *bmem, *b64;
2580 BUF_MEM *bptr;
2581
2582 b64 = BIO_new(BIO_f_base64());
2583 bmem = BIO_new(BIO_s_mem());
2584 b64 = BIO_push(b64, bmem);
2585 BIO_write(b64, input, length);
2586 if (BIO_flush(b64) == 1)
2587 {
2588 BIO_get_mem_ptr(b64, &bptr);
2589 memcpy(output, bptr->data, bptr->length-1);
2590 output[bptr->length-1] = '\0';
2591 }
2592 else
2593 {
2594 RTMP_Log(RTMP_LOGDEBUG, "%s, error", __FUNCTION__);
2595 return 0;
2596 }
2597 BIO_free_all(b64);
2598 #endif
2599 return 1;
2600 }
2601
2602 #if defined(USE_MBEDTLS)
2603 typedef mbedtls_md5_context MD5_CTX;
2604
2605 #if MBEDTLS_VERSION_NUMBER >= 0x02070000
2606 #define MD5_Init(ctx) mbedtls_md5_init(ctx); mbedtls_md5_starts_ret(ctx)
2607 #define MD5_Update(ctx,data,len) mbedtls_md5_update_ret(ctx,(unsigned char *)data,len)
2608 #define MD5_Final(dig,ctx) mbedtls_md5_finish_ret(ctx,dig); mbedtls_md5_free(ctx)
2609 #else
2610 #define MD5_Init(ctx) mbedtls_md5_init(ctx); mbedtls_md5_starts(ctx)
2611 #define MD5_Update(ctx,data,len) mbedtls_md5_update(ctx,(unsigned char *)data,len)
2612 #define MD5_Final(dig,ctx) mbedtls_md5_finish(ctx,dig); mbedtls_md5_free(ctx)
2613 #endif
2614
2615 #elif defined(USE_POLARSSL)
2616 #define MD5_CTX md5_context
2617 #define MD5_Init(ctx) md5_starts(ctx)
2618 #define MD5_Update(ctx,data,len) md5_update(ctx,(unsigned char *)data,len)
2619 #define MD5_Final(dig,ctx) md5_finish(ctx,dig)
2620 #elif defined(USE_GNUTLS)
2621 typedef struct md5_ctx MD5_CTX;
2622 #define MD5_Init(ctx) md5_init(ctx)
2623 #define MD5_Update(ctx,data,len) md5_update(ctx,len,data)
2624 #define MD5_Final(dig,ctx) md5_digest(ctx,MD5_DIGEST_LENGTH,dig)
2625 #else
2626 #endif
2627
2628 static const AVal av_authmod_adobe = AVC("authmod=adobe");
2629 static const AVal av_authmod_llnw = AVC("authmod=llnw");
2630
hexenc(unsigned char * inbuf,int len,char * dst)2631 static void hexenc(unsigned char *inbuf, int len, char *dst)
2632 {
2633 char *ptr = dst;
2634 while(len--)
2635 {
2636 sprintf(ptr, "%02x", *inbuf++);
2637 ptr += 2;
2638 }
2639 *ptr = '\0';
2640 }
2641
AValChr(AVal * av,char c)2642 static char *AValChr(AVal *av, char c)
2643 {
2644 int i;
2645 for (i = 0; i < av->av_len; i++)
2646 {
2647 if (av->av_val[i] == c)
2648 return &av->av_val[i];
2649 }
2650 return NULL;
2651 }
2652
2653 static int
PublisherAuth(RTMP * r,AVal * description)2654 PublisherAuth(RTMP *r, AVal *description)
2655 {
2656 char *token_in = NULL;
2657 char *ptr;
2658 unsigned char md5sum_val[MD5_DIGEST_LENGTH+1];
2659 MD5_CTX md5ctx;
2660 int challenge2_data;
2661 #define RESPONSE_LEN 32
2662 #define CHALLENGE2_LEN 16
2663 #define SALTED2_LEN (32+8+8+8)
2664 #define B64DIGEST_LEN 24 /* 16 byte digest => 22 b64 chars + 2 chars padding */
2665 #define B64INT_LEN 8 /* 4 byte int => 6 b64 chars + 2 chars padding */
2666 #define HEXHASH_LEN (2*MD5_DIGEST_LENGTH)
2667 char response[RESPONSE_LEN];
2668 char challenge2[CHALLENGE2_LEN];
2669 char salted2[SALTED2_LEN];
2670 AVal pubToken;
2671
2672 if (strstr(description->av_val, av_authmod_adobe.av_val) != NULL)
2673 {
2674 if(strstr(description->av_val, "code=403 need auth") != NULL)
2675 {
2676 if (strstr(r->Link.app.av_val, av_authmod_adobe.av_val) != NULL)
2677 {
2678 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2679 r->Link.pFlags |= RTMP_PUB_CLEAN;
2680 return 0;
2681 }
2682 else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len)
2683 {
2684 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_adobe.av_len + 8);
2685 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2686 av_authmod_adobe.av_val,
2687 r->Link.pubUser.av_val);
2688 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2689 r->Link.pFlags |= RTMP_PUB_NAME;
2690 }
2691 else
2692 {
2693 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2694 r->Link.pFlags |= RTMP_PUB_CLEAN;
2695 return 0;
2696 }
2697 }
2698 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2699 {
2700 char *par, *val = NULL, *orig_ptr;
2701 AVal user, salt, opaque, challenge, *aptr = NULL;
2702
2703 opaque.av_len = challenge.av_len = salt.av_len = user.av_len = 0;
2704 opaque.av_val = challenge.av_val = salt.av_val = user.av_val = NULL;
2705
2706 ptr = orig_ptr = strdup(token_in);
2707 while (ptr)
2708 {
2709 par = ptr;
2710 ptr = strchr(par, '&');
2711 if(ptr)
2712 *ptr++ = '\0';
2713
2714 val = strchr(par, '=');
2715 if(val)
2716 *val++ = '\0';
2717
2718 if (aptr)
2719 {
2720 aptr->av_len = par - aptr->av_val - 1;
2721 aptr = NULL;
2722 }
2723 if (strcmp(par, "user") == 0)
2724 {
2725 user.av_val = val;
2726 aptr = &user;
2727 }
2728 else if (strcmp(par, "salt") == 0)
2729 {
2730 salt.av_val = val;
2731 aptr = &salt;
2732 }
2733 else if (strcmp(par, "opaque") == 0)
2734 {
2735 opaque.av_val = val;
2736 aptr = &opaque;
2737 }
2738 else if (strcmp(par, "challenge") == 0)
2739 {
2740 challenge.av_val = val;
2741 aptr = &challenge;
2742 }
2743
2744 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2745 }
2746 if (aptr)
2747 aptr->av_len = (int)strlen(aptr->av_val);
2748
2749 /* hash1 = base64enc(md5(user + _aodbeAuthSalt + password)) */
2750 MD5_Init(&md5ctx);
2751 MD5_Update(&md5ctx, user.av_val, user.av_len);
2752 MD5_Update(&md5ctx, salt.av_val, salt.av_len);
2753 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2754 MD5_Final(md5sum_val, &md5ctx);
2755 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2756 user.av_val, salt.av_val, r->Link.pubPasswd.av_val);
2757 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2758
2759 b64enc(md5sum_val, MD5_DIGEST_LENGTH, salted2, SALTED2_LEN);
2760 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_1) = %s", __FUNCTION__, salted2);
2761
2762 challenge2_data = rand();
2763
2764 b64enc((unsigned char *) &challenge2_data, sizeof(int), challenge2, CHALLENGE2_LEN);
2765 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(%d) = %s", __FUNCTION__, challenge2_data, challenge2);
2766
2767 MD5_Init(&md5ctx);
2768 MD5_Update(&md5ctx, salted2, B64DIGEST_LEN);
2769 /* response = base64enc(md5(hash1 + opaque + challenge2)) */
2770 if (opaque.av_len)
2771 MD5_Update(&md5ctx, opaque.av_val, opaque.av_len);
2772 else if (challenge.av_len)
2773 MD5_Update(&md5ctx, challenge.av_val, challenge.av_len);
2774 MD5_Update(&md5ctx, challenge2, B64INT_LEN);
2775 MD5_Final(md5sum_val, &md5ctx);
2776
2777 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s%s%s) =>", __FUNCTION__,
2778 salted2, opaque.av_len ? opaque.av_val : "", challenge2);
2779 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2780
2781 b64enc(md5sum_val, MD5_DIGEST_LENGTH, response, RESPONSE_LEN);
2782 RTMP_Log(RTMP_LOGDEBUG, "%s, b64(md5_2) = %s", __FUNCTION__, response);
2783
2784 /* have all hashes, create auth token for the end of app */
2785 pubToken.av_val = malloc(32 + B64INT_LEN + B64DIGEST_LEN + opaque.av_len);
2786 pubToken.av_len = sprintf(pubToken.av_val,
2787 "&challenge=%s&response=%s&opaque=%s",
2788 challenge2,
2789 response,
2790 opaque.av_len ? opaque.av_val : "");
2791 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2792 free(orig_ptr);
2793 r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
2794 }
2795 else if(strstr(description->av_val, "?reason=authfailed") != NULL)
2796 {
2797 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: wrong password", __FUNCTION__);
2798 r->Link.pFlags |= RTMP_PUB_CLEAN;
2799 return 0;
2800 }
2801 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
2802 {
2803 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
2804 r->Link.pFlags |= RTMP_PUB_CLEAN;
2805 return 0;
2806 }
2807 else
2808 {
2809 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
2810 __FUNCTION__, description->av_val);
2811 r->Link.pFlags |= RTMP_PUB_CLEAN;
2812 return 0;
2813 }
2814
2815 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
2816 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
2817 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
2818 r->Link.app.av_len += pubToken.av_len;
2819 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2820 free(r->Link.app.av_val);
2821 r->Link.app.av_val = ptr;
2822
2823 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
2824 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
2825 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
2826 r->Link.tcUrl.av_len += pubToken.av_len;
2827 if(r->Link.pFlags & RTMP_PUB_ALLOC)
2828 free(r->Link.tcUrl.av_val);
2829 r->Link.tcUrl.av_val = ptr;
2830
2831 free(pubToken.av_val);
2832 r->Link.pFlags |= RTMP_PUB_ALLOC;
2833
2834 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
2835 r->Link.app.av_len, r->Link.app.av_val,
2836 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
2837 r->Link.streams[r->Link.curStreamIdx].playpath.av_val);
2838 }
2839 else if (strstr(description->av_val, av_authmod_llnw.av_val) != NULL)
2840 {
2841 if(strstr(description->av_val, "code=403 need auth") != NULL)
2842 {
2843 /* This part seems to be the same for llnw and adobe */
2844
2845 if (strstr(r->Link.app.av_val, av_authmod_llnw.av_val) != NULL)
2846 {
2847 RTMP_Log(RTMP_LOGERROR, "%s, wrong pubUser & pubPasswd for publisher auth", __FUNCTION__);
2848 r->Link.pFlags |= RTMP_PUB_CLEAN;
2849 return 0;
2850 }
2851 else if(r->Link.pubUser.av_len && r->Link.pubPasswd.av_len)
2852 {
2853 pubToken.av_val = malloc(r->Link.pubUser.av_len + av_authmod_llnw.av_len + 8);
2854 pubToken.av_len = sprintf(pubToken.av_val, "?%s&user=%s",
2855 av_authmod_llnw.av_val,
2856 r->Link.pubUser.av_val);
2857 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken1: %s", __FUNCTION__, pubToken.av_val);
2858 r->Link.pFlags |= RTMP_PUB_NAME;
2859 }
2860 else
2861 {
2862 RTMP_Log(RTMP_LOGERROR, "%s, need to set pubUser & pubPasswd for publisher auth", __FUNCTION__);
2863 r->Link.pFlags |= RTMP_PUB_CLEAN;
2864 return 0;
2865 }
2866 }
2867 else if((token_in = strstr(description->av_val, "?reason=needauth")) != NULL)
2868 {
2869 char *orig_ptr;
2870 char *par, *val = NULL;
2871 char hash1[HEXHASH_LEN+1], hash2[HEXHASH_LEN+1], hash3[HEXHASH_LEN+1];
2872 AVal user, nonce, *aptr = NULL;
2873 AVal apptmp;
2874
2875 /* llnw auth method
2876 * Seems to be closely based on HTTP Digest Auth:
2877 * http://tools.ietf.org/html/rfc2617
2878 * http://en.wikipedia.org/wiki/Digest_access_authentication
2879 */
2880
2881 const char authmod[] = "llnw";
2882 const char realm[] = "live";
2883 const char method[] = "publish";
2884 const char qop[] = "auth";
2885 /* nc = 1..connection count (or rather, number of times cnonce has been reused) */
2886 int nc = 1;
2887 /* nchex = hexenc(nc) (8 hex digits according to RFC 2617) */
2888 char nchex[9];
2889 /* cnonce = hexenc(4 random bytes) (initialized on first connection) */
2890 char cnonce[9];
2891
2892 nonce.av_len = user.av_len = 0;
2893 nonce.av_val = user.av_val = NULL;
2894
2895 ptr = orig_ptr = strdup(token_in);
2896 /* Extract parameters (we need user and nonce) */
2897 while (ptr)
2898 {
2899 par = ptr;
2900 ptr = strchr(par, '&');
2901 if(ptr)
2902 *ptr++ = '\0';
2903
2904 val = strchr(par, '=');
2905 if(val)
2906 *val++ = '\0';
2907
2908 if (aptr)
2909 {
2910 aptr->av_len = par - aptr->av_val - 1;
2911 aptr = NULL;
2912 }
2913 if (strcmp(par, "user") == 0)
2914 {
2915 user.av_val = val;
2916 aptr = &user;
2917 }
2918 else if (strcmp(par, "nonce") == 0)
2919 {
2920 nonce.av_val = val;
2921 aptr = &nonce;
2922 }
2923
2924 RTMP_Log(RTMP_LOGDEBUG, "%s, par:\"%s\" = val:\"%s\"", __FUNCTION__, par, val);
2925 }
2926 if (aptr)
2927 aptr->av_len = (int)strlen(aptr->av_val);
2928
2929 /* FIXME: handle case where user==NULL or nonce==NULL */
2930
2931 sprintf(nchex, "%08x", nc);
2932 sprintf(cnonce, "%08x", rand());
2933
2934 /* hash1 = hexenc(md5(user + ":" + realm + ":" + password)) */
2935 MD5_Init(&md5ctx);
2936 MD5_Update(&md5ctx, user.av_val, user.av_len);
2937 MD5_Update(&md5ctx, ":", 1);
2938 MD5_Update(&md5ctx, (void *)realm, sizeof(realm)-1);
2939 MD5_Update(&md5ctx, ":", 1);
2940 MD5_Update(&md5ctx, r->Link.pubPasswd.av_val, r->Link.pubPasswd.av_len);
2941 MD5_Final(md5sum_val, &md5ctx);
2942 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s) =>", __FUNCTION__,
2943 user.av_val, realm, r->Link.pubPasswd.av_val);
2944 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2945 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash1);
2946
2947 /* hash2 = hexenc(md5(method + ":/" + app + "/" + appInstance)) */
2948 /* Extract appname + appinstance without query parameters */
2949 apptmp = r->Link.app;
2950 ptr = AValChr(&apptmp, '?');
2951 if (ptr)
2952 apptmp.av_len = ptr - apptmp.av_val;
2953
2954 MD5_Init(&md5ctx);
2955 MD5_Update(&md5ctx, (void *)method, sizeof(method)-1);
2956 MD5_Update(&md5ctx, ":/", 2);
2957 MD5_Update(&md5ctx, apptmp.av_val, apptmp.av_len);
2958 if (!AValChr(&apptmp, '/'))
2959 MD5_Update(&md5ctx, "/_definst_", sizeof("/_definst_") - 1);
2960 MD5_Final(md5sum_val, &md5ctx);
2961 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:/%.*s) =>", __FUNCTION__,
2962 method, apptmp.av_len, apptmp.av_val);
2963 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2964 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash2);
2965
2966 /* hash3 = hexenc(md5(hash1 + ":" + nonce + ":" + nchex + ":" + cnonce + ":" + qop + ":" + hash2)) */
2967 MD5_Init(&md5ctx);
2968 MD5_Update(&md5ctx, hash1, HEXHASH_LEN);
2969 MD5_Update(&md5ctx, ":", 1);
2970 MD5_Update(&md5ctx, nonce.av_val, nonce.av_len);
2971 MD5_Update(&md5ctx, ":", 1);
2972 MD5_Update(&md5ctx, nchex, sizeof(nchex)-1);
2973 MD5_Update(&md5ctx, ":", 1);
2974 MD5_Update(&md5ctx, cnonce, sizeof(cnonce)-1);
2975 MD5_Update(&md5ctx, ":", 1);
2976 MD5_Update(&md5ctx, (void *)qop, sizeof(qop)-1);
2977 MD5_Update(&md5ctx, ":", 1);
2978 MD5_Update(&md5ctx, hash2, HEXHASH_LEN);
2979 MD5_Final(md5sum_val, &md5ctx);
2980 RTMP_Log(RTMP_LOGDEBUG, "%s, md5(%s:%s:%s:%s:%s:%s) =>", __FUNCTION__,
2981 hash1, nonce.av_val, nchex, cnonce, qop, hash2);
2982 RTMP_LogHexString(RTMP_LOGDEBUG, md5sum_val, MD5_DIGEST_LENGTH);
2983 hexenc(md5sum_val, MD5_DIGEST_LENGTH, hash3);
2984
2985 /* pubToken = &authmod=<authmod>&user=<username>&nonce=<nonce>&cnonce=<cnonce>&nc=<nchex>&response=<hash3> */
2986 /* Append nonces and response to query string which already contains
2987 * user + authmod */
2988 pubToken.av_val = malloc(64 + sizeof(authmod)-1 + user.av_len + nonce.av_len + sizeof(cnonce)-1 + sizeof(nchex)-1 + HEXHASH_LEN);
2989 sprintf(pubToken.av_val,
2990 "&nonce=%s&cnonce=%s&nc=%s&response=%s",
2991 nonce.av_val, cnonce, nchex, hash3);
2992 pubToken.av_len = (int)strlen(pubToken.av_val);
2993 RTMP_Log(RTMP_LOGDEBUG, "%s, pubToken2: %s", __FUNCTION__, pubToken.av_val);
2994 r->Link.pFlags |= RTMP_PUB_RESP|RTMP_PUB_CLATE;
2995
2996 free(orig_ptr);
2997 }
2998 else if(strstr(description->av_val, "?reason=authfail") != NULL)
2999 {
3000 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed", __FUNCTION__);
3001 r->Link.pFlags |= RTMP_PUB_CLEAN;
3002 return 0;
3003 }
3004 else if(strstr(description->av_val, "?reason=nosuchuser") != NULL)
3005 {
3006 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: no such user", __FUNCTION__);
3007 r->Link.pFlags |= RTMP_PUB_CLEAN;
3008 return 0;
3009 }
3010 else
3011 {
3012 RTMP_Log(RTMP_LOGERROR, "%s, Authentication failed: unknown auth mode: %s",
3013 __FUNCTION__, description->av_val);
3014 r->Link.pFlags |= RTMP_PUB_CLEAN;
3015 return 0;
3016 }
3017
3018 ptr = malloc(r->Link.app.av_len + pubToken.av_len);
3019 strncpy(ptr, r->Link.app.av_val, r->Link.app.av_len);
3020 strncpy(ptr + r->Link.app.av_len, pubToken.av_val, pubToken.av_len);
3021 r->Link.app.av_len += pubToken.av_len;
3022 if(r->Link.pFlags & RTMP_PUB_ALLOC)
3023 free(r->Link.app.av_val);
3024 r->Link.app.av_val = ptr;
3025
3026 ptr = malloc(r->Link.tcUrl.av_len + pubToken.av_len);
3027 strncpy(ptr, r->Link.tcUrl.av_val, r->Link.tcUrl.av_len);
3028 strncpy(ptr + r->Link.tcUrl.av_len, pubToken.av_val, pubToken.av_len);
3029 r->Link.tcUrl.av_len += pubToken.av_len;
3030 if(r->Link.pFlags & RTMP_PUB_ALLOC)
3031 free(r->Link.tcUrl.av_val);
3032 r->Link.tcUrl.av_val = ptr;
3033
3034 free(pubToken.av_val);
3035 r->Link.pFlags |= RTMP_PUB_ALLOC;
3036
3037 RTMP_Log(RTMP_LOGDEBUG, "%s, new app: %.*s tcUrl: %.*s playpath: %s", __FUNCTION__,
3038 r->Link.app.av_len, r->Link.app.av_val,
3039 r->Link.tcUrl.av_len, r->Link.tcUrl.av_val,
3040 r->Link.streams[r->Link.curStreamIdx].playpath.av_val);
3041 }
3042 else
3043 {
3044 return 0;
3045 }
3046 return 1;
3047 }
3048 #endif
3049
3050
3051 SAVC(onBWDone);
3052 SAVC(onFCSubscribe);
3053 SAVC(onFCUnsubscribe);
3054 SAVC(_onbwcheck);
3055 SAVC(_onbwdone);
3056 SAVC(_error);
3057 SAVC(close);
3058 SAVC(code);
3059 SAVC(level);
3060 SAVC(description);
3061 SAVC(onStatus);
3062 SAVC(playlist_ready);
3063 static const AVal av_NetStream_Failed = AVC("NetStream.Failed");
3064 static const AVal av_NetStream_Play_Failed = AVC("NetStream.Play.Failed");
3065 static const AVal av_NetStream_Play_StreamNotFound =
3066 AVC("NetStream.Play.StreamNotFound");
3067 static const AVal av_NetConnection_Connect_InvalidApp =
3068 AVC("NetConnection.Connect.InvalidApp");
3069 static const AVal av_NetStream_Play_Start = AVC("NetStream.Play.Start");
3070 static const AVal av_NetStream_Play_Complete = AVC("NetStream.Play.Complete");
3071 static const AVal av_NetStream_Play_Stop = AVC("NetStream.Play.Stop");
3072 static const AVal av_NetStream_Seek_Notify = AVC("NetStream.Seek.Notify");
3073 static const AVal av_NetStream_Pause_Notify = AVC("NetStream.Pause.Notify");
3074 static const AVal av_NetStream_Play_PublishNotify =
3075 AVC("NetStream.Play.PublishNotify");
3076 static const AVal av_NetStream_Play_UnpublishNotify =
3077 AVC("NetStream.Play.UnpublishNotify");
3078 static const AVal av_NetStream_Publish_Start = AVC("NetStream.Publish.Start");
3079 static const AVal av_NetStream_Publish_Rejected = AVC("NetStream.Publish.Rejected");
3080 static const AVal av_NetStream_Publish_Denied = AVC("NetStream.Publish.Denied");
3081 static const AVal av_NetStream_Publish_BadName = AVC("NetStream.Publish.BadName");
3082
3083
3084 /* Returns 0 for OK/Failed/error, 1 for 'Stop or Complete' */
3085 static int
HandleInvoke(RTMP * r,const char * body,unsigned int nBodySize)3086 HandleInvoke(RTMP *r, const char *body, unsigned int nBodySize)
3087 {
3088 AMFObject obj;
3089 AVal method;
3090 double txn;
3091 int ret = 0, nRes;
3092 if (body[0] != 0x02) /* make sure it is a string method name we start with */
3093 {
3094 RTMP_Log(RTMP_LOGWARNING, "%s, Sanity failed. no string method in invoke packet",
3095 __FUNCTION__);
3096 return 0;
3097 }
3098
3099 nRes = AMF_Decode(&obj, body, nBodySize, FALSE);
3100 if (nRes < 0)
3101 {
3102 RTMP_Log(RTMP_LOGERROR, "%s, error decoding invoke packet", __FUNCTION__);
3103 return 0;
3104 }
3105
3106 AMF_Dump(&obj);
3107 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &method);
3108 txn = AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 1));
3109 RTMP_Log(RTMP_LOGDEBUG, "%s, server invoking <%s>", __FUNCTION__, method.av_val);
3110
3111 if (AVMATCH(&method, &av__result))
3112 {
3113 AVal methodInvoked = {0};
3114 int i;
3115
3116 for (i=0; i<r->m_numCalls; i++)
3117 {
3118 if (r->m_methodCalls[i].num == (int)txn)
3119 {
3120 methodInvoked = r->m_methodCalls[i].name;
3121 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
3122 break;
3123 }
3124 }
3125 if (!methodInvoked.av_val)
3126 {
3127 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
3128 __FUNCTION__, txn);
3129 goto leave;
3130 }
3131
3132 RTMP_Log(RTMP_LOGDEBUG, "%s, received result for method call <%s>", __FUNCTION__,
3133 methodInvoked.av_val);
3134
3135 if (AVMATCH(&methodInvoked, &av_connect))
3136 {
3137 if (r->Link.token.av_len)
3138 {
3139 AMFObjectProperty p;
3140 if (RTMP_FindFirstMatchingProperty(&obj, &av_secureToken, &p))
3141 {
3142 DecodeTEA(&r->Link.token, &p.p_vu.p_aval);
3143 SendSecureTokenResponse(r, &p.p_vu.p_aval);
3144 }
3145 }
3146 if (r->Link.protocol & RTMP_FEATURE_WRITE)
3147 {
3148 for (int i = 0; i < r->Link.nStreams; i++)
3149 SendReleaseStream(r, i);
3150 for (int i = 0; i < r->Link.nStreams; i++)
3151 SendFCPublish(r, i);
3152 }
3153 else
3154 {
3155 RTMP_SendServerBW(r);
3156 RTMP_SendCtrl(r, 3, 0, 300);
3157 }
3158
3159 for (int i = 0; i < r->Link.nStreams; i++)
3160 RTMP_SendCreateStream(r);
3161
3162 if (!(r->Link.protocol & RTMP_FEATURE_WRITE))
3163 {
3164 /* Authenticate on Justin.tv legacy servers before sending FCSubscribe */
3165 if (r->Link.usherToken.av_len)
3166 SendUsherToken(r, &r->Link.usherToken);
3167 /* Send the FCSubscribe if live stream or if subscribepath is set */
3168 if (r->Link.subscribepath.av_len)
3169 SendFCSubscribe(r, &r->Link.subscribepath);
3170 else if (r->Link.lFlags & RTMP_LF_LIVE)
3171 {
3172 for (int i = 0; i < r->Link.nStreams; i++)
3173 SendFCSubscribe(r, &r->Link.streams[i].playpath);
3174 }
3175 }
3176 }
3177 else if (AVMATCH(&methodInvoked, &av_createStream))
3178 {
3179 int id = (int)AMFProp_GetNumber(AMF_GetProp(&obj, NULL, 3));
3180 r->Link.streams[r->Link.curStreamIdx].id = id;
3181
3182 if (r->Link.protocol & RTMP_FEATURE_WRITE)
3183 SendPublish(r, r->Link.curStreamIdx);
3184 else
3185 {
3186 if (r->Link.lFlags & RTMP_LF_PLST)
3187 SendPlaylist(r, r->Link.curStreamIdx);
3188 SendPlay(r, r->Link.curStreamIdx);
3189 RTMP_SendCtrl(r, 3, id, r->m_nBufferMS);
3190 }
3191
3192 r->Link.curStreamIdx++;
3193 }
3194 else if (AVMATCH(&methodInvoked, &av_play) ||
3195 AVMATCH(&methodInvoked, &av_publish))
3196 {
3197 r->m_bPlaying = TRUE;
3198 r->Link.playingStreams++;
3199 }
3200 free(methodInvoked.av_val);
3201 }
3202 else if (AVMATCH(&method, &av_onBWDone))
3203 {
3204 if (!r->m_nBWCheckCounter)
3205 SendCheckBW(r);
3206 }
3207 else if (AVMATCH(&method, &av_onFCSubscribe))
3208 {
3209 /* SendOnFCSubscribe(); */
3210 }
3211 else if (AVMATCH(&method, &av_onFCUnsubscribe))
3212 {
3213 RTMP_Close(r);
3214 ret = 1;
3215 }
3216 else if (AVMATCH(&method, &av_ping))
3217 {
3218 SendPong(r, txn);
3219 }
3220 else if (AVMATCH(&method, &av__onbwcheck))
3221 {
3222 SendCheckBWResult(r, txn);
3223 }
3224 else if (AVMATCH(&method, &av__onbwdone))
3225 {
3226 int i;
3227 for (i = 0; i < r->m_numCalls; i++)
3228 if (AVMATCH(&r->m_methodCalls[i].name, &av__checkbw))
3229 {
3230 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3231 break;
3232 }
3233 }
3234 else if (AVMATCH(&method, &av__error))
3235 {
3236 #if defined(CRYPTO) || defined(USE_ONLY_MD5)
3237 AVal methodInvoked = {0};
3238 int i;
3239
3240 if (r->Link.protocol & RTMP_FEATURE_WRITE)
3241 {
3242 for (i=0; i<r->m_numCalls; i++)
3243 {
3244 if (r->m_methodCalls[i].num == txn)
3245 {
3246 methodInvoked = r->m_methodCalls[i].name;
3247 AV_erase(r->m_methodCalls, &r->m_numCalls, i, FALSE);
3248 break;
3249 }
3250 }
3251 if (!methodInvoked.av_val)
3252 {
3253 RTMP_Log(RTMP_LOGDEBUG, "%s, received result id %f without matching request",
3254 __FUNCTION__, txn);
3255 goto leave;
3256 }
3257
3258 RTMP_Log(RTMP_LOGDEBUG, "%s, received error for method call <%s>", __FUNCTION__,
3259 methodInvoked.av_val);
3260
3261 if (AVMATCH(&methodInvoked, &av_connect))
3262 {
3263 AMFObject obj2;
3264 AVal code, level, description;
3265 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3266 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3267 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3268 AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
3269 RTMP_Log(RTMP_LOGDEBUG, "%s, error description: %s", __FUNCTION__, description.av_val);
3270 /* if PublisherAuth returns 1, then reconnect */
3271 if (PublisherAuth(r, &description) == 1)
3272 {
3273 RTMP_Close(r);
3274 if (r->Link.pFlags & RTMP_PUB_CLATE)
3275 {
3276 r->Link.pFlags |= RTMP_PUB_CLEAN;
3277 }
3278 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
3279 {
3280 goto leave;
3281 }
3282 }
3283 }
3284 }
3285 else
3286 {
3287 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3288 }
3289 free(methodInvoked.av_val);
3290 #else
3291 RTMP_Log(RTMP_LOGERROR, "rtmp server sent error");
3292 #endif
3293 }
3294 else if (AVMATCH(&method, &av_close))
3295 {
3296 RTMP_Log(RTMP_LOGERROR, "rtmp server requested close");
3297 RTMP_Close(r);
3298
3299 // disabled this for now, if the server sends an rtmp close message librtmp
3300 // will enter an infinite loop here until stack is exhausted.
3301 #if 0 && (defined(CRYPTO) || defined(USE_ONLY_MD5))
3302 if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
3303 !(r->Link.pFlags & RTMP_PUB_CLEAN) &&
3304 ( !(r->Link.pFlags & RTMP_PUB_NAME) ||
3305 !(r->Link.pFlags & RTMP_PUB_RESP) ||
3306 (r->Link.pFlags & RTMP_PUB_CLATE) ) )
3307 {
3308 /* clean later */
3309 if(r->Link.pFlags & RTMP_PUB_CLATE)
3310 r->Link.pFlags |= RTMP_PUB_CLEAN;
3311 RTMP_Log(RTMP_LOGERROR, "authenticating publisher");
3312
3313 if (!RTMP_Connect(r, NULL) || !RTMP_ConnectStream(r, 0))
3314 goto leave;
3315 }
3316 #endif
3317 }
3318 else if (AVMATCH(&method, &av_onStatus))
3319 {
3320 AMFObject obj2;
3321 AVal code, level, description;
3322 AMFProp_GetObject(AMF_GetProp(&obj, NULL, 3), &obj2);
3323 AMFProp_GetString(AMF_GetProp(&obj2, &av_code, -1), &code);
3324 AMFProp_GetString(AMF_GetProp(&obj2, &av_level, -1), &level);
3325 AMFProp_GetString(AMF_GetProp(&obj2, &av_description, -1), &description);
3326
3327 RTMP_Log(RTMP_LOGDEBUG, "%s, onStatus: %s", __FUNCTION__, code.av_val);
3328 if (AVMATCH(&code, &av_NetStream_Failed)
3329 || AVMATCH(&code, &av_NetStream_Play_Failed)
3330 || AVMATCH(&code, &av_NetStream_Play_StreamNotFound)
3331 || AVMATCH(&code, &av_NetConnection_Connect_InvalidApp)
3332 || AVMATCH(&code, &av_NetStream_Publish_Rejected)
3333 || AVMATCH(&code, &av_NetStream_Publish_Denied)
3334 || AVMATCH(&code, &av_NetStream_Publish_BadName))
3335 {
3336 r->m_stream_id = -1;
3337 RTMP_Close(r);
3338
3339 if (description.av_len)
3340 RTMP_Log(RTMP_LOGERROR, "%s:\n%s (%s)", r->Link.tcUrl.av_val, code.av_val, description.av_val);
3341 else
3342 RTMP_Log(RTMP_LOGERROR, "%s:\n%s", r->Link.tcUrl.av_val, code.av_val);
3343 }
3344
3345 else if (AVMATCH(&code, &av_NetStream_Play_Start)
3346 || AVMATCH(&code, &av_NetStream_Play_PublishNotify))
3347 {
3348 int i;
3349 r->m_bPlaying = TRUE;
3350 for (i = 0; i < r->m_numCalls; i++)
3351 {
3352 if (AVMATCH(&r->m_methodCalls[i].name, &av_play))
3353 {
3354 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3355 break;
3356 }
3357 }
3358 }
3359
3360 else if (AVMATCH(&code, &av_NetStream_Publish_Start))
3361 {
3362 int i;
3363 r->m_bPlaying = TRUE;
3364 for (i = 0; i < r->m_numCalls; i++)
3365 {
3366 if (AVMATCH(&r->m_methodCalls[i].name, &av_publish))
3367 {
3368 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3369 break;
3370 }
3371 }
3372 }
3373
3374 /* Return 1 if this is a Play.Complete or Play.Stop */
3375 else if (AVMATCH(&code, &av_NetStream_Play_Complete)
3376 || AVMATCH(&code, &av_NetStream_Play_Stop)
3377 || AVMATCH(&code, &av_NetStream_Play_UnpublishNotify))
3378 {
3379 RTMP_Close(r);
3380 ret = 1;
3381 }
3382
3383 else if (AVMATCH(&code, &av_NetStream_Seek_Notify))
3384 {
3385 r->m_read.flags &= ~RTMP_READ_SEEKING;
3386 }
3387
3388 else if (AVMATCH(&code, &av_NetStream_Pause_Notify))
3389 {
3390 if (r->m_pausing == 1 || r->m_pausing == 2)
3391 {
3392 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3393 r->m_pausing = 3;
3394 }
3395 }
3396
3397 else
3398 {
3399 RTMP_Log(RTMP_LOGWARNING, "Unhandled: %s:\n%s", r->Link.tcUrl.av_val, code.av_val);
3400 if (description.av_len)
3401 RTMP_Log(RTMP_LOGDEBUG, "Description: %s", description.av_val);
3402 }
3403 }
3404 else if (AVMATCH(&method, &av_playlist_ready))
3405 {
3406 int i;
3407 for (i = 0; i < r->m_numCalls; i++)
3408 {
3409 if (AVMATCH(&r->m_methodCalls[i].name, &av_set_playlist))
3410 {
3411 AV_erase(r->m_methodCalls, &r->m_numCalls, i, TRUE);
3412 break;
3413 }
3414 }
3415 }
3416 else
3417 {
3418
3419 }
3420 leave:
3421 AMF_Reset(&obj);
3422 return ret;
3423 }
3424
3425 int
RTMP_FindFirstMatchingProperty(AMFObject * obj,const AVal * name,AMFObjectProperty * p)3426 RTMP_FindFirstMatchingProperty(AMFObject *obj, const AVal *name,
3427 AMFObjectProperty * p)
3428 {
3429 int n;
3430 /* this is a small object search to locate the "duration" property */
3431 for (n = 0; n < obj->o_num; n++)
3432 {
3433 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3434
3435 if (AVMATCH(&prop->p_name, name))
3436 {
3437 memcpy(p, prop, sizeof(*prop));
3438 return TRUE;
3439 }
3440
3441 if (prop->p_type == AMF_OBJECT || prop->p_type == AMF_ECMA_ARRAY)
3442 {
3443 if (RTMP_FindFirstMatchingProperty(&prop->p_vu.p_object, name, p))
3444 return TRUE;
3445 }
3446 }
3447 return FALSE;
3448 }
3449
3450 /* Like above, but only check if name is a prefix of property */
3451 int
RTMP_FindPrefixProperty(AMFObject * obj,const AVal * name,AMFObjectProperty * p)3452 RTMP_FindPrefixProperty(AMFObject *obj, const AVal *name,
3453 AMFObjectProperty * p)
3454 {
3455 int n;
3456 for (n = 0; n < obj->o_num; n++)
3457 {
3458 AMFObjectProperty *prop = AMF_GetProp(obj, NULL, n);
3459
3460 if (prop->p_name.av_len > name->av_len &&
3461 !memcmp(prop->p_name.av_val, name->av_val, name->av_len))
3462 {
3463 memcpy(p, prop, sizeof(*prop));
3464 return TRUE;
3465 }
3466
3467 if (prop->p_type == AMF_OBJECT)
3468 {
3469 if (RTMP_FindPrefixProperty(&prop->p_vu.p_object, name, p))
3470 return TRUE;
3471 }
3472 }
3473 return FALSE;
3474 }
3475
3476 static int
DumpMetaData(AMFObject * obj)3477 DumpMetaData(AMFObject *obj)
3478 {
3479 AMFObjectProperty *prop;
3480 int n, len;
3481 for (n = 0; n < obj->o_num; n++)
3482 {
3483 char str[256] = "";
3484 prop = AMF_GetProp(obj, NULL, n);
3485 switch (prop->p_type)
3486 {
3487 case AMF_OBJECT:
3488 case AMF_ECMA_ARRAY:
3489 case AMF_STRICT_ARRAY:
3490 if (prop->p_name.av_len)
3491 RTMP_Log(RTMP_LOGINFO, "%.*s:", prop->p_name.av_len, prop->p_name.av_val);
3492 DumpMetaData(&prop->p_vu.p_object);
3493 break;
3494 case AMF_NUMBER:
3495 snprintf(str, 255, "%.2f", prop->p_vu.p_number);
3496 break;
3497 case AMF_BOOLEAN:
3498 snprintf(str, 255, "%s",
3499 prop->p_vu.p_number != 0. ? "TRUE" : "FALSE");
3500 break;
3501 case AMF_STRING:
3502 len = snprintf(str, 255, "%.*s", prop->p_vu.p_aval.av_len,
3503 prop->p_vu.p_aval.av_val);
3504 if (len >= 1 && str[len-1] == '\n')
3505 str[len-1] = '\0';
3506 break;
3507 case AMF_DATE:
3508 snprintf(str, 255, "timestamp:%.2f", prop->p_vu.p_number);
3509 break;
3510 default:
3511 snprintf(str, 255, "INVALID TYPE 0x%02x",
3512 (unsigned char)prop->p_type);
3513 }
3514 if (str[0] && prop->p_name.av_len)
3515 {
3516 RTMP_Log(RTMP_LOGINFO, " %-22.*s%s", prop->p_name.av_len,
3517 prop->p_name.av_val, str);
3518 }
3519 }
3520 return FALSE;
3521 }
3522
3523 SAVC(onMetaData);
3524 SAVC(duration);
3525 SAVC(video);
3526 SAVC(audio);
3527
3528 static int
HandleMetadata(RTMP * r,char * body,unsigned int len)3529 HandleMetadata(RTMP *r, char *body, unsigned int len)
3530 {
3531 /* allright we get some info here, so parse it and print it */
3532 /* also keep duration or filesize to make a nice progress bar */
3533
3534 AMFObject obj;
3535 AVal metastring;
3536 int ret = FALSE;
3537
3538 int nRes = AMF_Decode(&obj, body, len, FALSE);
3539 if (nRes < 0)
3540 {
3541 RTMP_Log(RTMP_LOGERROR, "%s, error decoding meta data packet", __FUNCTION__);
3542 return FALSE;
3543 }
3544
3545 AMF_Dump(&obj);
3546 AMFProp_GetString(AMF_GetProp(&obj, NULL, 0), &metastring);
3547
3548 if (AVMATCH(&metastring, &av_onMetaData))
3549 {
3550 AMFObjectProperty prop;
3551 /* Show metadata */
3552 RTMP_Log(RTMP_LOGINFO, "Metadata:");
3553 DumpMetaData(&obj);
3554 if (RTMP_FindFirstMatchingProperty(&obj, &av_duration, &prop))
3555 {
3556 r->m_fDuration = prop.p_vu.p_number;
3557 /*RTMP_Log(RTMP_LOGDEBUG, "Set duration: %.2f", m_fDuration); */
3558 }
3559 /* Search for audio or video tags */
3560 if (RTMP_FindPrefixProperty(&obj, &av_video, &prop))
3561 r->m_read.dataType |= 1;
3562 if (RTMP_FindPrefixProperty(&obj, &av_audio, &prop))
3563 r->m_read.dataType |= 4;
3564 ret = TRUE;
3565 }
3566 AMF_Reset(&obj);
3567 return ret;
3568 }
3569
3570 static void
HandleChangeChunkSize(RTMP * r,const RTMPPacket * packet)3571 HandleChangeChunkSize(RTMP *r, const RTMPPacket *packet)
3572 {
3573 if (packet->m_nBodySize >= 4)
3574 {
3575 r->m_inChunkSize = AMF_DecodeInt32(packet->m_body);
3576 RTMP_Log(RTMP_LOGDEBUG, "%s, received: chunk size change to %d", __FUNCTION__,
3577 r->m_inChunkSize);
3578 }
3579 }
3580
3581 static void
HandleAudio(RTMP * r,const RTMPPacket * packet)3582 HandleAudio(RTMP *r, const RTMPPacket *packet)
3583 {
3584 (void)r;
3585 (void)packet;
3586 }
3587
3588 static void
HandleVideo(RTMP * r,const RTMPPacket * packet)3589 HandleVideo(RTMP *r, const RTMPPacket *packet)
3590 {
3591 (void)r;
3592 (void)packet;
3593 }
3594
3595 static void
HandleCtrl(RTMP * r,const RTMPPacket * packet)3596 HandleCtrl(RTMP *r, const RTMPPacket *packet)
3597 {
3598 short nType = -1;
3599 unsigned int tmp;
3600 if (packet->m_body && packet->m_nBodySize >= 2)
3601 nType = AMF_DecodeInt16(packet->m_body);
3602 RTMP_Log(RTMP_LOGDEBUG, "%s, received ctrl. type: %d, len: %d", __FUNCTION__, nType,
3603 packet->m_nBodySize);
3604 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3605
3606 if (packet->m_nBodySize >= 6)
3607 {
3608 switch (nType)
3609 {
3610 case 0:
3611 tmp = AMF_DecodeInt32(packet->m_body + 2);
3612 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Begin %d", __FUNCTION__, tmp);
3613 break;
3614
3615 case 1:
3616 tmp = AMF_DecodeInt32(packet->m_body + 2);
3617 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream EOF %d", __FUNCTION__, tmp);
3618 if (r->m_pausing == 1)
3619 r->m_pausing = 2;
3620 break;
3621
3622 case 2:
3623 tmp = AMF_DecodeInt32(packet->m_body + 2);
3624 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream Dry %d", __FUNCTION__, tmp);
3625 break;
3626
3627 case 4:
3628 tmp = AMF_DecodeInt32(packet->m_body + 2);
3629 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream IsRecorded %d", __FUNCTION__, tmp);
3630 break;
3631
3632 case 6: /* server ping. reply with pong. */
3633 tmp = AMF_DecodeInt32(packet->m_body + 2);
3634 RTMP_Log(RTMP_LOGDEBUG, "%s, Ping %d", __FUNCTION__, tmp);
3635 RTMP_SendCtrl(r, 0x07, tmp, 0);
3636 break;
3637
3638 /* FMS 3.5 servers send the following two controls to let the client
3639 * know when the server has sent a complete buffer. I.e., when the
3640 * server has sent an amount of data equal to m_nBufferMS in duration.
3641 * The server meters its output so that data arrives at the client
3642 * in realtime and no faster.
3643 *
3644 * The rtmpdump program tries to set m_nBufferMS as large as
3645 * possible, to force the server to send data as fast as possible.
3646 * In practice, the server appears to cap this at about 1 hour's
3647 * worth of data. After the server has sent a complete buffer, and
3648 * sends this BufferEmpty message, it will wait until the play
3649 * duration of that buffer has passed before sending a new buffer.
3650 * The BufferReady message will be sent when the new buffer starts.
3651 * (There is no BufferReady message for the very first buffer;
3652 * presumably the Stream Begin message is sufficient for that
3653 * purpose.)
3654 *
3655 * If the network speed is much faster than the data bitrate, then
3656 * there may be long delays between the end of one buffer and the
3657 * start of the next.
3658 *
3659 * Since usually the network allows data to be sent at
3660 * faster than realtime, and rtmpdump wants to download the data
3661 * as fast as possible, we use this RTMP_LF_BUFX hack: when we
3662 * get the BufferEmpty message, we send a Pause followed by an
3663 * Unpause. This causes the server to send the next buffer immediately
3664 * instead of waiting for the full duration to elapse. (That's
3665 * also the purpose of the ToggleStream function, which rtmpdump
3666 * calls if we get a read timeout.)
3667 *
3668 * Media player apps don't need this hack since they are just
3669 * going to play the data in realtime anyway. It also doesn't work
3670 * for live streams since they obviously can only be sent in
3671 * realtime. And it's all moot if the network speed is actually
3672 * slower than the media bitrate.
3673 */
3674 case 31:
3675 tmp = AMF_DecodeInt32(packet->m_body + 2);
3676 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferEmpty %d", __FUNCTION__, tmp);
3677 if (!(r->Link.lFlags & RTMP_LF_BUFX))
3678 break;
3679 if (!r->m_pausing)
3680 {
3681 r->m_pauseStamp = r->m_mediaChannel < r->m_channelsAllocatedIn ?
3682 r->m_channelTimestamp[r->m_mediaChannel] : 0;
3683 RTMP_SendPause(r, TRUE, r->m_pauseStamp);
3684 r->m_pausing = 1;
3685 }
3686 else if (r->m_pausing == 2)
3687 {
3688 RTMP_SendPause(r, FALSE, r->m_pauseStamp);
3689 r->m_pausing = 3;
3690 }
3691 break;
3692
3693 case 32:
3694 tmp = AMF_DecodeInt32(packet->m_body + 2);
3695 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream BufferReady %d", __FUNCTION__, tmp);
3696 break;
3697
3698 default:
3699 tmp = AMF_DecodeInt32(packet->m_body + 2);
3700 RTMP_Log(RTMP_LOGDEBUG, "%s, Stream xx %d", __FUNCTION__, tmp);
3701 break;
3702 }
3703
3704 }
3705
3706 if (nType == 0x1A)
3707 {
3708 RTMP_Log(RTMP_LOGDEBUG, "%s, SWFVerification ping received: ", __FUNCTION__);
3709 if (packet->m_nBodySize > 2 && packet->m_body[2] > 0x01)
3710 {
3711 RTMP_Log(RTMP_LOGERROR,
3712 "%s: SWFVerification Type %d request not supported! Patches welcome...",
3713 __FUNCTION__, packet->m_body[2]);
3714 }
3715 #ifdef CRYPTO
3716 /*RTMP_LogHex(packet.m_body, packet.m_nBodySize); */
3717
3718 /* respond with HMAC SHA256 of decompressed SWF, key is the 30byte player key, also the last 30 bytes of the server handshake are applied */
3719 else if (r->Link.SWFSize)
3720 {
3721 RTMP_SendCtrl(r, 0x1B, 0, 0);
3722 }
3723 else
3724 {
3725 RTMP_Log(RTMP_LOGERROR,
3726 "%s: Ignoring SWFVerification request, use --swfVfy!",
3727 __FUNCTION__);
3728 }
3729 #else
3730 RTMP_Log(RTMP_LOGERROR,
3731 "%s: Ignoring SWFVerification request, no CRYPTO support!",
3732 __FUNCTION__);
3733 #endif
3734 }
3735 }
3736
3737 static void
HandleServerBW(RTMP * r,const RTMPPacket * packet)3738 HandleServerBW(RTMP *r, const RTMPPacket *packet)
3739 {
3740 r->m_nServerBW = AMF_DecodeInt32(packet->m_body);
3741 RTMP_Log(RTMP_LOGDEBUG, "%s: server BW = %d", __FUNCTION__, r->m_nServerBW);
3742 }
3743
3744 static void
HandleClientBW(RTMP * r,const RTMPPacket * packet)3745 HandleClientBW(RTMP *r, const RTMPPacket *packet)
3746 {
3747 r->m_nClientBW = AMF_DecodeInt32(packet->m_body);
3748 if (packet->m_nBodySize > 4)
3749 r->m_nClientBW2 = packet->m_body[4];
3750 else
3751 r->m_nClientBW2 = -1;
3752 RTMP_Log(RTMP_LOGDEBUG, "%s: client BW = %d %d", __FUNCTION__, r->m_nClientBW,
3753 r->m_nClientBW2);
3754 }
3755
3756 static int
DecodeInt32LE(const char * data)3757 DecodeInt32LE(const char *data)
3758 {
3759 unsigned char *c = (unsigned char *)data;
3760 unsigned int val;
3761
3762 val = (c[3] << 24) | (c[2] << 16) | (c[1] << 8) | c[0];
3763 return val;
3764 }
3765
3766 static int
EncodeInt32LE(char * output,int nVal)3767 EncodeInt32LE(char *output, int nVal)
3768 {
3769 output[0] = nVal;
3770 nVal >>= 8;
3771 output[1] = nVal;
3772 nVal >>= 8;
3773 output[2] = nVal;
3774 nVal >>= 8;
3775 output[3] = nVal;
3776 return 4;
3777 }
3778
3779 int
RTMP_ReadPacket(RTMP * r,RTMPPacket * packet)3780 RTMP_ReadPacket(RTMP *r, RTMPPacket *packet)
3781 {
3782 uint8_t hbuf[RTMP_MAX_HEADER_SIZE] = { 0 };
3783 char *header = (char *)hbuf;
3784 int nSize, hSize, nToRead, nChunk;
3785 // int didAlloc = FALSE;
3786 int extendedTimestamp = 0;
3787
3788 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d", __FUNCTION__, (int)r->m_sb.sb_socket);
3789
3790 if (ReadN(r, (char *)hbuf, 1) == 0)
3791 {
3792 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to read RTMP packet header", __FUNCTION__);
3793 return FALSE;
3794 }
3795
3796 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3797 packet->m_nChannel = (hbuf[0] & 0x3f);
3798 header++;
3799 if (packet->m_nChannel == 0)
3800 {
3801 if (ReadN(r, (char *)&hbuf[1], 1) != 1)
3802 {
3803 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 2nd byte",
3804 __FUNCTION__);
3805 return FALSE;
3806 }
3807 packet->m_nChannel = hbuf[1];
3808 packet->m_nChannel += 64;
3809 header++;
3810 }
3811 else if (packet->m_nChannel == 1)
3812 {
3813 int tmp;
3814 if (ReadN(r, (char *)&hbuf[1], 2) != 2)
3815 {
3816 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header 3nd byte",
3817 __FUNCTION__);
3818 return FALSE;
3819 }
3820 tmp = (hbuf[2] << 8) + hbuf[1];
3821 packet->m_nChannel = tmp + 64;
3822 RTMP_Log(RTMP_LOGDEBUG, "%s, m_nChannel: %0x", __FUNCTION__, packet->m_nChannel);
3823 header += 2;
3824 }
3825
3826 nSize = packetSize[packet->m_headerType];
3827
3828 if (packet->m_nChannel >= r->m_channelsAllocatedIn)
3829 {
3830 int n = packet->m_nChannel + 10;
3831 int *timestamp = realloc(r->m_channelTimestamp, sizeof(int) * n);
3832 RTMPPacket **packets = realloc(r->m_vecChannelsIn, sizeof(RTMPPacket*) * n);
3833 if (!timestamp)
3834 free(r->m_channelTimestamp);
3835 if (!packets)
3836 free(r->m_vecChannelsIn);
3837 r->m_channelTimestamp = timestamp;
3838 r->m_vecChannelsIn = packets;
3839 if (!timestamp || !packets)
3840 {
3841 r->m_channelsAllocatedIn = 0;
3842 return FALSE;
3843 }
3844 memset(r->m_channelTimestamp + r->m_channelsAllocatedIn, 0, sizeof(int) * (n - r->m_channelsAllocatedIn));
3845 memset(r->m_vecChannelsIn + r->m_channelsAllocatedIn, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedIn));
3846 r->m_channelsAllocatedIn = n;
3847 }
3848
3849 if (nSize == RTMP_LARGE_HEADER_SIZE) /* if we get a full header the timestamp is absolute */
3850 packet->m_hasAbsTimestamp = TRUE;
3851
3852 else if (nSize < RTMP_LARGE_HEADER_SIZE)
3853 {
3854 /* using values from the last message of this channel */
3855 if (r->m_vecChannelsIn[packet->m_nChannel])
3856 memcpy(packet, r->m_vecChannelsIn[packet->m_nChannel],
3857 sizeof(RTMPPacket));
3858 }
3859
3860 nSize--;
3861
3862 if (nSize > 0 && ReadN(r, header, nSize) != nSize)
3863 {
3864 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet header. type: %x",
3865 __FUNCTION__, (unsigned int)hbuf[0]);
3866 return FALSE;
3867 }
3868
3869 hSize = nSize + (header - (char *)hbuf);
3870
3871 if (nSize >= 3)
3872 {
3873 packet->m_nTimeStamp = AMF_DecodeInt24(header);
3874
3875 /*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); */
3876
3877 if (nSize >= 6)
3878 {
3879 packet->m_nBodySize = AMF_DecodeInt24(header + 3);
3880 packet->m_nBytesRead = 0;
3881
3882 if (nSize > 6)
3883 {
3884 packet->m_packetType = header[6];
3885
3886 if (nSize == 11)
3887 packet->m_nInfoField2 = DecodeInt32LE(header + 7);
3888 }
3889 }
3890
3891 extendedTimestamp = (packet->m_nTimeStamp == 0xffffff);
3892
3893 if (extendedTimestamp)
3894 {
3895 if (ReadN(r, header + nSize, 4) != 4)
3896 {
3897 RTMP_Log(RTMP_LOGERROR, "%s, failed to read extended timestamp",
3898 __FUNCTION__);
3899 return FALSE;
3900 }
3901 packet->m_nTimeStamp = AMF_DecodeInt32(header + nSize);
3902 hSize += 4;
3903 }
3904 }
3905
3906 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)hbuf, hSize);
3907
3908 if (packet->m_nBodySize > 0 && packet->m_body == NULL)
3909 {
3910 if (!RTMPPacket_Alloc(packet, packet->m_nBodySize))
3911 {
3912 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
3913 return FALSE;
3914 }
3915 // didAlloc = TRUE;
3916 packet->m_headerType = (hbuf[0] & 0xc0) >> 6;
3917 }
3918
3919 nToRead = packet->m_nBodySize - packet->m_nBytesRead;
3920 nChunk = r->m_inChunkSize;
3921 if (nToRead < nChunk)
3922 nChunk = nToRead;
3923
3924 /* Does the caller want the raw chunk? */
3925 if (packet->m_chunk)
3926 {
3927 packet->m_chunk->c_headerSize = hSize;
3928 memcpy(packet->m_chunk->c_header, hbuf, hSize);
3929 packet->m_chunk->c_chunk = packet->m_body + packet->m_nBytesRead;
3930 packet->m_chunk->c_chunkSize = nChunk;
3931 }
3932
3933 if (ReadN(r, packet->m_body + packet->m_nBytesRead, nChunk) != nChunk)
3934 {
3935 RTMP_Log(RTMP_LOGERROR, "%s, failed to read RTMP packet body. len: %u",
3936 __FUNCTION__, packet->m_nBodySize);
3937 return FALSE;
3938 }
3939
3940 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)packet->m_body + packet->m_nBytesRead, nChunk);
3941
3942 packet->m_nBytesRead += nChunk;
3943
3944 /* keep the packet as ref for other packets on this channel */
3945 if (!r->m_vecChannelsIn[packet->m_nChannel])
3946 r->m_vecChannelsIn[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
3947 memcpy(r->m_vecChannelsIn[packet->m_nChannel], packet, sizeof(RTMPPacket));
3948 if (extendedTimestamp)
3949 r->m_vecChannelsIn[packet->m_nChannel]->m_nTimeStamp = 0xffffff;
3950
3951 if (RTMPPacket_IsReady(packet))
3952 {
3953 /* make packet's timestamp absolute */
3954 if (!packet->m_hasAbsTimestamp)
3955 packet->m_nTimeStamp += r->m_channelTimestamp[packet->m_nChannel]; /* timestamps seem to be always relative!! */
3956
3957 r->m_channelTimestamp[packet->m_nChannel] = packet->m_nTimeStamp;
3958
3959 /* reset the data from the stored packet. we keep the header since we may use it later if a new packet for this channel */
3960 /* arrives and requests to re-use some info (small packet header) */
3961 r->m_vecChannelsIn[packet->m_nChannel]->m_body = NULL;
3962 r->m_vecChannelsIn[packet->m_nChannel]->m_nBytesRead = 0;
3963 r->m_vecChannelsIn[packet->m_nChannel]->m_hasAbsTimestamp = FALSE; /* can only be false if we reuse header */
3964 }
3965 else
3966 {
3967 packet->m_body = NULL; /* so it won't be erased on free */
3968 }
3969
3970 return TRUE;
3971 }
3972
3973 #ifndef CRYPTO
3974 static int
HandShake(RTMP * r,int FP9HandShake)3975 HandShake(RTMP *r, int FP9HandShake)
3976 {
3977 int i;
3978 uint32_t uptime, suptime;
3979 int bMatch;
3980 char type;
3981 char clientbuf[RTMP_SIG_SIZE + 1], *clientsig = clientbuf + 1;
3982 char serversig[RTMP_SIG_SIZE];
3983
3984 clientbuf[0] = 0x03; /* not encrypted */
3985
3986 uptime = htonl(RTMP_GetTime());
3987 memcpy(clientsig, &uptime, 4);
3988
3989 memset(&clientsig[4], 0, 4);
3990
3991 #ifdef _DEBUG
3992 for (i = 8; i < RTMP_SIG_SIZE; i++)
3993 clientsig[i] = 0xff;
3994 #else
3995 for (i = 8; i < RTMP_SIG_SIZE; i++)
3996 clientsig[i] = (char)(rand() % 256);
3997 #endif
3998
3999 if (!WriteN(r, clientbuf, RTMP_SIG_SIZE + 1))
4000 return FALSE;
4001
4002 if (ReadN(r, &type, 1) != 1) /* 0x03 or 0x06 */
4003 return FALSE;
4004
4005 RTMP_Log(RTMP_LOGDEBUG, "%s: Type Answer : %02X", __FUNCTION__, type);
4006
4007 if (type != clientbuf[0])
4008 RTMP_Log(RTMP_LOGWARNING, "%s: Type mismatch: client sent %d, server answered %d",
4009 __FUNCTION__, clientbuf[0], type);
4010
4011 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
4012 return FALSE;
4013
4014 /* decode server response */
4015
4016 memcpy(&suptime, serversig, 4);
4017 suptime = ntohl(suptime);
4018
4019 RTMP_Log(RTMP_LOGDEBUG, "%s: Server Uptime : %d", __FUNCTION__, suptime);
4020 RTMP_Log(RTMP_LOGDEBUG, "%s: FMS Version : %d.%d.%d.%d", __FUNCTION__,
4021 serversig[4], serversig[5], serversig[6], serversig[7]);
4022
4023 /* 2nd part of handshake */
4024 if (!WriteN(r, serversig, RTMP_SIG_SIZE))
4025 return FALSE;
4026
4027 if (ReadN(r, serversig, RTMP_SIG_SIZE) != RTMP_SIG_SIZE)
4028 return FALSE;
4029
4030 bMatch = (memcmp(serversig, clientsig, RTMP_SIG_SIZE) == 0);
4031 if (!bMatch)
4032 {
4033 RTMP_Log(RTMP_LOGWARNING, "%s, client signature does not match!", __FUNCTION__);
4034 }
4035
4036 /* er, totally unused? */
4037 (void)FP9HandShake;
4038 return TRUE;
4039 }
4040 #endif
4041
4042 int
RTMP_SendChunk(RTMP * r,RTMPChunk * chunk)4043 RTMP_SendChunk(RTMP *r, RTMPChunk *chunk)
4044 {
4045 int wrote;
4046 char hbuf[RTMP_MAX_HEADER_SIZE];
4047
4048 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, (int)r->m_sb.sb_socket,
4049 chunk->c_chunkSize);
4050 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_header, chunk->c_headerSize);
4051 if (chunk->c_chunkSize)
4052 {
4053 char *ptr = chunk->c_chunk - chunk->c_headerSize;
4054 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)chunk->c_chunk, chunk->c_chunkSize);
4055 /* save header bytes we're about to overwrite */
4056 memcpy(hbuf, ptr, chunk->c_headerSize);
4057 memcpy(ptr, chunk->c_header, chunk->c_headerSize);
4058 wrote = WriteN(r, ptr, chunk->c_headerSize + chunk->c_chunkSize);
4059 memcpy(ptr, hbuf, chunk->c_headerSize);
4060 }
4061 else
4062 wrote = WriteN(r, chunk->c_header, chunk->c_headerSize);
4063 return wrote;
4064 }
4065
4066 int
RTMP_SendPacket(RTMP * r,RTMPPacket * packet,int queue)4067 RTMP_SendPacket(RTMP *r, RTMPPacket *packet, int queue)
4068 {
4069 const RTMPPacket *prevPacket;
4070 uint32_t last = 0;
4071 int nSize;
4072 int hSize, cSize;
4073 char *header, *hptr, *hend, hbuf[RTMP_MAX_HEADER_SIZE], c;
4074 uint32_t t;
4075 char *buffer, *tbuf = NULL, *toff = NULL;
4076 int nChunkSize;
4077 int tlen;
4078
4079 if (packet->m_nChannel >= r->m_channelsAllocatedOut)
4080 {
4081 int n = packet->m_nChannel + 10;
4082 RTMPPacket **packets = realloc(r->m_vecChannelsOut, sizeof(RTMPPacket*) * n);
4083 if (!packets)
4084 {
4085 free(r->m_vecChannelsOut);
4086 r->m_vecChannelsOut = NULL;
4087 r->m_channelsAllocatedOut = 0;
4088 return FALSE;
4089 }
4090 r->m_vecChannelsOut = packets;
4091 memset(r->m_vecChannelsOut + r->m_channelsAllocatedOut, 0, sizeof(RTMPPacket*) * (n - r->m_channelsAllocatedOut));
4092 r->m_channelsAllocatedOut = n;
4093 }
4094
4095 prevPacket = r->m_vecChannelsOut[packet->m_nChannel];
4096 if (prevPacket && packet->m_headerType != RTMP_PACKET_SIZE_LARGE)
4097 {
4098 /* compress a bit by using the prev packet's attributes */
4099 if (prevPacket->m_nBodySize == packet->m_nBodySize
4100 && prevPacket->m_packetType == packet->m_packetType
4101 && packet->m_headerType == RTMP_PACKET_SIZE_MEDIUM)
4102 packet->m_headerType = RTMP_PACKET_SIZE_SMALL;
4103
4104 if (prevPacket->m_nTimeStamp == packet->m_nTimeStamp
4105 && packet->m_headerType == RTMP_PACKET_SIZE_SMALL)
4106 packet->m_headerType = RTMP_PACKET_SIZE_MINIMUM;
4107 last = prevPacket->m_nTimeStamp;
4108 }
4109
4110 if (packet->m_headerType > 3) /* sanity */
4111 {
4112 RTMP_Log(RTMP_LOGERROR, "sanity failed!! trying to send header of type: 0x%02x.",
4113 (unsigned char)packet->m_headerType);
4114 return FALSE;
4115 }
4116
4117 nSize = packetSize[packet->m_headerType];
4118 hSize = nSize;
4119 cSize = 0;
4120 t = packet->m_nTimeStamp - last;
4121
4122 if (packet->m_body)
4123 {
4124 header = packet->m_body - nSize;
4125 hend = packet->m_body;
4126 }
4127 else
4128 {
4129 header = hbuf + 6;
4130 hend = hbuf + sizeof(hbuf);
4131 }
4132
4133 if (packet->m_nChannel > 319)
4134 cSize = 2;
4135 else if (packet->m_nChannel > 63)
4136 cSize = 1;
4137 if (cSize)
4138 {
4139 header -= cSize;
4140 hSize += cSize;
4141 }
4142
4143 if (nSize > 1 && t >= 0xffffff)
4144 {
4145 header -= 4;
4146 hSize += 4;
4147 }
4148
4149 hptr = header;
4150 c = packet->m_headerType << 6;
4151 switch (cSize)
4152 {
4153 case 0:
4154 c |= packet->m_nChannel;
4155 break;
4156 case 1:
4157 break;
4158 case 2:
4159 c |= 1;
4160 break;
4161 }
4162 *hptr++ = c;
4163 if (cSize)
4164 {
4165 int tmp = packet->m_nChannel - 64;
4166 *hptr++ = tmp & 0xff;
4167 if (cSize == 2)
4168 *hptr++ = tmp >> 8;
4169 }
4170
4171 if (nSize > 1)
4172 {
4173 hptr = AMF_EncodeInt24(hptr, hend, t > 0xffffff ? 0xffffff : t);
4174 }
4175
4176 if (nSize > 4)
4177 {
4178 hptr = AMF_EncodeInt24(hptr, hend, packet->m_nBodySize);
4179 *hptr++ = packet->m_packetType;
4180 }
4181
4182 if (nSize > 8)
4183 hptr += EncodeInt32LE(hptr, packet->m_nInfoField2);
4184
4185 if (nSize > 1 && t >= 0xffffff)
4186 hptr = AMF_EncodeInt32(hptr, hend, t);
4187
4188 nSize = packet->m_nBodySize;
4189 buffer = packet->m_body;
4190 nChunkSize = r->m_outChunkSize;
4191
4192 RTMP_Log(RTMP_LOGDEBUG2, "%s: fd=%d, size=%d", __FUNCTION__, (int)r->m_sb.sb_socket,
4193 nSize);
4194 /* send all chunks in one HTTP request */
4195 if (r->Link.protocol & RTMP_FEATURE_HTTP)
4196 {
4197 int chunks = (nSize+nChunkSize-1) / nChunkSize;
4198 if (chunks > 1)
4199 {
4200 tlen = chunks * (cSize + 1) + nSize + hSize;
4201 tbuf = malloc(tlen);
4202 if (!tbuf)
4203 return FALSE;
4204 toff = tbuf;
4205 }
4206 }
4207 while (nSize + hSize)
4208 {
4209 int wrote;
4210
4211 if (nSize < nChunkSize)
4212 nChunkSize = nSize;
4213
4214 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)header, hSize);
4215 RTMP_LogHexString(RTMP_LOGDEBUG2, (uint8_t *)buffer, nChunkSize);
4216 if (tbuf)
4217 {
4218 memcpy(toff, header, nChunkSize + hSize);
4219 toff += nChunkSize + hSize;
4220 }
4221 else
4222 {
4223 wrote = WriteN(r, header, nChunkSize + hSize);
4224 if (!wrote)
4225 return FALSE;
4226 }
4227 nSize -= nChunkSize;
4228 buffer += nChunkSize;
4229 hSize = 0;
4230
4231 if (nSize > 0)
4232 {
4233 header = buffer - 1;
4234 hSize = 1;
4235 if (cSize)
4236 {
4237 header -= cSize;
4238 hSize += cSize;
4239 }
4240 *header = (0xc0 | c);
4241 if (cSize)
4242 {
4243 int tmp = packet->m_nChannel - 64;
4244 header[1] = tmp & 0xff;
4245 if (cSize == 2)
4246 header[2] = tmp >> 8;
4247 }
4248 }
4249 }
4250 if (tbuf)
4251 {
4252 int wrote = WriteN(r, tbuf, toff-tbuf);
4253 free(tbuf);
4254 tbuf = NULL;
4255 if (!wrote)
4256 return FALSE;
4257 }
4258
4259 /* we invoked a remote method */
4260 if (packet->m_packetType == RTMP_PACKET_TYPE_INVOKE)
4261 {
4262 AVal method;
4263 char *ptr;
4264 ptr = packet->m_body + 1;
4265 AMF_DecodeString(ptr, &method);
4266 RTMP_Log(RTMP_LOGDEBUG, "Invoking %s", method.av_val);
4267 /* keep it in call queue till result arrives */
4268 if (queue)
4269 {
4270 int txn;
4271 ptr += 3 + method.av_len;
4272 txn = (int)AMF_DecodeNumber(ptr);
4273 AV_queue(&r->m_methodCalls, &r->m_numCalls, &method, txn);
4274 }
4275 }
4276
4277 if (!r->m_vecChannelsOut[packet->m_nChannel])
4278 r->m_vecChannelsOut[packet->m_nChannel] = malloc(sizeof(RTMPPacket));
4279 memcpy(r->m_vecChannelsOut[packet->m_nChannel], packet, sizeof(RTMPPacket));
4280 return TRUE;
4281 }
4282
4283 void
RTMP_Close(RTMP * r)4284 RTMP_Close(RTMP *r)
4285 {
4286 int i;
4287
4288 if (RTMP_IsConnected(r))
4289 {
4290 for (int idx = 0; idx < r->Link.nStreams; idx++)
4291 {
4292 if (r->Link.streams[idx].id > 0)
4293 {
4294 i = r->Link.streams[idx].id;
4295 r->Link.streams[idx].id = 0;
4296 if ((r->Link.protocol & RTMP_FEATURE_WRITE))
4297 SendFCUnpublish(r, idx);
4298 SendDeleteStream(r, (double)i);
4299 }
4300 }
4301 if (r->m_clientID.av_val)
4302 {
4303 HTTP_Post(r, RTMPT_CLOSE, "", 1);
4304 free(r->m_clientID.av_val);
4305 r->m_clientID.av_val = NULL;
4306 r->m_clientID.av_len = 0;
4307 }
4308 RTMPSockBuf_Close(&r->m_sb);
4309 }
4310
4311 for (int idx = 0; idx < r->Link.nStreams; idx++)
4312 r->Link.streams[idx].id = -1;
4313
4314 r->m_stream_id = -1;
4315 r->m_sb.sb_socket = -1;
4316 r->m_nBWCheckCounter = 0;
4317 r->m_nBytesIn = 0;
4318 r->m_nBytesInSent = 0;
4319
4320 if (r->m_read.flags & RTMP_READ_HEADER)
4321 {
4322 free(r->m_read.buf);
4323 r->m_read.buf = NULL;
4324 }
4325 r->m_read.dataType = 0;
4326 r->m_read.flags = 0;
4327 r->m_read.status = 0;
4328 r->m_read.nResumeTS = 0;
4329 r->m_read.nIgnoredFrameCounter = 0;
4330 r->m_read.nIgnoredFlvFrameCounter = 0;
4331
4332 r->m_write.m_nBytesRead = 0;
4333 RTMPPacket_Free(&r->m_write);
4334
4335 for (i = 0; i < r->m_channelsAllocatedIn; i++)
4336 {
4337 if (r->m_vecChannelsIn[i])
4338 {
4339 RTMPPacket_Free(r->m_vecChannelsIn[i]);
4340 free(r->m_vecChannelsIn[i]);
4341 r->m_vecChannelsIn[i] = NULL;
4342 }
4343 }
4344 free(r->m_vecChannelsIn);
4345 r->m_vecChannelsIn = NULL;
4346 free(r->m_channelTimestamp);
4347 r->m_channelTimestamp = NULL;
4348 r->m_channelsAllocatedIn = 0;
4349 for (i = 0; i < r->m_channelsAllocatedOut; i++)
4350 {
4351 if (r->m_vecChannelsOut[i])
4352 {
4353 free(r->m_vecChannelsOut[i]);
4354 r->m_vecChannelsOut[i] = NULL;
4355 }
4356 }
4357 free(r->m_vecChannelsOut);
4358 r->m_vecChannelsOut = NULL;
4359 r->m_channelsAllocatedOut = 0;
4360 AV_clear(r->m_methodCalls, r->m_numCalls);
4361 r->m_methodCalls = NULL;
4362 r->m_numCalls = 0;
4363 r->m_numInvokes = 0;
4364
4365 r->m_bPlaying = FALSE;
4366 r->Link.playingStreams = 0;
4367 r->m_sb.sb_size = 0;
4368
4369 r->m_msgCounter = 0;
4370 r->m_resplen = 0;
4371 r->m_unackd = 0;
4372
4373 if (r->Link.lFlags & RTMP_LF_FTCU)
4374 {
4375 free(r->Link.tcUrl.av_val);
4376 r->Link.tcUrl.av_val = NULL;
4377 r->Link.lFlags ^= RTMP_LF_FTCU;
4378 }
4379
4380 memset (&r->m_bindIP, 0, sizeof(r->m_bindIP));
4381 r->m_bCustomSend = 0;
4382 r->m_customSendFunc = NULL;
4383 r->m_customSendParam = NULL;
4384
4385 #if defined(CRYPTO) || defined(USE_ONLY_MD5)
4386 if (!(r->Link.protocol & RTMP_FEATURE_WRITE) || (r->Link.pFlags & RTMP_PUB_CLEAN))
4387 {
4388 for (int idx = 0; idx < r->Link.nStreams; idx++)
4389 {
4390 free(r->Link.streams[idx].playpath.av_val);
4391 r->Link.streams[idx].playpath.av_val = NULL;
4392 }
4393
4394 r->Link.curStreamIdx = 0;
4395 r->Link.nStreams = 0;
4396 }
4397
4398 if ((r->Link.protocol & RTMP_FEATURE_WRITE) &&
4399 (r->Link.pFlags & RTMP_PUB_CLEAN) &&
4400 (r->Link.pFlags & RTMP_PUB_ALLOC))
4401 {
4402 free(r->Link.app.av_val);
4403 r->Link.app.av_val = NULL;
4404 free(r->Link.tcUrl.av_val);
4405 r->Link.tcUrl.av_val = NULL;
4406 }
4407 #elif defined(CRYPTO)
4408 if (r->Link.dh)
4409 {
4410 MDH_free(r->Link.dh);
4411 r->Link.dh = NULL;
4412 }
4413 if (r->Link.rc4keyIn)
4414 {
4415 RC4_free(r->Link.rc4keyIn);
4416 r->Link.rc4keyIn = NULL;
4417 }
4418 if (r->Link.rc4keyOut)
4419 {
4420 RC4_free(r->Link.rc4keyOut);
4421 r->Link.rc4keyOut = NULL;
4422 }
4423 #else
4424 for (int idx = 0; idx < r->Link.nStreams; idx++)
4425 {
4426 free(r->Link.streams[idx].playpath.av_val);
4427 r->Link.streams[idx].playpath.av_val = NULL;
4428 }
4429
4430 r->Link.curStreamIdx = 0;
4431 r->Link.nStreams = 0;
4432 #endif
4433 }
4434
4435 int
RTMPSockBuf_Fill(RTMPSockBuf * sb)4436 RTMPSockBuf_Fill(RTMPSockBuf *sb)
4437 {
4438 int nBytes;
4439
4440 if (!sb->sb_size)
4441 sb->sb_start = sb->sb_buf;
4442
4443 while (1)
4444 {
4445 nBytes = (int)sizeof(sb->sb_buf) - 1 - sb->sb_size - (sb->sb_start - sb->sb_buf);
4446 #if defined(CRYPTO) && !defined(NO_SSL)
4447 if (sb->sb_ssl)
4448 {
4449 nBytes = TLS_read(sb->sb_ssl, sb->sb_start + sb->sb_size, nBytes);
4450 }
4451 else
4452 #endif
4453 {
4454 nBytes = recv(sb->sb_socket, sb->sb_start + sb->sb_size, nBytes, MSG_NOSIGNAL);
4455 }
4456 if (nBytes > 0)
4457 {
4458 sb->sb_size += nBytes;
4459 }
4460 else if (nBytes == 0)
4461 {
4462 RTMP_Log(RTMP_LOGERROR, "%s, remote host closed connection",
4463 __FUNCTION__);
4464 }
4465 else
4466 {
4467 int level;
4468 int sockerr = GetSockError();
4469 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
4470 level = RTMP_LOGDEBUG;
4471 else
4472 level = RTMP_LOGERROR;
4473 RTMP_Log(level, "%s, recv returned %d. GetSockError(): %d (%s)",
4474 __FUNCTION__, nBytes, sockerr, socketerror(sockerr));
4475 if (sockerr == EINTR && !RTMP_ctrlC)
4476 continue;
4477
4478 if (sockerr == EWOULDBLOCK || sockerr == EAGAIN)
4479 {
4480 sb->sb_timedout = TRUE;
4481 nBytes = 0;
4482 }
4483 }
4484 break;
4485 }
4486
4487 return nBytes;
4488 }
4489
4490 int
RTMPSockBuf_Send(RTMPSockBuf * sb,const char * buf,int len)4491 RTMPSockBuf_Send(RTMPSockBuf *sb, const char *buf, int len)
4492 {
4493 int rc;
4494
4495 #if defined(RTMP_NETSTACK_DUMP)
4496 fwrite(buf, 1, len, netstackdump);
4497 #endif
4498
4499 #if defined(CRYPTO) && !defined(NO_SSL)
4500 if (sb->sb_ssl)
4501 {
4502 rc = TLS_write(sb->sb_ssl, buf, len);
4503 }
4504 else
4505 #endif
4506 {
4507 rc = send(sb->sb_socket, buf, len, MSG_NOSIGNAL);
4508 }
4509 return rc;
4510 }
4511
4512 int
RTMPSockBuf_Close(RTMPSockBuf * sb)4513 RTMPSockBuf_Close(RTMPSockBuf *sb)
4514 {
4515 #if defined(CRYPTO) && !defined(NO_SSL)
4516 if (sb->sb_ssl)
4517 {
4518 TLS_shutdown(sb->sb_ssl);
4519 TLS_close(sb->sb_ssl);
4520 sb->sb_ssl = NULL;
4521 }
4522 #endif
4523 if (sb->sb_socket != INVALID_SOCKET)
4524 return closesocket(sb->sb_socket);
4525 return 0;
4526 }
4527
4528 #define HEX2BIN(a) (((a)&0x40)?((a)&0xf)+9:((a)&0xf))
4529
4530 static void
DecodeTEA(AVal * key,AVal * text)4531 DecodeTEA(AVal *key, AVal *text)
4532 {
4533 uint32_t *v, k[4] = { 0 }, u;
4534 uint32_t z, y, sum = 0, e, DELTA = 0x9e3779b9;
4535 int32_t p, q;
4536 int i, n;
4537 unsigned char *ptr, *out;
4538
4539 /* prep key: pack 1st 16 chars into 4 LittleEndian ints */
4540 ptr = (unsigned char *)key->av_val;
4541 u = 0;
4542 n = 0;
4543 v = k;
4544 p = key->av_len > 16 ? 16 : key->av_len;
4545 for (i = 0; i < p; i++)
4546 {
4547 u |= ptr[i] << (n * 8);
4548 if (n == 3)
4549 {
4550 *v++ = u;
4551 u = 0;
4552 n = 0;
4553 }
4554 else
4555 {
4556 n++;
4557 }
4558 }
4559 /* any trailing chars */
4560 if (u)
4561 *v = u;
4562
4563 /* prep text: hex2bin, multiples of 4 */
4564 n = (text->av_len + 7) / 8;
4565 out = malloc(n * 8);
4566 ptr = (unsigned char *)text->av_val;
4567 v = (uint32_t *) out;
4568 for (i = 0; i < n; i++)
4569 {
4570 u = (HEX2BIN(ptr[0]) << 4) + HEX2BIN(ptr[1]);
4571 u |= ((HEX2BIN(ptr[2]) << 4) + HEX2BIN(ptr[3])) << 8;
4572 u |= ((HEX2BIN(ptr[4]) << 4) + HEX2BIN(ptr[5])) << 16;
4573 u |= ((HEX2BIN(ptr[6]) << 4) + HEX2BIN(ptr[7])) << 24;
4574 *v++ = u;
4575 ptr += 8;
4576 }
4577 v = (uint32_t *) out;
4578
4579 /* http://www.movable-type.co.uk/scripts/tea-block.html */
4580 #define MX (((z>>5)^(y<<2)) + ((y>>3)^(z<<4))) ^ ((sum^y) + (k[(p&3)^e]^z));
4581 z = v[n - 1];
4582 y = v[0];
4583 q = 6 + 52 / n;
4584 sum = q * DELTA;
4585 while (sum != 0)
4586 {
4587 e = sum >> 2 & 3;
4588 for (p = n - 1; p > 0; p--)
4589 z = v[p - 1], y = v[p] -= MX;
4590 z = v[n - 1];
4591 y = v[0] -= MX;
4592 sum -= DELTA;
4593 }
4594
4595 text->av_len /= 2;
4596 memcpy(text->av_val, out, text->av_len);
4597 free(out);
4598 }
4599
4600 static int
HTTP_Post(RTMP * r,RTMPTCmd cmd,const char * buf,int len)4601 HTTP_Post(RTMP *r, RTMPTCmd cmd, const char *buf, int len)
4602 {
4603 char hbuf[512];
4604 int hlen = snprintf(hbuf, sizeof(hbuf), "POST /%s%s/%d HTTP/1.1\r\n"
4605 "Host: %.*s:%d\r\n"
4606 "Accept: */*\r\n"
4607 "User-Agent: Shockwave Flash\r\n"
4608 "Connection: Keep-Alive\r\n"
4609 "Cache-Control: no-cache\r\n"
4610 "Content-type: application/x-fcs\r\n"
4611 "Content-length: %d\r\n\r\n", RTMPT_cmds[cmd],
4612 r->m_clientID.av_val ? r->m_clientID.av_val : "",
4613 r->m_msgCounter, r->Link.hostname.av_len, r->Link.hostname.av_val,
4614 r->Link.port, len);
4615 RTMPSockBuf_Send(&r->m_sb, hbuf, hlen);
4616 hlen = RTMPSockBuf_Send(&r->m_sb, buf, len);
4617 r->m_msgCounter++;
4618 r->m_unackd++;
4619 return hlen;
4620 }
4621
4622 static int
HTTP_read(RTMP * r,int fill)4623 HTTP_read(RTMP *r, int fill)
4624 {
4625 char *ptr;
4626 int hlen;
4627
4628 restart:
4629 if (fill)
4630 RTMPSockBuf_Fill(&r->m_sb);
4631 if (r->m_sb.sb_size < 13)
4632 {
4633 if (fill)
4634 goto restart;
4635 return -2;
4636 }
4637 if (strncmp(r->m_sb.sb_start, "HTTP/1.1 200 ", 13))
4638 return -1;
4639 r->m_sb.sb_start[r->m_sb.sb_size] = '\0';
4640 if (!strstr(r->m_sb.sb_start, "\r\n\r\n"))
4641 {
4642 if (fill)
4643 goto restart;
4644 return -2;
4645 }
4646
4647 ptr = r->m_sb.sb_start + sizeof("HTTP/1.1 200");
4648 while ((ptr = strstr(ptr, "Content-")))
4649 {
4650 if (!strncasecmp(ptr+8, "length:", 7)) break;
4651 ptr += 8;
4652 }
4653 if (!ptr)
4654 return -1;
4655 hlen = atoi(ptr+16);
4656 ptr = strstr(ptr+16, "\r\n\r\n");
4657 if (!ptr)
4658 return -1;
4659 ptr += 4;
4660 if (ptr + (r->m_clientID.av_val ? 1 : hlen) > r->m_sb.sb_start + r->m_sb.sb_size)
4661 {
4662 if (fill)
4663 goto restart;
4664 return -2;
4665 }
4666 r->m_sb.sb_size -= ptr - r->m_sb.sb_start;
4667 r->m_sb.sb_start = ptr;
4668 r->m_unackd--;
4669
4670 if (!r->m_clientID.av_val)
4671 {
4672 r->m_clientID.av_len = hlen;
4673 r->m_clientID.av_val = malloc(hlen+1);
4674 if (!r->m_clientID.av_val)
4675 return -1;
4676 r->m_clientID.av_val[0] = '/';
4677 memcpy(r->m_clientID.av_val+1, ptr, hlen-1);
4678 r->m_clientID.av_val[hlen] = 0;
4679 r->m_sb.sb_size = 0;
4680 }
4681 else
4682 {
4683 r->m_polling = *ptr++;
4684 r->m_resplen = hlen - 1;
4685 r->m_sb.sb_start++;
4686 r->m_sb.sb_size--;
4687 }
4688 return 0;
4689 }
4690
4691 #define MAX_IGNORED_FRAMES 50
4692
4693 /* Read from the stream until we get a media packet.
4694 * Returns -3 if Play.Close/Stop, -2 if fatal error, -1 if no more media
4695 * packets, 0 if ignorable error, >0 if there is a media packet
4696 */
4697 static int
Read_1_Packet(RTMP * r,char * buf,unsigned int buflen)4698 Read_1_Packet(RTMP *r, char *buf, unsigned int buflen)
4699 {
4700 uint32_t prevTagSize = 0;
4701 int rtnGetNextMediaPacket = 0, ret = RTMP_READ_EOF;
4702 RTMPPacket packet = { 0 };
4703 int recopy = FALSE;
4704 unsigned int size;
4705 char *ptr, *pend;
4706 uint32_t nTimeStamp = 0;
4707 unsigned int len;
4708
4709 rtnGetNextMediaPacket = RTMP_GetNextMediaPacket(r, &packet);
4710 while (rtnGetNextMediaPacket)
4711 {
4712 char *packetBody = packet.m_body;
4713 unsigned int nPacketLen = packet.m_nBodySize;
4714
4715 /* Return RTMP_READ_COMPLETE if this was completed nicely with
4716 * invoke message Play.Stop or Play.Complete
4717 */
4718 if (rtnGetNextMediaPacket == 2)
4719 {
4720 RTMP_Log(RTMP_LOGDEBUG,
4721 "Got Play.Complete or Play.Stop from server. "
4722 "Assuming stream is complete");
4723 ret = RTMP_READ_COMPLETE;
4724 break;
4725 }
4726
4727 r->m_read.dataType |= (((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO) << 2) |
4728 (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO));
4729
4730 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO && nPacketLen <= 5)
4731 {
4732 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small video packet: size: %d",
4733 nPacketLen);
4734 ret = RTMP_READ_IGNORE;
4735 break;
4736 }
4737 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO && nPacketLen <= 1)
4738 {
4739 RTMP_Log(RTMP_LOGDEBUG, "ignoring too small audio packet: size: %d",
4740 nPacketLen);
4741 ret = RTMP_READ_IGNORE;
4742 break;
4743 }
4744
4745 if (r->m_read.flags & RTMP_READ_SEEKING)
4746 {
4747 ret = RTMP_READ_IGNORE;
4748 break;
4749 }
4750 #ifdef _DEBUG
4751 RTMP_Log(RTMP_LOGDEBUG, "type: %02X, size: %d, TS: %d ms, abs TS: %d",
4752 packet.m_packetType, nPacketLen, packet.m_nTimeStamp,
4753 packet.m_hasAbsTimestamp);
4754 if (packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
4755 RTMP_Log(RTMP_LOGDEBUG, "frametype: %02X", (*packetBody & 0xf0));
4756 #endif
4757
4758 if (r->m_read.flags & RTMP_READ_RESUME)
4759 {
4760 /* check the header if we get one */
4761 if (packet.m_nTimeStamp == 0)
4762 {
4763 if (r->m_read.nMetaHeaderSize > 0
4764 && packet.m_packetType == RTMP_PACKET_TYPE_INFO)
4765 {
4766 AMFObject metaObj;
4767 int nRes =
4768 AMF_Decode(&metaObj, packetBody, nPacketLen, FALSE);
4769 if (nRes >= 0)
4770 {
4771 AVal metastring;
4772 AMFProp_GetString(AMF_GetProp(&metaObj, NULL, 0),
4773 &metastring);
4774
4775 if (AVMATCH(&metastring, &av_onMetaData))
4776 {
4777 /* compare */
4778 if ((r->m_read.nMetaHeaderSize != nPacketLen) ||
4779 (memcmp
4780 (r->m_read.metaHeader, packetBody,
4781 r->m_read.nMetaHeaderSize) != 0))
4782 {
4783 ret = RTMP_READ_ERROR;
4784 }
4785 }
4786 AMF_Reset(&metaObj);
4787 if (ret == RTMP_READ_ERROR)
4788 break;
4789 }
4790 }
4791
4792 /* check first keyframe to make sure we got the right position
4793 * in the stream! (the first non ignored frame)
4794 */
4795 if (r->m_read.nInitialFrameSize > 0)
4796 {
4797 /* video or audio data */
4798 if (packet.m_packetType == r->m_read.initialFrameType
4799 && r->m_read.nInitialFrameSize == nPacketLen)
4800 {
4801 /* we don't compare the sizes since the packet can
4802 * contain several FLV packets, just make sure the
4803 * first frame is our keyframe (which we are going
4804 * to rewrite)
4805 */
4806 if (memcmp
4807 (r->m_read.initialFrame, packetBody,
4808 r->m_read.nInitialFrameSize) == 0)
4809 {
4810 RTMP_Log(RTMP_LOGDEBUG, "Checked keyframe successfully!");
4811 r->m_read.flags |= RTMP_READ_GOTKF;
4812 /* ignore it! (what about audio data after it? it is
4813 * handled by ignoring all 0ms frames, see below)
4814 */
4815 ret = RTMP_READ_IGNORE;
4816 break;
4817 }
4818 }
4819
4820 /* hande FLV streams, even though the server resends the
4821 * keyframe as an extra video packet it is also included
4822 * in the first FLV stream chunk and we have to compare
4823 * it and filter it out !!
4824 */
4825 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4826 {
4827 /* basically we have to find the keyframe with the
4828 * correct TS being nResumeTS
4829 */
4830 unsigned int pos = 0;
4831 uint32_t ts = 0;
4832
4833 while (pos + 11 < nPacketLen)
4834 {
4835 /* size without header (11) and prevTagSize (4) */
4836 uint32_t dataSize =
4837 AMF_DecodeInt24(packetBody + pos + 1);
4838 ts = AMF_DecodeInt24(packetBody + pos + 4);
4839 ts |= (packetBody[pos + 7] << 24);
4840
4841 #ifdef _DEBUG
4842 RTMP_Log(RTMP_LOGDEBUG,
4843 "keyframe search: FLV Packet: type %02X, dataSize: %d, timeStamp: %d ms",
4844 packetBody[pos], dataSize, ts);
4845 #endif
4846 /* ok, is it a keyframe?:
4847 * well doesn't work for audio!
4848 */
4849 if (packetBody[pos /*6928, test 0 */ ] ==
4850 r->m_read.initialFrameType
4851 /* && (packetBody[11]&0xf0) == 0x10 */ )
4852 {
4853 if (ts == r->m_read.nResumeTS)
4854 {
4855 RTMP_Log(RTMP_LOGDEBUG,
4856 "Found keyframe with resume-keyframe timestamp!");
4857 if (r->m_read.nInitialFrameSize != dataSize
4858 || memcmp(r->m_read.initialFrame,
4859 packetBody + pos + 11,
4860 r->m_read.
4861 nInitialFrameSize) != 0)
4862 {
4863 RTMP_Log(RTMP_LOGERROR,
4864 "FLV Stream: Keyframe doesn't match!");
4865 ret = RTMP_READ_ERROR;
4866 break;
4867 }
4868 r->m_read.flags |= RTMP_READ_GOTFLVK;
4869
4870 /* skip this packet?
4871 * check whether skippable:
4872 */
4873 if (pos + 11 + dataSize + 4 > nPacketLen)
4874 {
4875 RTMP_Log(RTMP_LOGWARNING,
4876 "Non skipable packet since it doesn't end with chunk, stream corrupt!");
4877 ret = RTMP_READ_ERROR;
4878 break;
4879 }
4880 packetBody += (pos + 11 + dataSize + 4);
4881 nPacketLen -= (pos + 11 + dataSize + 4);
4882
4883 goto stopKeyframeSearch;
4884
4885 }
4886 else if (r->m_read.nResumeTS < ts)
4887 {
4888 /* the timestamp ts will only increase with
4889 * further packets, wait for seek
4890 */
4891 goto stopKeyframeSearch;
4892 }
4893 }
4894 pos += (11 + dataSize + 4);
4895 }
4896 if (ts < r->m_read.nResumeTS)
4897 {
4898 RTMP_Log(RTMP_LOGERROR,
4899 "First packet does not contain keyframe, all "
4900 "timestamps are smaller than the keyframe "
4901 "timestamp; probably the resume seek failed?");
4902 }
4903 stopKeyframeSearch:
4904 ;
4905 if (!(r->m_read.flags & RTMP_READ_GOTFLVK))
4906 {
4907 RTMP_Log(RTMP_LOGERROR,
4908 "Couldn't find the seeked keyframe in this chunk!");
4909 ret = RTMP_READ_IGNORE;
4910 break;
4911 }
4912 }
4913 }
4914 }
4915
4916 if (packet.m_nTimeStamp > 0
4917 && (r->m_read.flags & (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK)))
4918 {
4919 /* another problem is that the server can actually change from
4920 * 09/08 video/audio packets to an FLV stream or vice versa and
4921 * our keyframe check will prevent us from going along with the
4922 * new stream if we resumed.
4923 *
4924 * in this case set the 'found keyframe' variables to true.
4925 * We assume that if we found one keyframe somewhere and were
4926 * already beyond TS > 0 we have written data to the output
4927 * which means we can accept all forthcoming data including the
4928 * change between 08/09 <-> FLV packets
4929 */
4930 r->m_read.flags |= (RTMP_READ_GOTKF|RTMP_READ_GOTFLVK);
4931 }
4932
4933 /* skip till we find our keyframe
4934 * (seeking might put us somewhere before it)
4935 */
4936 if (!(r->m_read.flags & RTMP_READ_GOTKF) &&
4937 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4938 {
4939 RTMP_Log(RTMP_LOGWARNING,
4940 "Stream does not start with requested frame, ignoring data... ");
4941 r->m_read.nIgnoredFrameCounter++;
4942 if (r->m_read.nIgnoredFrameCounter > MAX_IGNORED_FRAMES)
4943 ret = RTMP_READ_ERROR; /* fatal error, couldn't continue stream */
4944 else
4945 ret = RTMP_READ_IGNORE;
4946 break;
4947 }
4948 /* ok, do the same for FLV streams */
4949 if (!(r->m_read.flags & RTMP_READ_GOTFLVK) &&
4950 packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
4951 {
4952 RTMP_Log(RTMP_LOGWARNING,
4953 "Stream does not start with requested FLV frame, ignoring data... ");
4954 r->m_read.nIgnoredFlvFrameCounter++;
4955 if (r->m_read.nIgnoredFlvFrameCounter > MAX_IGNORED_FRAMES)
4956 ret = RTMP_READ_ERROR;
4957 else
4958 ret = RTMP_READ_IGNORE;
4959 break;
4960 }
4961
4962 /* we have to ignore the 0ms frames since these are the first
4963 * keyframes; we've got these so don't mess around with multiple
4964 * copies sent by the server to us! (if the keyframe is found at a
4965 * later position there is only one copy and it will be ignored by
4966 * the preceding if clause)
4967 */
4968 if (!(r->m_read.flags & RTMP_READ_NO_IGNORE) &&
4969 packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
4970 {
4971 /* exclude type RTMP_PACKET_TYPE_FLASH_VIDEO since it can
4972 * contain several FLV packets
4973 */
4974 if (packet.m_nTimeStamp == 0)
4975 {
4976 ret = RTMP_READ_IGNORE;
4977 break;
4978 }
4979 else
4980 {
4981 /* stop ignoring packets */
4982 r->m_read.flags |= RTMP_READ_NO_IGNORE;
4983 }
4984 }
4985 }
4986
4987 /* calculate packet size and allocate slop buffer if necessary */
4988 size = nPacketLen +
4989 ((packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
4990 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
4991 || packet.m_packetType == RTMP_PACKET_TYPE_INFO) ? 11 : 0) +
4992 (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO ? 4 : 0);
4993
4994 if (size + 4 > buflen)
4995 {
4996 /* the extra 4 is for the case of an FLV stream without a last
4997 * prevTagSize (we need extra 4 bytes to append it) */
4998 r->m_read.buf = malloc(size + 4);
4999 if (r->m_read.buf == 0)
5000 {
5001 RTMP_Log(RTMP_LOGERROR, "Couldn't allocate memory!");
5002 ret = RTMP_READ_ERROR; /* fatal error */
5003 break;
5004 }
5005 recopy = TRUE;
5006 ptr = r->m_read.buf;
5007 }
5008 else
5009 {
5010 ptr = buf;
5011 }
5012 pend = ptr + size + 4;
5013
5014 /* use to return timestamp of last processed packet */
5015
5016 /* audio (0x08), video (0x09) or metadata (0x12) packets :
5017 * construct 11 byte header then add rtmp packet's data */
5018 if (packet.m_packetType == RTMP_PACKET_TYPE_AUDIO
5019 || packet.m_packetType == RTMP_PACKET_TYPE_VIDEO
5020 || packet.m_packetType == RTMP_PACKET_TYPE_INFO)
5021 {
5022 nTimeStamp = r->m_read.nResumeTS + packet.m_nTimeStamp;
5023 prevTagSize = 11 + nPacketLen;
5024
5025 *ptr = packet.m_packetType;
5026 ptr++;
5027 ptr = AMF_EncodeInt24(ptr, pend, nPacketLen);
5028
5029 #if 0
5030 if(packet.m_packetType == RTMP_PACKET_TYPE_VIDEO)
5031 {
5032
5033 /* H264 fix: */
5034 if((packetBody[0] & 0x0f) == 7) /* CodecId = H264 */
5035 {
5036 uint8_t packetType = *(packetBody+1);
5037
5038 uint32_t ts = AMF_DecodeInt24(packetBody+2); /* composition time */
5039 int32_t cts = (ts+0xff800000)^0xff800000;
5040 RTMP_Log(RTMP_LOGDEBUG, "cts : %d\n", cts);
5041
5042 nTimeStamp -= cts;
5043 /* get rid of the composition time */
5044 CRTMP::EncodeInt24(packetBody+2, 0);
5045 }
5046 RTMP_Log(RTMP_LOGDEBUG, "VIDEO: nTimeStamp: 0x%08X (%d)\n", nTimeStamp, nTimeStamp);
5047 }
5048 #endif
5049
5050 ptr = AMF_EncodeInt24(ptr, pend, nTimeStamp);
5051 *ptr = (char)((nTimeStamp & 0xFF000000) >> 24);
5052 ptr++;
5053
5054 /* stream id */
5055 ptr = AMF_EncodeInt24(ptr, pend, 0);
5056 }
5057
5058 memcpy(ptr, packetBody, nPacketLen);
5059 len = nPacketLen;
5060
5061 /* correct tagSize and obtain timestamp if we have an FLV stream */
5062 if (packet.m_packetType == RTMP_PACKET_TYPE_FLASH_VIDEO)
5063 {
5064 unsigned int pos = 0;
5065 int delta;
5066
5067 /* grab first timestamp and see if it needs fixing */
5068 nTimeStamp = AMF_DecodeInt24(packetBody + 4);
5069 nTimeStamp |= (packetBody[7] << 24);
5070 delta = packet.m_nTimeStamp - nTimeStamp + r->m_read.nResumeTS;
5071
5072 while (pos + 11 < nPacketLen)
5073 {
5074 /* size without header (11) and without prevTagSize (4) */
5075 uint32_t dataSize = AMF_DecodeInt24(packetBody + pos + 1);
5076 nTimeStamp = AMF_DecodeInt24(packetBody + pos + 4);
5077 nTimeStamp |= (packetBody[pos + 7] << 24);
5078
5079 if (delta)
5080 {
5081 nTimeStamp += delta;
5082 AMF_EncodeInt24(ptr+pos+4, pend, nTimeStamp);
5083 ptr[pos+7] = nTimeStamp>>24;
5084 }
5085
5086 /* set data type */
5087 r->m_read.dataType |= (((*(packetBody + pos) == 0x08) << 2) |
5088 (*(packetBody + pos) == 0x09));
5089
5090 if (pos + 11 + dataSize + 4 > nPacketLen)
5091 {
5092 if (pos + 11 + dataSize > nPacketLen)
5093 {
5094 RTMP_Log(RTMP_LOGERROR,
5095 "Wrong data size (%u), stream corrupted, aborting!",
5096 dataSize);
5097 ret = RTMP_READ_ERROR;
5098 break;
5099 }
5100 RTMP_Log(RTMP_LOGWARNING, "No tagSize found, appending!");
5101
5102 /* we have to append a last tagSize! */
5103 prevTagSize = dataSize + 11;
5104 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
5105 prevTagSize);
5106 size += 4;
5107 len += 4;
5108 }
5109 else
5110 {
5111 prevTagSize =
5112 AMF_DecodeInt32(packetBody + pos + 11 + dataSize);
5113
5114 #ifdef _DEBUG
5115 RTMP_Log(RTMP_LOGDEBUG,
5116 "FLV Packet: type %02X, dataSize: %u, tagSize: %u, timeStamp: %u ms",
5117 (unsigned char)packetBody[pos], dataSize, prevTagSize,
5118 nTimeStamp);
5119 #endif
5120
5121 if (prevTagSize != (dataSize + 11))
5122 {
5123 #ifdef _DEBUG
5124 RTMP_Log(RTMP_LOGWARNING,
5125 "Tag and data size are not consitent, writing tag size according to dataSize+11: %d",
5126 dataSize + 11);
5127 #endif
5128
5129 prevTagSize = dataSize + 11;
5130 AMF_EncodeInt32(ptr + pos + 11 + dataSize, pend,
5131 prevTagSize);
5132 }
5133 }
5134
5135 pos += prevTagSize + 4; /*(11+dataSize+4); */
5136 }
5137 }
5138 ptr += len;
5139
5140 if (packet.m_packetType != RTMP_PACKET_TYPE_FLASH_VIDEO)
5141 {
5142 /* FLV tag packets contain their own prevTagSize */
5143 AMF_EncodeInt32(ptr, pend, prevTagSize);
5144 }
5145
5146 /* In non-live this nTimeStamp can contain an absolute TS.
5147 * Update ext timestamp with this absolute offset in non-live mode
5148 * otherwise report the relative one
5149 */
5150 /* 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); */
5151 r->m_read.timestamp = (r->Link.lFlags & RTMP_LF_LIVE) ? packet.m_nTimeStamp : nTimeStamp;
5152
5153 ret = size;
5154 break;
5155 }
5156
5157 if (rtnGetNextMediaPacket)
5158 RTMPPacket_Free(&packet);
5159
5160 if (recopy)
5161 {
5162 len = ret > (int)(buflen) ? buflen : (unsigned int)(ret);
5163 memcpy(buf, r->m_read.buf, len);
5164 r->m_read.bufpos = r->m_read.buf + len;
5165 r->m_read.buflen = ret - len;
5166 }
5167 return ret;
5168 }
5169
5170 static const char flvHeader[] = { 'F', 'L', 'V', 0x01,
5171 0x00, /* 0x04 == audio, 0x01 == video */
5172 0x00, 0x00, 0x00, 0x09,
5173 0x00, 0x00, 0x00, 0x00
5174 };
5175
5176 #define HEADERBUF (128*1024)
5177 int
RTMP_Read(RTMP * r,char * buf,int size)5178 RTMP_Read(RTMP *r, char *buf, int size)
5179 {
5180 int nRead = 0, total = 0;
5181
5182 /* can't continue */
5183 fail:
5184 switch (r->m_read.status)
5185 {
5186 case RTMP_READ_EOF:
5187 case RTMP_READ_COMPLETE:
5188 return 0;
5189 case RTMP_READ_ERROR: /* corrupted stream, resume failed */
5190 SetSockError(EINVAL);
5191 return -1;
5192 default:
5193 break;
5194 }
5195
5196 /* first time thru */
5197 if (!(r->m_read.flags & RTMP_READ_HEADER))
5198 {
5199 if (!(r->m_read.flags & RTMP_READ_RESUME))
5200 {
5201 char *mybuf = malloc(HEADERBUF), *end = mybuf + HEADERBUF;
5202 int cnt = 0;
5203 r->m_read.buf = mybuf;
5204 r->m_read.buflen = HEADERBUF;
5205
5206 memcpy(mybuf, flvHeader, sizeof(flvHeader));
5207 r->m_read.buf += sizeof(flvHeader);
5208 r->m_read.buflen -= sizeof(flvHeader);
5209 cnt += sizeof(flvHeader);
5210
5211 while (r->m_read.timestamp == 0)
5212 {
5213 nRead = Read_1_Packet(r, r->m_read.buf, r->m_read.buflen);
5214 if (nRead < 0)
5215 {
5216 free(mybuf);
5217 r->m_read.buf = NULL;
5218 r->m_read.buflen = 0;
5219 r->m_read.status = nRead;
5220 goto fail;
5221 }
5222 /* buffer overflow, fix buffer and give up */
5223 if (r->m_read.buf < mybuf || r->m_read.buf > end)
5224 {
5225 mybuf = realloc(mybuf, cnt + nRead);
5226 memcpy(mybuf+cnt, r->m_read.buf, nRead);
5227 free(r->m_read.buf);
5228 r->m_read.buf = mybuf+cnt+nRead;
5229 break;
5230 }
5231 cnt += nRead;
5232 r->m_read.buf += nRead;
5233 r->m_read.buflen -= nRead;
5234 if (r->m_read.dataType == 5)
5235 break;
5236 }
5237 mybuf[4] = r->m_read.dataType;
5238 r->m_read.buflen = r->m_read.buf - mybuf;
5239 r->m_read.buf = mybuf;
5240 r->m_read.bufpos = mybuf;
5241 }
5242 r->m_read.flags |= RTMP_READ_HEADER;
5243 }
5244
5245 if ((r->m_read.flags & RTMP_READ_SEEKING) && r->m_read.buf)
5246 {
5247 /* drop whatever's here */
5248 free(r->m_read.buf);
5249 r->m_read.buf = NULL;
5250 r->m_read.bufpos = NULL;
5251 r->m_read.buflen = 0;
5252 }
5253
5254 /* If there's leftover data buffered, use it up */
5255 if (r->m_read.buf)
5256 {
5257 nRead = r->m_read.buflen;
5258 if (nRead > size)
5259 nRead = size;
5260 memcpy(buf, r->m_read.bufpos, nRead);
5261 r->m_read.buflen -= nRead;
5262 if (!r->m_read.buflen)
5263 {
5264 free(r->m_read.buf);
5265 r->m_read.buf = NULL;
5266 r->m_read.bufpos = NULL;
5267 }
5268 else
5269 {
5270 r->m_read.bufpos += nRead;
5271 }
5272 buf += nRead;
5273 total += nRead;
5274 size -= nRead;
5275 }
5276
5277 while (size > 0 && (nRead = Read_1_Packet(r, buf, size)) >= 0)
5278 {
5279 if (!nRead) continue;
5280 buf += nRead;
5281 total += nRead;
5282 size -= nRead;
5283 break;
5284 }
5285 if (nRead < 0)
5286 r->m_read.status = nRead;
5287
5288 if (size < 0)
5289 total += size;
5290 return total;
5291 }
5292
5293 int
RTMP_Write(RTMP * r,const char * buf,int size,int streamIdx)5294 RTMP_Write(RTMP *r, const char *buf, int size, int streamIdx)
5295 {
5296 RTMPPacket *pkt = &r->m_write;
5297 char *enc;
5298 int s2 = size, ret, num;
5299
5300 pkt->m_nChannel = 0x04; /* source channel */
5301 pkt->m_nInfoField2 = r->Link.streams[streamIdx].id;
5302
5303 while (s2)
5304 {
5305 if (!pkt->m_nBytesRead)
5306 {
5307 if (size < 11)
5308 {
5309 /* FLV pkt too small */
5310 return 0;
5311 }
5312
5313 if (buf[0] == 'F' && buf[1] == 'L' && buf[2] == 'V')
5314 {
5315 buf += 13;
5316 s2 -= 13;
5317 }
5318
5319 pkt->m_packetType = *buf++;
5320 pkt->m_nBodySize = AMF_DecodeInt24(buf);
5321 buf += 3;
5322 pkt->m_nTimeStamp = AMF_DecodeInt24(buf);
5323 buf += 3;
5324 pkt->m_nTimeStamp |= *buf++ << 24;
5325 buf += 3;
5326 s2 -= 11;
5327
5328 if (((pkt->m_packetType == RTMP_PACKET_TYPE_AUDIO
5329 || pkt->m_packetType == RTMP_PACKET_TYPE_VIDEO) &&
5330 !pkt->m_nTimeStamp) || pkt->m_packetType == RTMP_PACKET_TYPE_INFO)
5331 {
5332 pkt->m_headerType = RTMP_PACKET_SIZE_LARGE;
5333 }
5334 else
5335 {
5336 pkt->m_headerType = RTMP_PACKET_SIZE_MEDIUM;
5337 }
5338
5339 if (!RTMPPacket_Alloc(pkt, pkt->m_nBodySize))
5340 {
5341 RTMP_Log(RTMP_LOGDEBUG, "%s, failed to allocate packet", __FUNCTION__);
5342 return FALSE;
5343 }
5344 enc = pkt->m_body;
5345 }
5346 else
5347 {
5348 enc = pkt->m_body + pkt->m_nBytesRead;
5349 }
5350 num = pkt->m_nBodySize - pkt->m_nBytesRead;
5351 if (num > s2)
5352 num = s2;
5353 memcpy(enc, buf, num);
5354 pkt->m_nBytesRead += num;
5355 s2 -= num;
5356 buf += num;
5357 if (pkt->m_nBytesRead == pkt->m_nBodySize)
5358 {
5359 ret = RTMP_SendPacket(r, pkt, FALSE);
5360 RTMPPacket_Free(pkt);
5361 pkt->m_nBytesRead = 0;
5362 if (!ret)
5363 return -1;
5364 buf += 4;
5365 s2 -= 4;
5366 if (s2 < 0)
5367 break;
5368 }
5369 }
5370 return size+s2;
5371 }
5372