rtmp: Add support for adobe authentication
[libav.git] / libavformat / rtmpproto.c
CommitLineData
9fd6b843
KS
1/*
2 * RTMP network protocol
3 * Copyright (c) 2009 Kostya Shishkov
4 *
2912e87a 5 * This file is part of Libav.
9fd6b843 6 *
2912e87a 7 * Libav is free software; you can redistribute it and/or
9fd6b843
KS
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
2912e87a 12 * Libav is distributed in the hope that it will be useful,
9fd6b843
KS
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
2912e87a 18 * License along with Libav; if not, write to the Free Software
9fd6b843
KS
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22/**
ba87f080 23 * @file
9fd6b843
KS
24 * RTMP protocol
25 */
26
27#include "libavcodec/bytestream.h"
28#include "libavutil/avstring.h"
08225d01 29#include "libavutil/base64.h"
3383a53e 30#include "libavutil/intfloat.h"
9fd6b843 31#include "libavutil/lfg.h"
08225d01 32#include "libavutil/md5.h"
6465562e 33#include "libavutil/opt.h"
e5f2731c 34#include "libavutil/random_seed.h"
9fd6b843
KS
35#include "libavutil/sha.h"
36#include "avformat.h"
e4a9e3cc 37#include "internal.h"
9fd6b843
KS
38
39#include "network.h"
40
41#include "flv.h"
42#include "rtmp.h"
acd554c1 43#include "rtmpcrypt.h"
9fd6b843 44#include "rtmppkt.h"
0589da0a 45#include "url.h"
9fd6b843 46
93f257db
SP
47#if CONFIG_ZLIB
48#include <zlib.h>
49#endif
50
cfac91fe
KS
51//#define DEBUG
52
6465562e 53#define APP_MAX_LENGTH 128
b3b17512 54#define PLAYPATH_MAX_LENGTH 256
55c9320e 55#define TCURL_MAX_LENGTH 512
e64673e4 56#define FLASHVER_MAX_LENGTH 64
e5f2731c 57#define RTMP_PKTDATA_DEFAULT_SIZE 4096
6465562e 58
9fd6b843
KS
59/** RTMP protocol handler state */
60typedef enum {
61 STATE_START, ///< client has not done anything yet
62 STATE_HANDSHAKED, ///< client has performed handshake
6bf22e18 63 STATE_FCPUBLISH, ///< client FCPublishing stream (for output)
9fd6b843 64 STATE_PLAYING, ///< client has started receiving multimedia data from server
6bf22e18 65 STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
e5f2731c 66 STATE_RECEIVING, ///< received a publish command (for input)
72b870b9 67 STATE_STOPPED, ///< the broadcast has been stopped
9fd6b843
KS
68} ClientState;
69
f89584ca
SP
70typedef struct TrackedMethod {
71 char *name;
72 int id;
73} TrackedMethod;
74
9fd6b843
KS
75/** protocol handler context */
76typedef struct RTMPContext {
6465562e 77 const AVClass *class;
9fd6b843
KS
78 URLContext* stream; ///< TCP stream used in interactions with RTMP server
79 RTMPPacket prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
f5ce90f2
JO
80 int in_chunk_size; ///< size of the chunks incoming RTMP packets are divided into
81 int out_chunk_size; ///< size of the chunks outgoing RTMP packets are divided into
b316991b 82 int is_input; ///< input/output flag
b3b17512 83 char *playpath; ///< stream identifier to play (with possible "mp4:" prefix)
b2e495af 84 int live; ///< 0: recorded, -1: live, -2: both
6465562e 85 char *app; ///< name of application
8ee3e187 86 char *conn; ///< append arbitrary AMF data to the Connect message
9fd6b843
KS
87 ClientState state; ///< current state
88 int main_channel_id; ///< an additional channel ID which is used for some invocations
89 uint8_t* flv_data; ///< buffer with data for demuxer
90 int flv_size; ///< current buffer size
91 int flv_off; ///< number of bytes read from current buffer
46743a85 92 int flv_nb_packets; ///< number of flv packets published
6bf22e18 93 RTMPPacket out_pkt; ///< rtmp packet, created from flv a/v or metadata (for output)
bf7c1719
KS
94 uint32_t client_report_size; ///< number of bytes after which client should report to server
95 uint32_t bytes_read; ///< number of bytes read from server
96 uint32_t last_bytes_read; ///< number of bytes read last reported to server
3ffe32eb 97 int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call
b14629e5
MS
98 uint8_t flv_header[11]; ///< partial incoming flv packet header
99 int flv_header_bytes; ///< number of initialized bytes in flv_header
704af3e2 100 int nb_invokes; ///< keeps track of invoke messages
55c9320e 101 char* tcurl; ///< url of the target stream
e64673e4 102 char* flashver; ///< version of the flash plugin
635ac8e1
SP
103 char* swfhash; ///< SHA256 hash of the decompressed SWF file (32 bytes)
104 int swfhash_len; ///< length of the SHA256 hash
105 int swfsize; ///< size of the decompressed SWF file
05945db9 106 char* swfurl; ///< url of the swf player
93f257db 107 char* swfverify; ///< URL to player swf file, compute hash/size automatically
635ac8e1 108 char swfverification[42]; ///< hash of the SWF verification
758377a2 109 char* pageurl; ///< url of the web page
00cb52c6 110 char* subscribe; ///< name of live stream to subscribe
c2d38bea 111 int server_bw; ///< server bandwidth
9477c035 112 int client_buffer_time; ///< client buffer time in ms
46743a85 113 int flush_interval; ///< number of packets flushed in the same request (RTMPT only)
acd554c1 114 int encrypted; ///< use an encrypted connection (RTMPE only)
f89584ca
SP
115 TrackedMethod*tracked_methods; ///< tracked methods buffer
116 int nb_tracked_methods; ///< number of tracked methods
117 int tracked_methods_size; ///< size of the tracked methods buffer
e5f2731c
JO
118 int listen; ///< listen mode flag
119 int listen_timeout; ///< listen timeout to wait for new connections
120 int nb_streamid; ///< The next stream id to return on createStream calls
08225d01
MS
121 char username[50];
122 char password[50];
123 char auth_params[500];
124 int do_reconnect;
125 int auth_tried;
9fd6b843
KS
126} RTMPContext;
127
128#define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing
129/** Client key used for digest signing */
130static const uint8_t rtmp_player_key[] = {
131 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
132 'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',
133
134 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
135 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
136 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
137};
138
139#define SERVER_KEY_OPEN_PART_LEN 36 ///< length of partial key used for first server digest signing
140/** Key used for RTMP server digest signing */
141static const uint8_t rtmp_server_key[] = {
142 'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
143 'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
144 'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',
145
146 0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
147 0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
148 0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
149};
150
f89584ca
SP
151static int add_tracked_method(RTMPContext *rt, const char *name, int id)
152{
153 void *ptr;
154
155 if (rt->nb_tracked_methods + 1 > rt->tracked_methods_size) {
156 rt->tracked_methods_size = (rt->nb_tracked_methods + 1) * 2;
157 ptr = av_realloc(rt->tracked_methods,
158 rt->tracked_methods_size * sizeof(*rt->tracked_methods));
159 if (!ptr)
160 return AVERROR(ENOMEM);
161 rt->tracked_methods = ptr;
162 }
163
164 rt->tracked_methods[rt->nb_tracked_methods].name = av_strdup(name);
165 if (!rt->tracked_methods[rt->nb_tracked_methods].name)
166 return AVERROR(ENOMEM);
167 rt->tracked_methods[rt->nb_tracked_methods].id = id;
168 rt->nb_tracked_methods++;
169
170 return 0;
171}
172
173static void del_tracked_method(RTMPContext *rt, int index)
174{
175 memmove(&rt->tracked_methods[index], &rt->tracked_methods[index + 1],
176 sizeof(*rt->tracked_methods) * (rt->nb_tracked_methods - index - 1));
177 rt->nb_tracked_methods--;
178}
179
a8103503
SP
180static int find_tracked_method(URLContext *s, RTMPPacket *pkt, int offset,
181 char **tracked_method)
182{
183 RTMPContext *rt = s->priv_data;
184 GetByteContext gbc;
185 double pkt_id;
186 int ret;
187 int i;
188
189 bytestream2_init(&gbc, pkt->data + offset, pkt->data_size - offset);
190 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
191 return ret;
192
193 for (i = 0; i < rt->nb_tracked_methods; i++) {
194 if (rt->tracked_methods[i].id != pkt_id)
195 continue;
196
197 *tracked_method = rt->tracked_methods[i].name;
198 del_tracked_method(rt, i);
199 break;
200 }
201
202 return 0;
203}
204
f89584ca
SP
205static void free_tracked_methods(RTMPContext *rt)
206{
207 int i;
208
209 for (i = 0; i < rt->nb_tracked_methods; i ++)
210 av_free(rt->tracked_methods[i].name);
211 av_free(rt->tracked_methods);
08225d01
MS
212 rt->tracked_methods = NULL;
213 rt->tracked_methods_size = 0;
214 rt->nb_tracked_methods = 0;
f89584ca
SP
215}
216
217static int rtmp_send_packet(RTMPContext *rt, RTMPPacket *pkt, int track)
218{
219 int ret;
220
221 if (pkt->type == RTMP_PT_INVOKE && track) {
222 GetByteContext gbc;
223 char name[128];
224 double pkt_id;
225 int len;
226
227 bytestream2_init(&gbc, pkt->data, pkt->data_size);
228 if ((ret = ff_amf_read_string(&gbc, name, sizeof(name), &len)) < 0)
229 goto fail;
230
231 if ((ret = ff_amf_read_number(&gbc, &pkt_id)) < 0)
232 goto fail;
233
234 if ((ret = add_tracked_method(rt, name, pkt_id)) < 0)
235 goto fail;
236 }
237
f5ce90f2 238 ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
f89584ca
SP
239 rt->prev_pkt[1]);
240fail:
241 ff_rtmp_packet_destroy(pkt);
242 return ret;
243}
244
8ee3e187
SP
245static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
246{
05338686 247 char *field, *value;
8ee3e187
SP
248 char type;
249
250 /* The type must be B for Boolean, N for number, S for string, O for
251 * object, or Z for null. For Booleans the data must be either 0 or 1 for
252 * FALSE or TRUE, respectively. Likewise for Objects the data must be
253 * 0 or 1 to end or begin an object, respectively. Data items in subobjects
254 * may be named, by prefixing the type with 'N' and specifying the name
255 * before the value (ie. NB:myFlag:1). This option may be used multiple times
256 * to construct arbitrary AMF sequences. */
257 if (param[0] && param[1] == ':') {
258 type = param[0];
259 value = param + 2;
260 } else if (param[0] == 'N' && param[1] && param[2] == ':') {
261 type = param[1];
05338686
MS
262 field = param + 3;
263 value = strchr(field, ':');
264 if (!value)
265 goto fail;
266 *value = '\0';
267 value++;
8ee3e187
SP
268
269 if (!field || !value)
270 goto fail;
271
272 ff_amf_write_field_name(p, field);
273 } else {
274 goto fail;
275 }
276
277 switch (type) {
278 case 'B':
279 ff_amf_write_bool(p, value[0] != '0');
280 break;
281 case 'S':
282 ff_amf_write_string(p, value);
283 break;
284 case 'N':
285 ff_amf_write_number(p, strtod(value, NULL));
286 break;
287 case 'Z':
288 ff_amf_write_null(p);
289 break;
290 case 'O':
291 if (value[0] != '0')
292 ff_amf_write_object_start(p);
293 else
294 ff_amf_write_object_end(p);
295 break;
296 default:
297 goto fail;
298 break;
299 }
300
301 return 0;
302
303fail:
304 av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
305 return AVERROR(EINVAL);
306}
307
9fd6b843 308/**
49bd8e4b 309 * Generate 'connect' call and send it to the server.
9fd6b843 310 */
f645f1d6 311static int gen_connect(URLContext *s, RTMPContext *rt)
9fd6b843
KS
312{
313 RTMPPacket pkt;
e64673e4 314 uint8_t *p;
f645f1d6
SP
315 int ret;
316
317 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
318 0, 4096)) < 0)
319 return ret;
9fd6b843 320
9fd6b843
KS
321 p = pkt.data;
322
9fd6b843 323 ff_amf_write_string(&p, "connect");
1eef08f9 324 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
325 ff_amf_write_object_start(&p);
326 ff_amf_write_field_name(&p, "app");
08225d01 327 ff_amf_write_string2(&p, rt->app, rt->auth_params);
9fd6b843 328
e64673e4 329 if (!rt->is_input) {
6bf22e18
S
330 ff_amf_write_field_name(&p, "type");
331 ff_amf_write_string(&p, "nonprivate");
332 }
9fd6b843 333 ff_amf_write_field_name(&p, "flashVer");
e64673e4 334 ff_amf_write_string(&p, rt->flashver);
05945db9
SP
335
336 if (rt->swfurl) {
337 ff_amf_write_field_name(&p, "swfUrl");
338 ff_amf_write_string(&p, rt->swfurl);
339 }
340
9fd6b843 341 ff_amf_write_field_name(&p, "tcUrl");
08225d01 342 ff_amf_write_string2(&p, rt->tcurl, rt->auth_params);
6bf22e18 343 if (rt->is_input) {
c7240611
KS
344 ff_amf_write_field_name(&p, "fpad");
345 ff_amf_write_bool(&p, 0);
346 ff_amf_write_field_name(&p, "capabilities");
347 ff_amf_write_number(&p, 15.0);
faba4a9b
SP
348
349 /* Tell the server we support all the audio codecs except
350 * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
351 * which are unused in the RTMP protocol implementation. */
c7240611 352 ff_amf_write_field_name(&p, "audioCodecs");
faba4a9b 353 ff_amf_write_number(&p, 4071.0);
c7240611
KS
354 ff_amf_write_field_name(&p, "videoCodecs");
355 ff_amf_write_number(&p, 252.0);
356 ff_amf_write_field_name(&p, "videoFunction");
357 ff_amf_write_number(&p, 1.0);
758377a2
SP
358
359 if (rt->pageurl) {
360 ff_amf_write_field_name(&p, "pageUrl");
361 ff_amf_write_string(&p, rt->pageurl);
362 }
6bf22e18 363 }
9fd6b843
KS
364 ff_amf_write_object_end(&p);
365
8ee3e187 366 if (rt->conn) {
05338686 367 char *param = rt->conn;
8ee3e187
SP
368
369 // Write arbitrary AMF data to the Connect message.
8ee3e187 370 while (param != NULL) {
05338686
MS
371 char *sep;
372 param += strspn(param, " ");
373 if (!*param)
374 break;
375 sep = strchr(param, ' ');
376 if (sep)
377 *sep = '\0';
8ee3e187
SP
378 if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
379 // Invalid AMF parameter.
380 ff_rtmp_packet_destroy(&pkt);
381 return ret;
382 }
383
05338686
MS
384 if (sep)
385 param = sep + 1;
386 else
387 break;
8ee3e187
SP
388 }
389 }
390
9fd6b843
KS
391 pkt.data_size = p - pkt.data;
392
f89584ca 393 return rtmp_send_packet(rt, &pkt, 1);
9fd6b843
KS
394}
395
e5f2731c
JO
396static int read_connect(URLContext *s, RTMPContext *rt)
397{
398 RTMPPacket pkt = { 0 };
399 uint8_t *p;
400 const uint8_t *cp;
401 int ret;
402 char command[64];
403 int stringlen;
404 double seqnum;
405 uint8_t tmpstr[256];
406 GetByteContext gbc;
407
408 if ((ret = ff_rtmp_packet_read(rt->stream, &pkt, rt->in_chunk_size,
409 rt->prev_pkt[1])) < 0)
410 return ret;
411 cp = pkt.data;
412 bytestream2_init(&gbc, cp, pkt.data_size);
413 if (ff_amf_read_string(&gbc, command, sizeof(command), &stringlen)) {
414 av_log(s, AV_LOG_ERROR, "Unable to read command string\n");
415 ff_rtmp_packet_destroy(&pkt);
416 return AVERROR_INVALIDDATA;
417 }
418 if (strcmp(command, "connect")) {
419 av_log(s, AV_LOG_ERROR, "Expecting connect, got %s\n", command);
420 ff_rtmp_packet_destroy(&pkt);
421 return AVERROR_INVALIDDATA;
422 }
423 ret = ff_amf_read_number(&gbc, &seqnum);
424 if (ret)
425 av_log(s, AV_LOG_WARNING, "SeqNum not found\n");
426 /* Here one could parse an AMF Object with data as flashVers and others. */
427 ret = ff_amf_get_field_value(gbc.buffer,
428 gbc.buffer + bytestream2_get_bytes_left(&gbc),
429 "app", tmpstr, sizeof(tmpstr));
430 if (ret)
431 av_log(s, AV_LOG_WARNING, "App field not found in connect\n");
432 if (!ret && strcmp(tmpstr, rt->app))
433 av_log(s, AV_LOG_WARNING, "App field don't match up: %s <-> %s\n",
434 tmpstr, rt->app);
435 ff_rtmp_packet_destroy(&pkt);
436
437 // Send Window Acknowledgement Size (as defined in speficication)
438 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
439 RTMP_PT_SERVER_BW, 0, 4)) < 0)
440 return ret;
441 p = pkt.data;
442 bytestream_put_be32(&p, rt->server_bw);
443 pkt.data_size = p - pkt.data;
444 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
445 rt->prev_pkt[1]);
446 ff_rtmp_packet_destroy(&pkt);
447 if (ret < 0)
448 return ret;
449 // Send Peer Bandwidth
450 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
451 RTMP_PT_CLIENT_BW, 0, 5)) < 0)
452 return ret;
453 p = pkt.data;
454 bytestream_put_be32(&p, rt->server_bw);
455 bytestream_put_byte(&p, 2); // dynamic
456 pkt.data_size = p - pkt.data;
457 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
458 rt->prev_pkt[1]);
459 ff_rtmp_packet_destroy(&pkt);
460 if (ret < 0)
461 return ret;
462
463 // Ping request
464 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL,
465 RTMP_PT_PING, 0, 6)) < 0)
466 return ret;
467
468 p = pkt.data;
469 bytestream_put_be16(&p, 0); // 0 -> Stream Begin
470 bytestream_put_be32(&p, 0);
471 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
472 rt->prev_pkt[1]);
473 ff_rtmp_packet_destroy(&pkt);
474 if (ret < 0)
475 return ret;
476
477 // Chunk size
478 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
479 RTMP_PT_CHUNK_SIZE, 0, 4)) < 0)
480 return ret;
481
482 p = pkt.data;
483 bytestream_put_be32(&p, rt->out_chunk_size);
484 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
485 rt->prev_pkt[1]);
486 ff_rtmp_packet_destroy(&pkt);
487 if (ret < 0)
488 return ret;
489
490 // Send result_ NetConnection.Connect.Success to connect
491 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
492 RTMP_PT_INVOKE, 0,
493 RTMP_PKTDATA_DEFAULT_SIZE)) < 0)
494 return ret;
495
496 p = pkt.data;
497 ff_amf_write_string(&p, "_result");
498 ff_amf_write_number(&p, seqnum);
499
500 ff_amf_write_object_start(&p);
501 ff_amf_write_field_name(&p, "fmsVer");
502 ff_amf_write_string(&p, "FMS/3,0,1,123");
503 ff_amf_write_field_name(&p, "capabilities");
504 ff_amf_write_number(&p, 31);
505 ff_amf_write_object_end(&p);
506
507 ff_amf_write_object_start(&p);
508 ff_amf_write_field_name(&p, "level");
509 ff_amf_write_string(&p, "status");
510 ff_amf_write_field_name(&p, "code");
511 ff_amf_write_string(&p, "NetConnection.Connect.Success");
512 ff_amf_write_field_name(&p, "description");
513 ff_amf_write_string(&p, "Connection succeeded.");
514 ff_amf_write_field_name(&p, "objectEncoding");
515 ff_amf_write_number(&p, 0);
516 ff_amf_write_object_end(&p);
517
518 pkt.data_size = p - pkt.data;
519 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
520 rt->prev_pkt[1]);
521 ff_rtmp_packet_destroy(&pkt);
522 if (ret < 0)
523 return ret;
524
525 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL,
526 RTMP_PT_INVOKE, 0, 30)) < 0)
527 return ret;
528 p = pkt.data;
529 ff_amf_write_string(&p, "onBWDone");
530 ff_amf_write_number(&p, 0);
531 ff_amf_write_null(&p);
532 ff_amf_write_number(&p, 8192);
533 pkt.data_size = p - pkt.data;
534 ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->out_chunk_size,
535 rt->prev_pkt[1]);
536 ff_rtmp_packet_destroy(&pkt);
537
538 return ret;
539}
540
9fd6b843 541/**
49bd8e4b 542 * Generate 'releaseStream' call and send it to the server. It should make
6bf22e18
S
543 * the server release some channel for media streams.
544 */
f645f1d6 545static int gen_release_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
546{
547 RTMPPacket pkt;
548 uint8_t *p;
f645f1d6 549 int ret;
6bf22e18 550
f645f1d6
SP
551 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
552 0, 29 + strlen(rt->playpath))) < 0)
553 return ret;
6bf22e18 554
7f804085 555 av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
6bf22e18
S
556 p = pkt.data;
557 ff_amf_write_string(&p, "releaseStream");
704af3e2 558 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
559 ff_amf_write_null(&p);
560 ff_amf_write_string(&p, rt->playpath);
561
7011a42b 562 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
563}
564
565/**
49bd8e4b 566 * Generate 'FCPublish' call and send it to the server. It should make
6bf22e18
S
567 * the server preapare for receiving media streams.
568 */
f645f1d6 569static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
570{
571 RTMPPacket pkt;
572 uint8_t *p;
f645f1d6 573 int ret;
6bf22e18 574
f645f1d6
SP
575 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
576 0, 25 + strlen(rt->playpath))) < 0)
577 return ret;
6bf22e18 578
7f804085 579 av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
6bf22e18
S
580 p = pkt.data;
581 ff_amf_write_string(&p, "FCPublish");
704af3e2 582 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
583 ff_amf_write_null(&p);
584 ff_amf_write_string(&p, rt->playpath);
585
7011a42b 586 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
587}
588
589/**
49bd8e4b 590 * Generate 'FCUnpublish' call and send it to the server. It should make
6bf22e18
S
591 * the server destroy stream.
592 */
f645f1d6 593static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
594{
595 RTMPPacket pkt;
596 uint8_t *p;
f645f1d6 597 int ret;
6bf22e18 598
f645f1d6
SP
599 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
600 0, 27 + strlen(rt->playpath))) < 0)
601 return ret;
6bf22e18 602
7f804085 603 av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
6bf22e18
S
604 p = pkt.data;
605 ff_amf_write_string(&p, "FCUnpublish");
704af3e2 606 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
607 ff_amf_write_null(&p);
608 ff_amf_write_string(&p, rt->playpath);
609
f89584ca 610 return rtmp_send_packet(rt, &pkt, 0);
6bf22e18
S
611}
612
613/**
49bd8e4b 614 * Generate 'createStream' call and send it to the server. It should make
9fd6b843
KS
615 * the server allocate some channel for media streams.
616 */
f645f1d6 617static int gen_create_stream(URLContext *s, RTMPContext *rt)
9fd6b843
KS
618{
619 RTMPPacket pkt;
620 uint8_t *p;
f645f1d6 621 int ret;
9fd6b843 622
7f804085 623 av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
f645f1d6
SP
624
625 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
626 0, 25)) < 0)
627 return ret;
9fd6b843
KS
628
629 p = pkt.data;
630 ff_amf_write_string(&p, "createStream");
704af3e2 631 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
632 ff_amf_write_null(&p);
633
f89584ca 634 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
635}
636
637
638/**
49bd8e4b 639 * Generate 'deleteStream' call and send it to the server. It should make
6bf22e18
S
640 * the server remove some channel for media streams.
641 */
f645f1d6 642static int gen_delete_stream(URLContext *s, RTMPContext *rt)
6bf22e18
S
643{
644 RTMPPacket pkt;
645 uint8_t *p;
f645f1d6 646 int ret;
6bf22e18 647
7f804085 648 av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
f645f1d6
SP
649
650 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
651 0, 34)) < 0)
652 return ret;
6bf22e18
S
653
654 p = pkt.data;
655 ff_amf_write_string(&p, "deleteStream");
1eef08f9 656 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843 657 ff_amf_write_null(&p);
6bf22e18 658 ff_amf_write_number(&p, rt->main_channel_id);
9fd6b843 659
f89584ca 660 return rtmp_send_packet(rt, &pkt, 0);
9fd6b843
KS
661}
662
663/**
9477c035
SP
664 * Generate client buffer time and send it to the server.
665 */
666static int gen_buffer_time(URLContext *s, RTMPContext *rt)
667{
668 RTMPPacket pkt;
669 uint8_t *p;
670 int ret;
671
672 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
673 1, 10)) < 0)
674 return ret;
675
676 p = pkt.data;
677 bytestream_put_be16(&p, 3);
678 bytestream_put_be32(&p, rt->main_channel_id);
679 bytestream_put_be32(&p, rt->client_buffer_time);
680
f89584ca 681 return rtmp_send_packet(rt, &pkt, 0);
9477c035
SP
682}
683
684/**
49bd8e4b 685 * Generate 'play' call and send it to the server, then ping the server
9fd6b843
KS
686 * to start actual playing.
687 */
f645f1d6 688static int gen_play(URLContext *s, RTMPContext *rt)
9fd6b843
KS
689{
690 RTMPPacket pkt;
691 uint8_t *p;
f645f1d6 692 int ret;
9fd6b843 693
7f804085 694 av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
f645f1d6
SP
695
696 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
697 0, 29 + strlen(rt->playpath))) < 0)
698 return ret;
699
9fd6b843
KS
700 pkt.extra = rt->main_channel_id;
701
702 p = pkt.data;
703 ff_amf_write_string(&p, "play");
1eef08f9 704 ff_amf_write_number(&p, ++rt->nb_invokes);
9fd6b843
KS
705 ff_amf_write_null(&p);
706 ff_amf_write_string(&p, rt->playpath);
b2e495af 707 ff_amf_write_number(&p, rt->live);
9fd6b843 708
f89584ca 709 return rtmp_send_packet(rt, &pkt, 1);
9fd6b843
KS
710}
711
712/**
49bd8e4b 713 * Generate 'publish' call and send it to the server.
6bf22e18 714 */
f645f1d6 715static int gen_publish(URLContext *s, RTMPContext *rt)
6bf22e18
S
716{
717 RTMPPacket pkt;
718 uint8_t *p;
f645f1d6 719 int ret;
6bf22e18 720
7f804085 721 av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
f645f1d6
SP
722
723 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
724 0, 30 + strlen(rt->playpath))) < 0)
725 return ret;
726
6bf22e18
S
727 pkt.extra = rt->main_channel_id;
728
729 p = pkt.data;
730 ff_amf_write_string(&p, "publish");
1eef08f9 731 ff_amf_write_number(&p, ++rt->nb_invokes);
6bf22e18
S
732 ff_amf_write_null(&p);
733 ff_amf_write_string(&p, rt->playpath);
734 ff_amf_write_string(&p, "live");
735
f89584ca 736 return rtmp_send_packet(rt, &pkt, 1);
6bf22e18
S
737}
738
739/**
49bd8e4b 740 * Generate ping reply and send it to the server.
9fd6b843 741 */
f645f1d6 742static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
9fd6b843
KS
743{
744 RTMPPacket pkt;
745 uint8_t *p;
f645f1d6
SP
746 int ret;
747
8ea1459b
SP
748 if (ppkt->data_size < 6) {
749 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
750 ppkt->data_size);
751 return AVERROR_INVALIDDATA;
752 }
753
f645f1d6
SP
754 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
755 ppkt->timestamp + 1, 6)) < 0)
756 return ret;
9fd6b843 757
9fd6b843
KS
758 p = pkt.data;
759 bytestream_put_be16(&p, 7);
4aaebf78 760 bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
f645f1d6 761
f89584ca 762 return rtmp_send_packet(rt, &pkt, 0);
9fd6b843
KS
763}
764
bf7c1719 765/**
635ac8e1
SP
766 * Generate SWF verification message and send it to the server.
767 */
768static int gen_swf_verification(URLContext *s, RTMPContext *rt)
769{
770 RTMPPacket pkt;
771 uint8_t *p;
772 int ret;
773
774 av_log(s, AV_LOG_DEBUG, "Sending SWF verification...\n");
775 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
776 0, 44)) < 0)
777 return ret;
778
779 p = pkt.data;
780 bytestream_put_be16(&p, 27);
781 memcpy(p, rt->swfverification, 42);
782
783 return rtmp_send_packet(rt, &pkt, 0);
784}
785
786/**
34d908c0
RS
787 * Generate server bandwidth message and send it to the server.
788 */
f645f1d6 789static int gen_server_bw(URLContext *s, RTMPContext *rt)
34d908c0
RS
790{
791 RTMPPacket pkt;
792 uint8_t *p;
f645f1d6
SP
793 int ret;
794
795 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
796 0, 4)) < 0)
797 return ret;
34d908c0 798
34d908c0 799 p = pkt.data;
c2d38bea 800 bytestream_put_be32(&p, rt->server_bw);
f645f1d6 801
f89584ca 802 return rtmp_send_packet(rt, &pkt, 0);
34d908c0
RS
803}
804
805/**
d55961fa
SP
806 * Generate check bandwidth message and send it to the server.
807 */
f645f1d6 808static int gen_check_bw(URLContext *s, RTMPContext *rt)
d55961fa
SP
809{
810 RTMPPacket pkt;
811 uint8_t *p;
f645f1d6 812 int ret;
d55961fa 813
f645f1d6
SP
814 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
815 0, 21)) < 0)
816 return ret;
d55961fa
SP
817
818 p = pkt.data;
819 ff_amf_write_string(&p, "_checkbw");
8b6a5a79 820 ff_amf_write_number(&p, ++rt->nb_invokes);
d55961fa
SP
821 ff_amf_write_null(&p);
822
fb7e7808 823 return rtmp_send_packet(rt, &pkt, 1);
d55961fa
SP
824}
825
826/**
49bd8e4b 827 * Generate report on bytes read so far and send it to the server.
bf7c1719 828 */
f645f1d6 829static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
bf7c1719
KS
830{
831 RTMPPacket pkt;
832 uint8_t *p;
f645f1d6
SP
833 int ret;
834
835 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
836 ts, 4)) < 0)
837 return ret;
bf7c1719 838
bf7c1719
KS
839 p = pkt.data;
840 bytestream_put_be32(&p, rt->bytes_read);
f645f1d6 841
f89584ca 842 return rtmp_send_packet(rt, &pkt, 0);
bf7c1719
KS
843}
844
00cb52c6
SP
845static int gen_fcsubscribe_stream(URLContext *s, RTMPContext *rt,
846 const char *subscribe)
f9e77c17
SP
847{
848 RTMPPacket pkt;
849 uint8_t *p;
850 int ret;
851
852 if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
00cb52c6 853 0, 27 + strlen(subscribe))) < 0)
f9e77c17
SP
854 return ret;
855
856 p = pkt.data;
857 ff_amf_write_string(&p, "FCSubscribe");
858 ff_amf_write_number(&p, ++rt->nb_invokes);
859 ff_amf_write_null(&p);
00cb52c6 860 ff_amf_write_string(&p, subscribe);
f9e77c17 861
f89584ca 862 return rtmp_send_packet(rt, &pkt, 1);
f9e77c17
SP
863}
864
3505d557
SP
865int ff_rtmp_calc_digest(const uint8_t *src, int len, int gap,
866 const uint8_t *key, int keylen, uint8_t *dst)
9fd6b843
KS
867{
868 struct AVSHA *sha;
869 uint8_t hmac_buf[64+32] = {0};
870 int i;
871
e002e329 872 sha = av_sha_alloc();
08e93f5b
SP
873 if (!sha)
874 return AVERROR(ENOMEM);
9fd6b843
KS
875
876 if (keylen < 64) {
877 memcpy(hmac_buf, key, keylen);
878 } else {
879 av_sha_init(sha, 256);
880 av_sha_update(sha,key, keylen);
881 av_sha_final(sha, hmac_buf);
882 }
883 for (i = 0; i < 64; i++)
884 hmac_buf[i] ^= HMAC_IPAD_VAL;
885
886 av_sha_init(sha, 256);
887 av_sha_update(sha, hmac_buf, 64);
888 if (gap <= 0) {
889 av_sha_update(sha, src, len);
890 } else { //skip 32 bytes used for storing digest
891 av_sha_update(sha, src, gap);
892 av_sha_update(sha, src + gap + 32, len - gap - 32);
893 }
894 av_sha_final(sha, hmac_buf + 64);
895
896 for (i = 0; i < 64; i++)
897 hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
898 av_sha_init(sha, 256);
899 av_sha_update(sha, hmac_buf, 64+32);
900 av_sha_final(sha, dst);
901
902 av_free(sha);
08e93f5b
SP
903
904 return 0;
9fd6b843
KS
905}
906
0e31088b
SP
907int ff_rtmp_calc_digest_pos(const uint8_t *buf, int off, int mod_val,
908 int add_val)
909{
910 int i, digest_pos = 0;
911
912 for (i = 0; i < 4; i++)
913 digest_pos += buf[i + off];
914 digest_pos = digest_pos % mod_val + add_val;
915
916 return digest_pos;
917}
918
9fd6b843 919/**
49bd8e4b 920 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
9fd6b843
KS
921 * will be stored) into that packet.
922 *
923 * @param buf handshake data (1536 bytes)
acd554c1 924 * @param encrypted use an encrypted connection (RTMPE)
9fd6b843
KS
925 * @return offset to the digest inside input data
926 */
acd554c1 927static int rtmp_handshake_imprint_with_digest(uint8_t *buf, int encrypted)
9fd6b843 928{
0e31088b 929 int ret, digest_pos;
9fd6b843 930
acd554c1
SP
931 if (encrypted)
932 digest_pos = ff_rtmp_calc_digest_pos(buf, 772, 728, 776);
933 else
934 digest_pos = ff_rtmp_calc_digest_pos(buf, 8, 728, 12);
9fd6b843 935
3505d557
SP
936 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
937 rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
938 buf + digest_pos);
08e93f5b
SP
939 if (ret < 0)
940 return ret;
941
9fd6b843
KS
942 return digest_pos;
943}
944
945/**
49bd8e4b 946 * Verify that the received server response has the expected digest value.
9fd6b843
KS
947 *
948 * @param buf handshake data received from the server (1536 bytes)
949 * @param off position to search digest offset from
950 * @return 0 if digest is valid, digest position otherwise
951 */
952static int rtmp_validate_digest(uint8_t *buf, int off)
953{
9fd6b843 954 uint8_t digest[32];
0e31088b 955 int ret, digest_pos;
9fd6b843 956
0e31088b 957 digest_pos = ff_rtmp_calc_digest_pos(buf, off, 728, off + 4);
9fd6b843 958
3505d557
SP
959 ret = ff_rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
960 rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
961 digest);
08e93f5b
SP
962 if (ret < 0)
963 return ret;
964
9fd6b843
KS
965 if (!memcmp(digest, buf + digest_pos, 32))
966 return digest_pos;
967 return 0;
968}
969
635ac8e1
SP
970static int rtmp_calc_swf_verification(URLContext *s, RTMPContext *rt,
971 uint8_t *buf)
972{
973 uint8_t *p;
974 int ret;
975
976 if (rt->swfhash_len != 32) {
977 av_log(s, AV_LOG_ERROR,
978 "Hash of the decompressed SWF file is not 32 bytes long.\n");
979 return AVERROR(EINVAL);
980 }
981
982 p = &rt->swfverification[0];
983 bytestream_put_byte(&p, 1);
984 bytestream_put_byte(&p, 1);
985 bytestream_put_be32(&p, rt->swfsize);
986 bytestream_put_be32(&p, rt->swfsize);
987
988 if ((ret = ff_rtmp_calc_digest(rt->swfhash, 32, 0, buf, 32, p)) < 0)
989 return ret;
990
991 return 0;
992}
993
93f257db
SP
994#if CONFIG_ZLIB
995static int rtmp_uncompress_swfplayer(uint8_t *in_data, int64_t in_size,
996 uint8_t **out_data, int64_t *out_size)
997{
998 z_stream zs = { 0 };
999 void *ptr;
1000 int size;
1001 int ret = 0;
1002
1003 zs.avail_in = in_size;
1004 zs.next_in = in_data;
1005 ret = inflateInit(&zs);
1006 if (ret != Z_OK)
1007 return AVERROR_UNKNOWN;
1008
1009 do {
1010 uint8_t tmp_buf[16384];
1011
1012 zs.avail_out = sizeof(tmp_buf);
1013 zs.next_out = tmp_buf;
1014
1015 ret = inflate(&zs, Z_NO_FLUSH);
1016 if (ret != Z_OK && ret != Z_STREAM_END) {
1017 ret = AVERROR_UNKNOWN;
1018 goto fail;
1019 }
1020
1021 size = sizeof(tmp_buf) - zs.avail_out;
1022 if (!(ptr = av_realloc(*out_data, *out_size + size))) {
1023 ret = AVERROR(ENOMEM);
1024 goto fail;
1025 }
1026 *out_data = ptr;
1027
1028 memcpy(*out_data + *out_size, tmp_buf, size);
1029 *out_size += size;
1030 } while (zs.avail_out == 0);
1031
1032fail:
1033 inflateEnd(&zs);
1034 return ret;
1035}
1036#endif
1037
1038static int rtmp_calc_swfhash(URLContext *s)
1039{
1040 RTMPContext *rt = s->priv_data;
1041 uint8_t *in_data = NULL, *out_data = NULL, *swfdata;
1042 int64_t in_size, out_size;
1043 URLContext *stream;
1044 char swfhash[32];
1045 int swfsize;
1046 int ret = 0;
1047
1048 /* Get the SWF player file. */
1049 if ((ret = ffurl_open(&stream, rt->swfverify, AVIO_FLAG_READ,
1050 &s->interrupt_callback, NULL)) < 0) {
1051 av_log(s, AV_LOG_ERROR, "Cannot open connection %s.\n", rt->swfverify);
1052 goto fail;
1053 }
1054
1055 if ((in_size = ffurl_seek(stream, 0, AVSEEK_SIZE)) < 0) {
1056 ret = AVERROR(EIO);
1057 goto fail;
1058 }
1059
1060 if (!(in_data = av_malloc(in_size))) {
1061 ret = AVERROR(ENOMEM);
1062 goto fail;
1063 }
1064
1065 if ((ret = ffurl_read_complete(stream, in_data, in_size)) < 0)
1066 goto fail;
1067
1068 if (in_size < 3) {
1069 ret = AVERROR_INVALIDDATA;
1070 goto fail;
1071 }
1072
1073 if (!memcmp(in_data, "CWS", 3)) {
1074 /* Decompress the SWF player file using Zlib. */
1075 if (!(out_data = av_malloc(8))) {
1076 ret = AVERROR(ENOMEM);
1077 goto fail;
1078 }
1079 *in_data = 'F'; // magic stuff
1080 memcpy(out_data, in_data, 8);
1081 out_size = 8;
1082
1083#if CONFIG_ZLIB
1084 if ((ret = rtmp_uncompress_swfplayer(in_data + 8, in_size - 8,
1085 &out_data, &out_size)) < 0)
1086 goto fail;
1087#else
1088 av_log(s, AV_LOG_ERROR,
1089 "Zlib is required for decompressing the SWF player file.\n");
1090 ret = AVERROR(EINVAL);
1091 goto fail;
1092#endif
1093 swfsize = out_size;
1094 swfdata = out_data;
1095 } else {
1096 swfsize = in_size;
1097 swfdata = in_data;
1098 }
1099
1100 /* Compute the SHA256 hash of the SWF player file. */
1101 if ((ret = ff_rtmp_calc_digest(swfdata, swfsize, 0,
1102 "Genuine Adobe Flash Player 001", 30,
1103 swfhash)) < 0)
1104 goto fail;
1105
1106 /* Set SWFVerification parameters. */
1107 av_opt_set_bin(rt, "rtmp_swfhash", swfhash, 32, 0);
1108 rt->swfsize = swfsize;
1109
1110fail:
1111 av_freep(&in_data);
1112 av_freep(&out_data);
1113 ffurl_close(stream);
1114 return ret;
1115}
1116
9fd6b843 1117/**
49bd8e4b 1118 * Perform handshake with the server by means of exchanging pseudorandom data
9fd6b843
KS
1119 * signed with HMAC-SHA2 digest.
1120 *
1121 * @return 0 if handshake succeeds, negative value otherwise
1122 */
1123static int rtmp_handshake(URLContext *s, RTMPContext *rt)
1124{
1125 AVLFG rnd;
1126 uint8_t tosend [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
1127 3, // unencrypted data
1128 0, 0, 0, 0, // client uptime
1129 RTMP_CLIENT_VER1,
1130 RTMP_CLIENT_VER2,
1131 RTMP_CLIENT_VER3,
1132 RTMP_CLIENT_VER4,
1133 };
1134 uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
1135 uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
1136 int i;
1137 int server_pos, client_pos;
acd554c1 1138 uint8_t digest[32], signature[32];
acd554c1 1139 int ret, type = 0;
9fd6b843 1140
7f804085 1141 av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
9fd6b843
KS
1142
1143 av_lfg_init(&rnd, 0xDEADC0DE);
1144 // generate handshake packet - 1536 bytes of pseudorandom data
1145 for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
1146 tosend[i] = av_lfg_get(&rnd) >> 24;
acd554c1 1147
f7bfb126 1148 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1149 /* When the client wants to use RTMPE, we have to change the command
1150 * byte to 0x06 which means to use encrypted data and we have to set
1151 * the flash version to at least 9.0.115.0. */
1152 tosend[0] = 6;
1153 tosend[5] = 128;
1154 tosend[6] = 0;
1155 tosend[7] = 3;
1156 tosend[8] = 2;
1157
1158 /* Initialize the Diffie-Hellmann context and generate the public key
1159 * to send to the server. */
1160 if ((ret = ff_rtmpe_gen_pub_key(rt->stream, tosend + 1)) < 0)
1161 return ret;
1162 }
1163
f7bfb126 1164 client_pos = rtmp_handshake_imprint_with_digest(tosend + 1, rt->encrypted);
08e93f5b
SP
1165 if (client_pos < 0)
1166 return client_pos;
9fd6b843 1167
bba287fd
SP
1168 if ((ret = ffurl_write(rt->stream, tosend,
1169 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
1170 av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
1171 return ret;
1172 }
1173
177bcc95
SP
1174 if ((ret = ffurl_read_complete(rt->stream, serverdata,
1175 RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
7f804085 1176 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 1177 return ret;
9fd6b843 1178 }
177bcc95
SP
1179
1180 if ((ret = ffurl_read_complete(rt->stream, clientdata,
1181 RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
7f804085 1182 av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
177bcc95 1183 return ret;
9fd6b843
KS
1184 }
1185
acd554c1 1186 av_log(s, AV_LOG_DEBUG, "Type answer %d\n", serverdata[0]);
7f804085 1187 av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
9fd6b843
KS
1188 serverdata[5], serverdata[6], serverdata[7], serverdata[8]);
1189
e2ee11e8 1190 if (rt->is_input && serverdata[5] >= 3) {
c7240611 1191 server_pos = rtmp_validate_digest(serverdata + 1, 772);
08e93f5b
SP
1192 if (server_pos < 0)
1193 return server_pos;
1194
9fd6b843 1195 if (!server_pos) {
acd554c1 1196 type = 1;
c7240611 1197 server_pos = rtmp_validate_digest(serverdata + 1, 8);
08e93f5b
SP
1198 if (server_pos < 0)
1199 return server_pos;
1200
c7240611 1201 if (!server_pos) {
7f804085 1202 av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
a4d3f358 1203 return AVERROR(EIO);
c7240611 1204 }
9fd6b843 1205 }
9fd6b843 1206
635ac8e1
SP
1207 /* Generate SWFVerification token (SHA256 HMAC hash of decompressed SWF,
1208 * key are the last 32 bytes of the server handshake. */
1209 if (rt->swfsize) {
1210 if ((ret = rtmp_calc_swf_verification(s, rt, serverdata + 1 +
1211 RTMP_HANDSHAKE_PACKET_SIZE - 32)) < 0)
1212 return ret;
1213 }
1214
3505d557
SP
1215 ret = ff_rtmp_calc_digest(tosend + 1 + client_pos, 32, 0,
1216 rtmp_server_key, sizeof(rtmp_server_key),
1217 digest);
08e93f5b
SP
1218 if (ret < 0)
1219 return ret;
1220
3505d557 1221 ret = ff_rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32,
acd554c1 1222 0, digest, 32, signature);
08e93f5b
SP
1223 if (ret < 0)
1224 return ret;
1225
f7bfb126 1226 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1227 /* Compute the shared secret key sent by the server and initialize
1228 * the RC4 encryption. */
1229 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1230 tosend + 1, type)) < 0)
1231 return ret;
1232
1233 /* Encrypt the signature received by the server. */
1234 ff_rtmpe_encrypt_sig(rt->stream, signature, digest, serverdata[0]);
1235 }
1236
1237 if (memcmp(signature, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
7f804085 1238 av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
a4d3f358 1239 return AVERROR(EIO);
c7240611 1240 }
9fd6b843 1241
c7240611
KS
1242 for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
1243 tosend[i] = av_lfg_get(&rnd) >> 24;
3505d557
SP
1244 ret = ff_rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
1245 rtmp_player_key, sizeof(rtmp_player_key),
1246 digest);
08e93f5b
SP
1247 if (ret < 0)
1248 return ret;
1249
3505d557
SP
1250 ret = ff_rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
1251 digest, 32,
1252 tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
08e93f5b
SP
1253 if (ret < 0)
1254 return ret;
c7240611 1255
f7bfb126 1256 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1257 /* Encrypt the signature to be send to the server. */
1258 ff_rtmpe_encrypt_sig(rt->stream, tosend +
1259 RTMP_HANDSHAKE_PACKET_SIZE - 32, digest,
1260 serverdata[0]);
1261 }
1262
c7240611 1263 // write reply back to the server
bba287fd
SP
1264 if ((ret = ffurl_write(rt->stream, tosend,
1265 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1266 return ret;
acd554c1 1267
f7bfb126 1268 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1269 /* Set RC4 keys for encryption and update the keystreams. */
1270 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1271 return ret;
1272 }
6bf22e18 1273 } else {
f7bfb126 1274 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1275 /* Compute the shared secret key sent by the server and initialize
1276 * the RC4 encryption. */
1277 if ((ret = ff_rtmpe_compute_secret_key(rt->stream, serverdata + 1,
1278 tosend + 1, 1)) < 0)
1279 return ret;
1280
1281 if (serverdata[0] == 9) {
1282 /* Encrypt the signature received by the server. */
1283 ff_rtmpe_encrypt_sig(rt->stream, signature, digest,
1284 serverdata[0]);
1285 }
1286 }
1287
bba287fd
SP
1288 if ((ret = ffurl_write(rt->stream, serverdata + 1,
1289 RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
1290 return ret;
acd554c1 1291
f7bfb126 1292 if (rt->encrypted && CONFIG_FFRTMPCRYPT_PROTOCOL) {
acd554c1
SP
1293 /* Set RC4 keys for encryption and update the keystreams. */
1294 if ((ret = ff_rtmpe_update_keystream(rt->stream)) < 0)
1295 return ret;
1296 }
6bf22e18
S
1297 }
1298
9fd6b843
KS
1299 return 0;
1300}
1301
e5f2731c
JO
1302static int rtmp_receive_hs_packet(RTMPContext* rt, uint32_t *first_int,
1303 uint32_t *second_int, char *arraydata,
1304 int size)
1305{
cb5ab02a 1306 int inoutsize;
e5f2731c
JO
1307
1308 inoutsize = ffurl_read_complete(rt->stream, arraydata,
1309 RTMP_HANDSHAKE_PACKET_SIZE);
1310 if (inoutsize <= 0)
1311 return AVERROR(EIO);
1312 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1313 av_log(rt, AV_LOG_ERROR, "Erroneous Message size %d"
1314 " not following standard\n", (int)inoutsize);
1315 return AVERROR(EINVAL);
1316 }
1317
1318 *first_int = AV_RB32(arraydata);
1319 *second_int = AV_RB32(arraydata + 4);
1320 return 0;
1321}
1322
1323static int rtmp_send_hs_packet(RTMPContext* rt, uint32_t first_int,
1324 uint32_t second_int, char *arraydata, int size)
1325{
cb5ab02a 1326 int inoutsize;
e5f2731c
JO
1327
1328 AV_WB32(arraydata, first_int);
1329 AV_WB32(arraydata + 4, first_int);
1330 inoutsize = ffurl_write(rt->stream, arraydata,
1331 RTMP_HANDSHAKE_PACKET_SIZE);
1332 if (inoutsize != RTMP_HANDSHAKE_PACKET_SIZE) {
1333 av_log(rt, AV_LOG_ERROR, "Unable to write answer\n");
1334 return AVERROR(EIO);
1335 }
1336
1337 return 0;
1338}
1339
1340/**
1341 * rtmp handshake server side
1342 */
1343static int rtmp_server_handshake(URLContext *s, RTMPContext *rt)
1344{
1345 uint8_t buffer[RTMP_HANDSHAKE_PACKET_SIZE];
1346 uint32_t hs_epoch;
1347 uint32_t hs_my_epoch;
1348 uint8_t hs_c1[RTMP_HANDSHAKE_PACKET_SIZE];
1349 uint8_t hs_s1[RTMP_HANDSHAKE_PACKET_SIZE];
1350 uint32_t zeroes;
1351 uint32_t temp = 0;
1352 int randomidx = 0;
cb5ab02a 1353 int inoutsize = 0;
e5f2731c
JO
1354 int ret;
1355
1356 inoutsize = ffurl_read_complete(rt->stream, buffer, 1); // Receive C0
1357 if (inoutsize <= 0) {
1358 av_log(s, AV_LOG_ERROR, "Unable to read handshake\n");
1359 return AVERROR(EIO);
1360 }
1361 // Check Version
1362 if (buffer[0] != 3) {
1363 av_log(s, AV_LOG_ERROR, "RTMP protocol version mismatch\n");
1364 return AVERROR(EIO);
1365 }
1366 if (ffurl_write(rt->stream, buffer, 1) <= 0) { // Send S0
1367 av_log(s, AV_LOG_ERROR,
1368 "Unable to write answer - RTMP S0\n");
1369 return AVERROR(EIO);
1370 }
1371 /* Receive C1 */
1372 ret = rtmp_receive_hs_packet(rt, &hs_epoch, &zeroes, hs_c1,
1373 RTMP_HANDSHAKE_PACKET_SIZE);
1374 if (ret) {
1375 av_log(s, AV_LOG_ERROR, "RTMP Handshake C1 Error\n");
1376 return ret;
1377 }
1378 if (zeroes)
1379 av_log(s, AV_LOG_WARNING, "Erroneous C1 Message zero != 0\n");
1380 /* Send S1 */
1381 /* By now same epoch will be sent */
1382 hs_my_epoch = hs_epoch;
1383 /* Generate random */
2f1b2ff9 1384 for (randomidx = 8; randomidx < (RTMP_HANDSHAKE_PACKET_SIZE);
e5f2731c 1385 randomidx += 4)
2f1b2ff9 1386 AV_WB32(hs_s1 + randomidx, av_get_random_seed());
e5f2731c
JO
1387
1388 ret = rtmp_send_hs_packet(rt, hs_my_epoch, 0, hs_s1,
1389 RTMP_HANDSHAKE_PACKET_SIZE);
1390 if (ret) {
1391 av_log(s, AV_LOG_ERROR, "RTMP Handshake S1 Error\n");
1392 return ret;
1393 }
1394 /* Send S2 */
1395 ret = rtmp_send_hs_packet(rt, hs_epoch, 0, hs_c1,
1396 RTMP_HANDSHAKE_PACKET_SIZE);
1397 if (ret) {
1398 av_log(s, AV_LOG_ERROR, "RTMP Handshake S2 Error\n");
1399 return ret;
1400 }
1401 /* Receive C2 */
1402 ret = rtmp_receive_hs_packet(rt, &temp, &zeroes, buffer,
1403 RTMP_HANDSHAKE_PACKET_SIZE);
1404 if (ret) {
1405 av_log(s, AV_LOG_ERROR, "RTMP Handshake C2 Error\n");
1406 return ret;
1407 }
1408 if (temp != hs_my_epoch)
1409 av_log(s, AV_LOG_WARNING,
1410 "Erroneous C2 Message epoch does not match up with C1 epoch\n");
1411 if (memcmp(buffer + 8, hs_s1 + 8,
1412 RTMP_HANDSHAKE_PACKET_SIZE - 8))
1413 av_log(s, AV_LOG_WARNING,
1414 "Erroneous C2 Message random does not match up\n");
1415
1416 return 0;
1417}
1418
7be2a7d8
SP
1419static int handle_chunk_size(URLContext *s, RTMPPacket *pkt)
1420{
1421 RTMPContext *rt = s->priv_data;
1422 int ret;
1423
e49e6b64 1424 if (pkt->data_size < 4) {
7be2a7d8 1425 av_log(s, AV_LOG_ERROR,
e49e6b64 1426 "Too short chunk size change packet (%d)\n",
7be2a7d8 1427 pkt->data_size);
e7ea6883 1428 return AVERROR_INVALIDDATA;
7be2a7d8
SP
1429 }
1430
1431 if (!rt->is_input) {
f5ce90f2
JO
1432 /* Send the same chunk size change packet back to the server,
1433 * setting the outgoing chunk size to the same as the incoming one. */
1434 if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->out_chunk_size,
7be2a7d8
SP
1435 rt->prev_pkt[1])) < 0)
1436 return ret;
f5ce90f2 1437 rt->out_chunk_size = AV_RB32(pkt->data);
7be2a7d8
SP
1438 }
1439
f5ce90f2
JO
1440 rt->in_chunk_size = AV_RB32(pkt->data);
1441 if (rt->in_chunk_size <= 0) {
1442 av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n",
1443 rt->in_chunk_size);
e7ea6883 1444 return AVERROR_INVALIDDATA;
7be2a7d8 1445 }
f5ce90f2
JO
1446 av_log(s, AV_LOG_DEBUG, "New incoming chunk size = %d\n",
1447 rt->in_chunk_size);
7be2a7d8
SP
1448
1449 return 0;
1450}
1451
0ffd5161
SP
1452static int handle_ping(URLContext *s, RTMPPacket *pkt)
1453{
1454 RTMPContext *rt = s->priv_data;
1455 int t, ret;
1456
8ea1459b
SP
1457 if (pkt->data_size < 2) {
1458 av_log(s, AV_LOG_ERROR, "Too short ping packet (%d)\n",
1459 pkt->data_size);
1460 return AVERROR_INVALIDDATA;
1461 }
1462
0ffd5161
SP
1463 t = AV_RB16(pkt->data);
1464 if (t == 6) {
1465 if ((ret = gen_pong(s, rt, pkt)) < 0)
1466 return ret;
635ac8e1
SP
1467 } else if (t == 26) {
1468 if (rt->swfsize) {
1469 if ((ret = gen_swf_verification(s, rt)) < 0)
1470 return ret;
1471 } else {
1472 av_log(s, AV_LOG_WARNING, "Ignoring SWFVerification request.\n");
1473 }
0ffd5161
SP
1474 }
1475
1476 return 0;
1477}
1478
912ecc9a
SP
1479static int handle_client_bw(URLContext *s, RTMPPacket *pkt)
1480{
1481 RTMPContext *rt = s->priv_data;
1482
1483 if (pkt->data_size < 4) {
1484 av_log(s, AV_LOG_ERROR,
1485 "Client bandwidth report packet is less than 4 bytes long (%d)\n",
1486 pkt->data_size);
088a82bb 1487 return AVERROR_INVALIDDATA;
912ecc9a 1488 }
abf77a24
SP
1489
1490 rt->client_report_size = AV_RB32(pkt->data);
1491 if (rt->client_report_size <= 0) {
1492 av_log(s, AV_LOG_ERROR, "Incorrect client bandwidth %d\n",
1493 rt->client_report_size);
1494 return AVERROR_INVALIDDATA;
1495
1496 }
1497 av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", rt->client_report_size);
1498 rt->client_report_size >>= 1;
912ecc9a
SP
1499
1500 return 0;
1501}
1502
9b498148
SP
1503static int handle_server_bw(URLContext *s, RTMPPacket *pkt)
1504{
1505 RTMPContext *rt = s->priv_data;
1506
2357f606
SP
1507 if (pkt->data_size < 4) {
1508 av_log(s, AV_LOG_ERROR,
1509 "Too short server bandwidth report packet (%d)\n",
1510 pkt->data_size);
1511 return AVERROR_INVALIDDATA;
1512 }
1513
9b498148
SP
1514 rt->server_bw = AV_RB32(pkt->data);
1515 if (rt->server_bw <= 0) {
1516 av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n",
1517 rt->server_bw);
be8f9492 1518 return AVERROR_INVALIDDATA;
9b498148
SP
1519 }
1520 av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
1521
1522 return 0;
1523}
1524
08225d01
MS
1525static int do_adobe_auth(RTMPContext *rt, const char *user, const char *salt,
1526 const char *opaque, const char *challenge)
1527{
1528 uint8_t hash[16];
1529 char hashstr[AV_BASE64_SIZE(sizeof(hash))], challenge2[10];
1530 struct AVMD5 *md5 = av_md5_alloc();
1531 if (!md5)
1532 return AVERROR(ENOMEM);
1533
1534 snprintf(challenge2, sizeof(challenge2), "%08x", av_get_random_seed());
1535
1536 av_md5_init(md5);
1537 av_md5_update(md5, user, strlen(user));
1538 av_md5_update(md5, salt, strlen(salt));
1539 av_md5_update(md5, rt->password, strlen(rt->password));
1540 av_md5_final(md5, hash);
1541 av_base64_encode(hashstr, sizeof(hashstr), hash,
1542 sizeof(hash));
1543 av_md5_init(md5);
1544 av_md5_update(md5, hashstr, strlen(hashstr));
1545 if (opaque)
1546 av_md5_update(md5, opaque, strlen(opaque));
1547 else if (challenge)
1548 av_md5_update(md5, challenge, strlen(challenge));
1549 av_md5_update(md5, challenge2, strlen(challenge2));
1550 av_md5_final(md5, hash);
1551 av_base64_encode(hashstr, sizeof(hashstr), hash,
1552 sizeof(hash));
1553 snprintf(rt->auth_params, sizeof(rt->auth_params),
1554 "?authmod=%s&user=%s&challenge=%s&response=%s",
1555 "adobe", user, challenge2, hashstr);
1556 if (opaque)
1557 av_strlcatf(rt->auth_params, sizeof(rt->auth_params),
1558 "&opaque=%s", opaque);
1559
1560 av_free(md5);
1561 return 0;
1562}
1563
1564static int handle_connect_error(URLContext *s, const char *desc)
1565{
1566 RTMPContext *rt = s->priv_data;
1567 char buf[300], *ptr;
1568 int i = 0, ret = 0;
1569 const char *user = "", *salt = "", *opaque = NULL,
1570 *challenge = NULL, *cptr = NULL;
1571
1572 if (!(cptr = strstr(desc, "authmod=adobe"))) {
1573 av_log(s, AV_LOG_ERROR,
1574 "Unknown connect error (unsupported authentication method?)\n");
1575 return AVERROR_UNKNOWN;
1576 }
1577
1578 if (!rt->username[0] || !rt->password[0]) {
1579 av_log(s, AV_LOG_ERROR, "No credentials set\n");
1580 return AVERROR_UNKNOWN;
1581 }
1582
1583 if (strstr(desc, "?reason=authfailed")) {
1584 av_log(s, AV_LOG_ERROR, "Incorrect username/password\n");
1585 return AVERROR_UNKNOWN;
1586 } else if (strstr(desc, "?reason=nosuchuser")) {
1587 av_log(s, AV_LOG_ERROR, "Incorrect username\n");
1588 return AVERROR_UNKNOWN;
1589 }
1590
1591 if (rt->auth_tried) {
1592 av_log(s, AV_LOG_ERROR, "Authentication failed\n");
1593 return AVERROR_UNKNOWN;
1594 }
1595
1596 rt->auth_params[0] = '\0';
1597
1598 if (strstr(desc, "code=403 need auth")) {
1599 snprintf(rt->auth_params, sizeof(rt->auth_params),
1600 "?authmod=%s&user=%s", "adobe", rt->username);
1601 return 0;
1602 }
1603
1604 if (!(cptr = strstr(desc, "?reason=needauth"))) {
1605 av_log(s, AV_LOG_ERROR, "No auth parameters found\n");
1606 return AVERROR_UNKNOWN;
1607 }
1608
1609 av_strlcpy(buf, cptr + 1, sizeof(buf));
1610 ptr = buf;
1611
1612 while (ptr) {
1613 char *next = strchr(ptr, '&');
1614 char *value = strchr(ptr, '=');
1615 if (next)
1616 *next++ = '\0';
1617 if (value)
1618 *value++ = '\0';
1619 if (!strcmp(ptr, "user")) {
1620 user = value;
1621 } else if (!strcmp(ptr, "salt")) {
1622 salt = value;
1623 } else if (!strcmp(ptr, "opaque")) {
1624 opaque = value;
1625 } else if (!strcmp(ptr, "challenge")) {
1626 challenge = value;
1627 }
1628 ptr = next;
1629 }
1630
1631 if ((ret = do_adobe_auth(rt, user, salt, challenge, opaque)) < 0)
1632 return ret;
1633
1634 rt->auth_tried = 1;
1635 return 0;
1636}
1637
3eebc1e1
SP
1638static int handle_invoke_error(URLContext *s, RTMPPacket *pkt)
1639{
08225d01 1640 RTMPContext *rt = s->priv_data;
3eebc1e1 1641 const uint8_t *data_end = pkt->data + pkt->data_size;
fb7e7808
SP
1642 char *tracked_method = NULL;
1643 int level = AV_LOG_ERROR;
3eebc1e1 1644 uint8_t tmpstr[256];
fb7e7808
SP
1645 int ret;
1646
1647 if ((ret = find_tracked_method(s, pkt, 9, &tracked_method)) < 0)
1648 return ret;
3eebc1e1
SP
1649
1650 if (!ff_amf_get_field_value(pkt->data + 9, data_end,
1651 "description", tmpstr, sizeof(tmpstr))) {
7011a42b
SP
1652 if (tracked_method && (!strcmp(tracked_method, "_checkbw") ||
1653 !strcmp(tracked_method, "releaseStream") ||
1654 !strcmp(tracked_method, "FCSubscribe") ||
1655 !strcmp(tracked_method, "FCPublish"))) {
1656 /* Gracefully ignore Adobe-specific historical artifact errors. */
fb7e7808
SP
1657 level = AV_LOG_WARNING;
1658 ret = 0;
08225d01
MS
1659 } else if (tracked_method && !strcmp(tracked_method, "connect")) {
1660 ret = handle_connect_error(s, tmpstr);
1661 if (!ret) {
1662 rt->do_reconnect = 1;
1663 level = AV_LOG_VERBOSE;
1664 }
fb7e7808 1665 } else
c76daa89 1666 ret = AVERROR_UNKNOWN;
fb7e7808 1667 av_log(s, level, "Server error: %s\n", tmpstr);
3eebc1e1
SP
1668 }
1669
fb7e7808
SP
1670 av_free(tracked_method);
1671 return ret;
3eebc1e1
SP
1672}
1673
e5f2731c
JO
1674static int send_invoke_response(URLContext *s, RTMPPacket *pkt)
1675{
1676 RTMPContext *rt = s->priv_data;
1677 double seqnum;
1678 char filename[64];
1679 char command[64];
1680 char statusmsg[128];
1681 int stringlen;
1682 char *pchar;
1683 const uint8_t *p = pkt->data;
1684 uint8_t *pp = NULL;
1685 RTMPPacket spkt = { 0 };
1686 GetByteContext gbc;
1687 int ret;
1688
1689 bytestream2_init(&gbc, p, pkt->data_size);
1690 if (ff_amf_read_string(&gbc, command, sizeof(command),
1691 &stringlen)) {
1692 av_log(s, AV_LOG_ERROR, "Error in PT_INVOKE\n");
1693 return AVERROR_INVALIDDATA;
1694 }
1695
1696 ret = ff_amf_read_number(&gbc, &seqnum);
1697 if (ret)
1698 return ret;
1699 ret = ff_amf_read_null(&gbc);
1700 if (ret)
1701 return ret;
1702 if (!strcmp(command, "FCPublish") ||
1703 !strcmp(command, "publish")) {
1704 ret = ff_amf_read_string(&gbc, filename,
1705 sizeof(filename), &stringlen);
1706 // check with url
1707 if (s->filename) {
1708 pchar = strrchr(s->filename, '/');
1709 if (!pchar) {
1710 av_log(s, AV_LOG_WARNING,
1711 "Unable to find / in url %s, bad format\n",
1712 s->filename);
1713 pchar = s->filename;
1714 }
1715 pchar++;
1716 if (strcmp(pchar, filename))
1717 av_log(s, AV_LOG_WARNING, "Unexpected stream %s, expecting"
1718 " %s\n", filename, pchar);
1719 }
1720 rt->state = STATE_RECEIVING;
1721 }
1722
1723 if (!strcmp(command, "FCPublish")) {
1724 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1725 RTMP_PT_INVOKE, 0,
1726 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1727 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1728 return ret;
1729 }
1730 pp = spkt.data;
1731 ff_amf_write_string(&pp, "onFCPublish");
1732 } else if (!strcmp(command, "publish")) {
1733 PutByteContext pbc;
1734 // Send Stream Begin 1
1735 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_NETWORK_CHANNEL,
1736 RTMP_PT_PING, 0, 6)) < 0) {
1737 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1738 return ret;
1739 }
1740 pp = spkt.data;
1741 bytestream2_init_writer(&pbc, pp, spkt.data_size);
1742 bytestream2_put_be16(&pbc, 0); // 0 -> Stream Begin
1743 bytestream2_put_be32(&pbc, rt->nb_streamid);
1744 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1745 rt->prev_pkt[1]);
1746 ff_rtmp_packet_destroy(&spkt);
1747 if (ret < 0)
1748 return ret;
1749
1750 // Send onStatus(NetStream.Publish.Start)
1751 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1752 RTMP_PT_INVOKE, 0,
1753 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1754 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1755 return ret;
1756 }
1757 spkt.extra = pkt->extra;
1758 pp = spkt.data;
1759 ff_amf_write_string(&pp, "onStatus");
1760 ff_amf_write_number(&pp, 0);
1761 ff_amf_write_null(&pp);
1762
1763 ff_amf_write_object_start(&pp);
1764 ff_amf_write_field_name(&pp, "level");
1765 ff_amf_write_string(&pp, "status");
1766 ff_amf_write_field_name(&pp, "code");
1767 ff_amf_write_string(&pp, "NetStream.Publish.Start");
1768 ff_amf_write_field_name(&pp, "description");
1769 snprintf(statusmsg, sizeof(statusmsg),
1770 "%s is now published", filename);
1771 ff_amf_write_string(&pp, statusmsg);
1772 ff_amf_write_field_name(&pp, "details");
1773 ff_amf_write_string(&pp, filename);
1774 ff_amf_write_field_name(&pp, "clientid");
1775 snprintf(statusmsg, sizeof(statusmsg), "%s", LIBAVFORMAT_IDENT);
1776 ff_amf_write_string(&pp, statusmsg);
1777 ff_amf_write_object_end(&pp);
1778
1779 } else {
1780 if ((ret = ff_rtmp_packet_create(&spkt, RTMP_SYSTEM_CHANNEL,
1781 RTMP_PT_INVOKE, 0,
1782 RTMP_PKTDATA_DEFAULT_SIZE)) < 0) {
1783 av_log(s, AV_LOG_ERROR, "Unable to create response packet\n");
1784 return ret;
1785 }
1786 pp = spkt.data;
1787 ff_amf_write_string(&pp, "_result");
1788 ff_amf_write_number(&pp, seqnum);
1789 ff_amf_write_null(&pp);
1790 if (!strcmp(command, "createStream")) {
1791 rt->nb_streamid++;
1792 if (rt->nb_streamid == 0 || rt->nb_streamid == 2)
1793 rt->nb_streamid++; /* Values 0 and 2 are reserved */
1794 ff_amf_write_number(&pp, rt->nb_streamid);
1795 /* By now we don't control which streams are removed in
1796 * deleteStream. There is no stream creation control
1797 * if a client creates more than 2^32 - 2 streams. */
1798 }
1799 }
1800 spkt.data_size = pp - spkt.data;
1801 ret = ff_rtmp_packet_write(rt->stream, &spkt, rt->out_chunk_size,
1802 rt->prev_pkt[1]);
1803 ff_rtmp_packet_destroy(&spkt);
1804 return ret;
1805}
1806
5e6001db
SP
1807static int handle_invoke_result(URLContext *s, RTMPPacket *pkt)
1808{
1809 RTMPContext *rt = s->priv_data;
1810 char *tracked_method = NULL;
5e6001db 1811 int ret = 0;
5e6001db 1812
a8103503 1813 if ((ret = find_tracked_method(s, pkt, 10, &tracked_method)) < 0)
5e6001db
SP
1814 return ret;
1815
5e6001db
SP
1816 if (!tracked_method) {
1817 /* Ignore this reply when the current method is not tracked. */
1818 return ret;
1819 }
1820
1821 if (!memcmp(tracked_method, "connect", 7)) {
1822 if (!rt->is_input) {
1823 if ((ret = gen_release_stream(s, rt)) < 0)
1824 goto fail;
1825
1826 if ((ret = gen_fcpublish_stream(s, rt)) < 0)
1827 goto fail;
1828 } else {
1829 if ((ret = gen_server_bw(s, rt)) < 0)
1830 goto fail;
1831 }
1832
1833 if ((ret = gen_create_stream(s, rt)) < 0)
1834 goto fail;
1835
1836 if (rt->is_input) {
1837 /* Send the FCSubscribe command when the name of live
1838 * stream is defined by the user or if it's a live stream. */
1839 if (rt->subscribe) {
1840 if ((ret = gen_fcsubscribe_stream(s, rt, rt->subscribe)) < 0)
1841 goto fail;
1842 } else if (rt->live == -1) {
1843 if ((ret = gen_fcsubscribe_stream(s, rt, rt->playpath)) < 0)
1844 goto fail;
1845 }
1846 }
1847 } else if (!memcmp(tracked_method, "createStream", 12)) {
1848 //extract a number from the result
1849 if (pkt->data[10] || pkt->data[19] != 5 || pkt->data[20]) {
1850 av_log(s, AV_LOG_WARNING, "Unexpected reply on connect()\n");
1851 } else {
1852 rt->main_channel_id = av_int2double(AV_RB64(pkt->data + 21));
1853 }
1854
1855 if (!rt->is_input) {
1856 if ((ret = gen_publish(s, rt)) < 0)
1857 goto fail;
1858 } else {
1859 if ((ret = gen_play(s, rt)) < 0)
1860 goto fail;
1861 if ((ret = gen_buffer_time(s, rt)) < 0)
1862 goto fail;
1863 }
1864 }
1865
1866fail:
1867 av_free(tracked_method);
1868 return ret;
1869}
1870
71036a3a 1871static int handle_invoke_status(URLContext *s, RTMPPacket *pkt)
9fd6b843 1872{
6d1c9945 1873 RTMPContext *rt = s->priv_data;
71036a3a
SP
1874 const uint8_t *data_end = pkt->data + pkt->data_size;
1875 const uint8_t *ptr = pkt->data + 11;
1876 uint8_t tmpstr[256];
9fd6b843 1877 int i, t;
71036a3a
SP
1878
1879 for (i = 0; i < 2; i++) {
1880 t = ff_amf_tag_size(ptr, data_end);
1881 if (t < 0)
1882 return 1;
1883 ptr += t;
1884 }
1885
1886 t = ff_amf_get_field_value(ptr, data_end, "level", tmpstr, sizeof(tmpstr));
1887 if (!t && !strcmp(tmpstr, "error")) {
1888 if (!ff_amf_get_field_value(ptr, data_end,
1889 "description", tmpstr, sizeof(tmpstr)))
1890 av_log(s, AV_LOG_ERROR, "Server error: %s\n", tmpstr);
1891 return -1;
1892 }
1893
1894 t = ff_amf_get_field_value(ptr, data_end, "code", tmpstr, sizeof(tmpstr));
1895 if (!t && !strcmp(tmpstr, "NetStream.Play.Start")) rt->state = STATE_PLAYING;
1896 if (!t && !strcmp(tmpstr, "NetStream.Play.Stop")) rt->state = STATE_STOPPED;
1897 if (!t && !strcmp(tmpstr, "NetStream.Play.UnpublishNotify")) rt->state = STATE_STOPPED;
1898 if (!t && !strcmp(tmpstr, "NetStream.Publish.Start")) rt->state = STATE_PUBLISHING;
1899
1900 return 0;
1901}
1902
1903static int handle_invoke(URLContext *s, RTMPPacket *pkt)
1904{
1905 RTMPContext *rt = s->priv_data;
f89584ca 1906 int ret = 0;
9fd6b843 1907
6d1c9945
SP
1908 //TODO: check for the messages sent for wrong state?
1909 if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
3eebc1e1
SP
1910 if ((ret = handle_invoke_error(s, pkt)) < 0)
1911 return ret;
6d1c9945 1912 } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
5e6001db 1913 if ((ret = handle_invoke_result(s, pkt)) < 0)
f89584ca 1914 return ret;
6d1c9945 1915 } else if (!memcmp(pkt->data, "\002\000\010onStatus", 11)) {
71036a3a
SP
1916 if ((ret = handle_invoke_status(s, pkt)) < 0)
1917 return ret;
6d1c9945
SP
1918 } else if (!memcmp(pkt->data, "\002\000\010onBWDone", 11)) {
1919 if ((ret = gen_check_bw(s, rt)) < 0)
1920 return ret;
e5f2731c
JO
1921 } else if (!memcmp(pkt->data, "\002\000\015releaseStream", 16) ||
1922 !memcmp(pkt->data, "\002\000\011FCPublish", 12) ||
1923 !memcmp(pkt->data, "\002\000\007publish", 10) ||
1924 !memcmp(pkt->data, "\002\000\010_checkbw", 11) ||
1925 !memcmp(pkt->data, "\002\000\014createStream", 15)) {
1926 if (ret = send_invoke_response(s, pkt) < 0)
1927 return ret;
6d1c9945
SP
1928 }
1929
f89584ca 1930 return ret;
6d1c9945
SP
1931}
1932
e5f2731c
JO
1933static int handle_notify(URLContext *s, RTMPPacket *pkt) {
1934 RTMPContext *rt = s->priv_data;
1935 const uint8_t *p = NULL;
1936 uint8_t *cp = NULL;
1937 uint8_t commandbuffer[64];
1938 char statusmsg[128];
1939 int stringlen;
1940 GetByteContext gbc;
1941 PutByteContext pbc;
1942 uint32_t ts;
1943 int old_flv_size;
1944 const uint8_t *datatowrite;
1945 unsigned datatowritelength;
1946
1947 p = pkt->data;
1948 bytestream2_init(&gbc, p, pkt->data_size);
1949 if (ff_amf_read_string(&gbc, commandbuffer, sizeof(commandbuffer),
1950 &stringlen))
1951 return AVERROR_INVALIDDATA;
1952 if (!strcmp(commandbuffer, "@setDataFrame")) {
1953 datatowrite = gbc.buffer;
1954 datatowritelength = bytestream2_get_bytes_left(&gbc);
1955 if (ff_amf_read_string(&gbc, statusmsg,
1956 sizeof(statusmsg), &stringlen))
1957 return AVERROR_INVALIDDATA;
1958 if (strcmp(statusmsg, "onMetaData")) {
1959 av_log(s, AV_LOG_INFO, "Expecting onMetadata but got %s\n",
1960 statusmsg);
1961 return 0;
1962 }
1963
1964 /* Provide ECMAArray to flv */
1965 ts = pkt->timestamp;
1966
1967 // generate packet header and put data into buffer for FLV demuxer
1968 if (rt->flv_off < rt->flv_size) {
1969 old_flv_size = rt->flv_size;
1970 rt->flv_size += datatowritelength + 15;
1971 } else {
1972 old_flv_size = 0;
1973 rt->flv_size = datatowritelength + 15;
1974 rt->flv_off = 0;
1975 }
1976
1977 cp = av_realloc(rt->flv_data, rt->flv_size);
1978 if (!cp)
1979 return AVERROR(ENOMEM);
1980 rt->flv_data = cp;
1981 bytestream2_init_writer(&pbc, cp, rt->flv_size);
1982 bytestream2_skip_p(&pbc, old_flv_size);
1983 bytestream2_put_byte(&pbc, pkt->type);
1984 bytestream2_put_be24(&pbc, datatowritelength);
1985 bytestream2_put_be24(&pbc, ts);
1986 bytestream2_put_byte(&pbc, ts >> 24);
1987 bytestream2_put_be24(&pbc, 0);
1988 bytestream2_put_buffer(&pbc, datatowrite, datatowritelength);
1989 bytestream2_put_be32(&pbc, 0);
1990 }
1991 return 0;
1992}
1993
6d1c9945
SP
1994/**
1995 * Parse received packet and possibly perform some action depending on
1996 * the packet contents.
1997 * @return 0 for no errors, negative values for serious errors which prevent
1998 * further communications, positive values for uncritical errors
1999 */
2000static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
2001{
2002 int ret;
2003
2004#ifdef DEBUG
2005 ff_rtmp_packet_dump(s, pkt);
2006#endif
2007
2008 switch (pkt->type) {
fb96c1c5
LB
2009 case RTMP_PT_BYTES_READ:
2010 av_dlog(s, "received bytes read report\n");
2011 break;
6d1c9945
SP
2012 case RTMP_PT_CHUNK_SIZE:
2013 if ((ret = handle_chunk_size(s, pkt)) < 0)
2014 return ret;
2015 break;
2016 case RTMP_PT_PING:
2017 if ((ret = handle_ping(s, pkt)) < 0)
2018 return ret;
2019 break;
2020 case RTMP_PT_CLIENT_BW:
2021 if ((ret = handle_client_bw(s, pkt)) < 0)
2022 return ret;
2023 break;
2024 case RTMP_PT_SERVER_BW:
2025 if ((ret = handle_server_bw(s, pkt)) < 0)
2026 return ret;
2027 break;
2028 case RTMP_PT_INVOKE:
2029 if ((ret = handle_invoke(s, pkt)) < 0)
2030 return ret;
9fd6b843 2031 break;
08e087cc
JO
2032 case RTMP_PT_VIDEO:
2033 case RTMP_PT_AUDIO:
9c9c21ea 2034 case RTMP_PT_METADATA:
e5f2731c 2035 case RTMP_PT_NOTIFY:
9c9c21ea 2036 /* Audio, Video and Metadata packets are parsed in get_packet() */
08e087cc 2037 break;
9ff930aa
SP
2038 default:
2039 av_log(s, AV_LOG_VERBOSE, "Unknown packet type received 0x%02X\n", pkt->type);
2040 break;
9fd6b843
KS
2041 }
2042 return 0;
2043}
2044
2045/**
49bd8e4b 2046 * Interact with the server by receiving and sending RTMP packets until
9fd6b843
KS
2047 * there is some significant data (media data or expected status notification).
2048 *
2049 * @param s reading context
1d8041b3
SS
2050 * @param for_header non-zero value tells function to work until it
2051 * gets notification from the server that playing has been started,
2052 * otherwise function will work until some media data is received (or
2053 * an error happens)
9fd6b843
KS
2054 * @return 0 for successful operation, negative value in case of error
2055 */
2056static int get_packet(URLContext *s, int for_header)
2057{
2058 RTMPContext *rt = s->priv_data;
2059 int ret;
56e29bf2
S
2060 uint8_t *p;
2061 const uint8_t *next;
2062 uint32_t data_size;
2063 uint32_t ts, cts, pts=0;
9fd6b843 2064
72b870b9
MS
2065 if (rt->state == STATE_STOPPED)
2066 return AVERROR_EOF;
2067
e07c92e4 2068 for (;;) {
271c869c 2069 RTMPPacket rpkt = { 0 };
9fd6b843 2070 if ((ret = ff_rtmp_packet_read(rt->stream, &rpkt,
f5ce90f2 2071 rt->in_chunk_size, rt->prev_pkt[0])) <= 0) {
b381a823 2072 if (ret == 0) {
9fd6b843
KS
2073 return AVERROR(EAGAIN);
2074 } else {
2075 return AVERROR(EIO);
2076 }
2077 }
bf7c1719
KS
2078 rt->bytes_read += ret;
2079 if (rt->bytes_read > rt->last_bytes_read + rt->client_report_size) {
7f804085 2080 av_log(s, AV_LOG_DEBUG, "Sending bytes read report\n");
f645f1d6
SP
2081 if ((ret = gen_bytes_read(s, rt, rpkt.timestamp + 1)) < 0)
2082 return ret;
bf7c1719
KS
2083 rt->last_bytes_read = rt->bytes_read;
2084 }
9fd6b843
KS
2085
2086 ret = rtmp_parse_result(s, rt, &rpkt);
2087 if (ret < 0) {//serious error in current packet
2088 ff_rtmp_packet_destroy(&rpkt);
f645f1d6 2089 return ret;
9fd6b843 2090 }
08225d01
MS
2091 if (rt->do_reconnect && for_header) {
2092 ff_rtmp_packet_destroy(&rpkt);
2093 return 0;
2094 }
72b870b9
MS
2095 if (rt->state == STATE_STOPPED) {
2096 ff_rtmp_packet_destroy(&rpkt);
2097 return AVERROR_EOF;
2098 }
e5f2731c
JO
2099 if (for_header && (rt->state == STATE_PLAYING ||
2100 rt->state == STATE_PUBLISHING ||
2101 rt->state == STATE_RECEIVING)) {
9fd6b843
KS
2102 ff_rtmp_packet_destroy(&rpkt);
2103 return 0;
2104 }
6bf22e18 2105 if (!rpkt.data_size || !rt->is_input) {
9fd6b843
KS
2106 ff_rtmp_packet_destroy(&rpkt);
2107 continue;
2108 }
2109 if (rpkt.type == RTMP_PT_VIDEO || rpkt.type == RTMP_PT_AUDIO ||
afbacb93 2110 (rpkt.type == RTMP_PT_NOTIFY && !memcmp("\002\000\012onMetaData", rpkt.data, 13))) {
56e29bf2 2111 ts = rpkt.timestamp;
9fd6b843 2112
9fd6b843
KS
2113 // generate packet header and put data into buffer for FLV demuxer
2114 rt->flv_off = 0;
2115 rt->flv_size = rpkt.data_size + 15;
2116 rt->flv_data = p = av_realloc(rt->flv_data, rt->flv_size);
2117 bytestream_put_byte(&p, rpkt.type);
2118 bytestream_put_be24(&p, rpkt.data_size);
2119 bytestream_put_be24(&p, ts);
2120 bytestream_put_byte(&p, ts >> 24);
2121 bytestream_put_be24(&p, 0);
2122 bytestream_put_buffer(&p, rpkt.data, rpkt.data_size);
2123 bytestream_put_be32(&p, 0);
2124 ff_rtmp_packet_destroy(&rpkt);
2125 return 0;
e5f2731c
JO
2126 } else if (rpkt.type == RTMP_PT_NOTIFY) {
2127 ret = handle_notify(s, &rpkt);
2128 ff_rtmp_packet_destroy(&rpkt);
2129 if (ret) {
2130 av_log(s, AV_LOG_ERROR, "Handle notify error\n");
2131 return ret;
2132 }
2133 return 0;
9fd6b843
KS
2134 } else if (rpkt.type == RTMP_PT_METADATA) {
2135 // we got raw FLV data, make it available for FLV demuxer
2136 rt->flv_off = 0;
2137 rt->flv_size = rpkt.data_size;
2138 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
56e29bf2
S
2139 /* rewrite timestamps */
2140 next = rpkt.data;
2141 ts = rpkt.timestamp;
2142 while (next - rpkt.data < rpkt.data_size - 11) {
2143 next++;
2144 data_size = bytestream_get_be24(&next);
2145 p=next;
2146 cts = bytestream_get_be24(&next);
aae9a093 2147 cts |= bytestream_get_byte(&next) << 24;
56e29bf2
S
2148 if (pts==0)
2149 pts=cts;
2150 ts += cts - pts;
2151 pts = cts;
2152 bytestream_put_be24(&p, ts);
2153 bytestream_put_byte(&p, ts >> 24);
2154 next += data_size + 3 + 4;
2155 }
9fd6b843
KS
2156 memcpy(rt->flv_data, rpkt.data, rpkt.data_size);
2157 ff_rtmp_packet_destroy(&rpkt);
2158 return 0;
2159 }
2160 ff_rtmp_packet_destroy(&rpkt);
2161 }
9fd6b843
KS
2162}
2163
2164static int rtmp_close(URLContext *h)
2165{
2166 RTMPContext *rt = h->priv_data;
f645f1d6 2167 int ret = 0;
9fd6b843 2168
e07c92e4 2169 if (!rt->is_input) {
6bf22e18
S
2170 rt->flv_data = NULL;
2171 if (rt->out_pkt.data_size)
2172 ff_rtmp_packet_destroy(&rt->out_pkt);
615c2879 2173 if (rt->state > STATE_FCPUBLISH)
f645f1d6 2174 ret = gen_fcunpublish_stream(h, rt);
6bf22e18 2175 }
615c2879 2176 if (rt->state > STATE_HANDSHAKED)
f645f1d6 2177 ret = gen_delete_stream(h, rt);
6bf22e18 2178
f89584ca 2179 free_tracked_methods(rt);
9fd6b843 2180 av_freep(&rt->flv_data);
e52a9145 2181 ffurl_close(rt->stream);
f645f1d6 2182 return ret;
9fd6b843
KS
2183}
2184
2185/**
49bd8e4b 2186 * Open RTMP connection and verify that the stream can be played.
9fd6b843
KS
2187 *
2188 * URL syntax: rtmp://server[:port][/app][/playpath]
2189 * where 'app' is first one or two directories in the path
2190 * (e.g. /ondemand/, /flash/live/, etc.)
2191 * and 'playpath' is a file name (the rest of the path,
2192 * may be prefixed with "mp4:")
2193 */
2194static int rtmp_open(URLContext *s, const char *uri, int flags)
2195{
7e580505 2196 RTMPContext *rt = s->priv_data;
08225d01 2197 char proto[8], hostname[256], path[1024], auth[100], *fname;
6465562e 2198 char *old_app;
9fd6b843 2199 uint8_t buf[2048];
b316991b 2200 int port;
86991ce2 2201 AVDictionary *opts = NULL;
9fd6b843
KS
2202 int ret;
2203
e5f2731c
JO
2204 if (rt->listen_timeout > 0)
2205 rt->listen = 1;
2206
59d96941 2207 rt->is_input = !(flags & AVIO_FLAG_WRITE);
9fd6b843 2208
08225d01
MS
2209 av_url_split(proto, sizeof(proto), auth, sizeof(auth),
2210 hostname, sizeof(hostname), &port,
f984dcf6 2211 path, sizeof(path), s->filename);
9fd6b843 2212
08225d01
MS
2213 if (auth[0]) {
2214 char *ptr = strchr(auth, ':');
2215 if (ptr) {
2216 *ptr = '\0';
2217 av_strlcpy(rt->username, auth, sizeof(rt->username));
2218 av_strlcpy(rt->password, ptr + 1, sizeof(rt->password));
2219 }
2220 }
2221
e5f2731c
JO
2222 if (rt->listen && strcmp(proto, "rtmp")) {
2223 av_log(s, AV_LOG_ERROR, "rtmp_listen not available for %s\n",
2224 proto);
2225 return AVERROR(EINVAL);
2226 }
86991ce2
SP
2227 if (!strcmp(proto, "rtmpt") || !strcmp(proto, "rtmpts")) {
2228 if (!strcmp(proto, "rtmpts"))
2229 av_dict_set(&opts, "ffrtmphttp_tls", "1", 1);
2230
8e50c57d 2231 /* open the http tunneling connection */
775c4d36 2232 ff_url_join(buf, sizeof(buf), "ffrtmphttp", NULL, hostname, port, NULL);
6aedabc9
SP
2233 } else if (!strcmp(proto, "rtmps")) {
2234 /* open the tls connection */
2235 if (port < 0)
2236 port = RTMPS_DEFAULT_PORT;
2237 ff_url_join(buf, sizeof(buf), "tls", NULL, hostname, port, NULL);
08cd95e8
SP
2238 } else if (!strcmp(proto, "rtmpe") || (!strcmp(proto, "rtmpte"))) {
2239 if (!strcmp(proto, "rtmpte"))
2240 av_dict_set(&opts, "ffrtmpcrypt_tunneling", "1", 1);
2241
acd554c1
SP
2242 /* open the encrypted connection */
2243 ff_url_join(buf, sizeof(buf), "ffrtmpcrypt", NULL, hostname, port, NULL);
2244 rt->encrypted = 1;
8e50c57d
SP
2245 } else {
2246 /* open the tcp connection */
2247 if (port < 0)
2248 port = RTMP_DEFAULT_PORT;
e5f2731c
JO
2249 if (rt->listen)
2250 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port,
2251 "?listen&listen_timeout=%d",
2252 rt->listen_timeout * 1000);
2253 else
2254 ff_url_join(buf, sizeof(buf), "tcp", NULL, hostname, port, NULL);
8e50c57d 2255 }
9fd6b843 2256
08225d01 2257reconnect:
f645f1d6 2258 if ((ret = ffurl_open(&rt->stream, buf, AVIO_FLAG_READ_WRITE,
86991ce2 2259 &s->interrupt_callback, &opts)) < 0) {
59d96941 2260 av_log(s , AV_LOG_ERROR, "Cannot open connection %s\n", buf);
9fd6b843 2261 goto fail;
fe523958 2262 }
9fd6b843 2263
93f257db
SP
2264 if (rt->swfverify) {
2265 if ((ret = rtmp_calc_swfhash(s)) < 0)
2266 goto fail;
2267 }
2268
c7240611 2269 rt->state = STATE_START;
e5f2731c
JO
2270 if (!rt->listen && (ret = rtmp_handshake(s, rt)) < 0)
2271 goto fail;
2272 if (rt->listen && (ret = rtmp_server_handshake(s, rt)) < 0)
02490bf3 2273 goto fail;
9fd6b843 2274
f5ce90f2
JO
2275 rt->out_chunk_size = 128;
2276 rt->in_chunk_size = 128; // Probably overwritten later
c7240611 2277 rt->state = STATE_HANDSHAKED;
6465562e
SP
2278
2279 // Keep the application name when it has been defined by the user.
2280 old_app = rt->app;
2281
2282 rt->app = av_malloc(APP_MAX_LENGTH);
2283 if (!rt->app) {
f645f1d6
SP
2284 ret = AVERROR(ENOMEM);
2285 goto fail;
6465562e
SP
2286 }
2287
c7240611
KS
2288 //extract "app" part from path
2289 if (!strncmp(path, "/ondemand/", 10)) {
2290 fname = path + 10;
2291 memcpy(rt->app, "ondemand", 9);
2292 } else {
4b7304e8
MS
2293 char *next = *path ? path + 1 : path;
2294 char *p = strchr(next, '/');
c7240611 2295 if (!p) {
4b7304e8 2296 fname = next;
c7240611 2297 rt->app[0] = '\0';
9fd6b843 2298 } else {
c6eeb9b7 2299 // make sure we do not mismatch a playpath for an application instance
c7240611
KS
2300 char *c = strchr(p + 1, ':');
2301 fname = strchr(p + 1, '/');
c6eeb9b7 2302 if (!fname || (c && c < fname)) {
c7240611
KS
2303 fname = p + 1;
2304 av_strlcpy(rt->app, path + 1, p - path);
9fd6b843 2305 } else {
c7240611
KS
2306 fname++;
2307 av_strlcpy(rt->app, path + 1, fname - path - 1);
9fd6b843
KS
2308 }
2309 }
c7240611 2310 }
6465562e
SP
2311
2312 if (old_app) {
2313 // The name of application has been defined by the user, override it.
2314 av_free(rt->app);
2315 rt->app = old_app;
2316 }
2317
b3b17512 2318 if (!rt->playpath) {
f862537d
SP
2319 int len = strlen(fname);
2320
b3b17512
SP
2321 rt->playpath = av_malloc(PLAYPATH_MAX_LENGTH);
2322 if (!rt->playpath) {
f645f1d6
SP
2323 ret = AVERROR(ENOMEM);
2324 goto fail;
b3b17512
SP
2325 }
2326
0a9a2257 2327 if (!strchr(fname, ':') && len >= 4 &&
f862537d
SP
2328 (!strcmp(fname + len - 4, ".f4v") ||
2329 !strcmp(fname + len - 4, ".mp4"))) {
b3b17512 2330 memcpy(rt->playpath, "mp4:", 5);
0a9a2257 2331 } else if (len >= 4 && !strcmp(fname + len - 4, ".flv")) {
f862537d 2332 fname[len - 4] = '\0';
b3b17512
SP
2333 } else {
2334 rt->playpath[0] = 0;
2335 }
d578f947 2336 av_strlcat(rt->playpath, fname, PLAYPATH_MAX_LENGTH);
c7240611 2337 }
9fd6b843 2338
55c9320e
SP
2339 if (!rt->tcurl) {
2340 rt->tcurl = av_malloc(TCURL_MAX_LENGTH);
08e93f5b
SP
2341 if (!rt->tcurl) {
2342 ret = AVERROR(ENOMEM);
2343 goto fail;
2344 }
55c9320e
SP
2345 ff_url_join(rt->tcurl, TCURL_MAX_LENGTH, proto, NULL, hostname,
2346 port, "/%s", rt->app);
2347 }
2348
e64673e4
SP
2349 if (!rt->flashver) {
2350 rt->flashver = av_malloc(FLASHVER_MAX_LENGTH);
08e93f5b
SP
2351 if (!rt->flashver) {
2352 ret = AVERROR(ENOMEM);
2353 goto fail;
2354 }
e64673e4
SP
2355 if (rt->is_input) {
2356 snprintf(rt->flashver, FLASHVER_MAX_LENGTH, "%s %d,%d,%d,%d",
2357 RTMP_CLIENT_PLATFORM, RTMP_CLIENT_VER1, RTMP_CLIENT_VER2,
2358 RTMP_CLIENT_VER3, RTMP_CLIENT_VER4);
2359 } else {
2360 snprintf(rt->flashver, FLASHVER_MAX_LENGTH,
2361 "FMLE/3.0 (compatible; %s)", LIBAVFORMAT_IDENT);
2362 }
2363 }
2364
bf7c1719
KS
2365 rt->client_report_size = 1048576;
2366 rt->bytes_read = 0;
2367 rt->last_bytes_read = 0;
c2d38bea 2368 rt->server_bw = 2500000;
bf7c1719 2369
7f804085 2370 av_log(s, AV_LOG_DEBUG, "Proto = %s, path = %s, app = %s, fname = %s\n",
c7240611 2371 proto, path, rt->app, rt->playpath);
e5f2731c
JO
2372 if (!rt->listen) {
2373 if ((ret = gen_connect(s, rt)) < 0)
2374 goto fail;
2375 } else {
2376 if (read_connect(s, s->priv_data) < 0)
2377 goto fail;
2378 rt->is_input = 1;
2379 }
9fd6b843 2380
c7240611
KS
2381 do {
2382 ret = get_packet(s, 1);
2383 } while (ret == EAGAIN);
2384 if (ret < 0)
2385 goto fail;
6bf22e18 2386
08225d01
MS
2387 if (rt->do_reconnect) {
2388 ffurl_close(rt->stream);
2389 rt->stream = NULL;
2390 rt->do_reconnect = 0;
2391 rt->nb_invokes = 0;
2392 memset(rt->prev_pkt, 0, sizeof(rt->prev_pkt));
2393 free_tracked_methods(rt);
2394 goto reconnect;
2395 }
2396
6bf22e18 2397 if (rt->is_input) {
9fd6b843
KS
2398 // generate FLV header for demuxer
2399 rt->flv_size = 13;
2400 rt->flv_data = av_realloc(rt->flv_data, rt->flv_size);
2401 rt->flv_off = 0;
2402 memcpy(rt->flv_data, "FLV\1\5\0\0\0\011\0\0\0\0", rt->flv_size);
6bf22e18
S
2403 } else {
2404 rt->flv_size = 0;
2405 rt->flv_data = NULL;
2406 rt->flv_off = 0;
b14629e5 2407 rt->skip_bytes = 13;
9fd6b843
KS
2408 }
2409
5958df34 2410 s->max_packet_size = rt->stream->max_packet_size;
9fd6b843
KS
2411 s->is_streamed = 1;
2412 return 0;
2413
2414fail:
86991ce2 2415 av_dict_free(&opts);
9fd6b843 2416 rtmp_close(s);
f645f1d6 2417 return ret;
9fd6b843
KS
2418}
2419
2420static int rtmp_read(URLContext *s, uint8_t *buf, int size)
2421{
2422 RTMPContext *rt = s->priv_data;
2423 int orig_size = size;
2424 int ret;
2425
2426 while (size > 0) {
2427 int data_left = rt->flv_size - rt->flv_off;
2428
2429 if (data_left >= size) {
2430 memcpy(buf, rt->flv_data + rt->flv_off, size);
2431 rt->flv_off += size;
2432 return orig_size;
2433 }
2434 if (data_left > 0) {
2435 memcpy(buf, rt->flv_data + rt->flv_off, data_left);
2436 buf += data_left;
2437 size -= data_left;
2438 rt->flv_off = rt->flv_size;
e8ccf245 2439 return data_left;
9fd6b843
KS
2440 }
2441 if ((ret = get_packet(s, 0)) < 0)
2442 return ret;
2443 }
2444 return orig_size;
2445}
2446
9ad4c65f 2447static int rtmp_write(URLContext *s, const uint8_t *buf, int size)
9fd6b843 2448{
9ad4c65f 2449 RTMPContext *rt = s->priv_data;
6bf22e18
S
2450 int size_temp = size;
2451 int pktsize, pkttype;
2452 uint32_t ts;
2453 const uint8_t *buf_temp = buf;
7dc747f5 2454 uint8_t c;
f645f1d6 2455 int ret;
6bf22e18 2456
6bf22e18 2457 do {
b14629e5
MS
2458 if (rt->skip_bytes) {
2459 int skip = FFMIN(rt->skip_bytes, size_temp);
2460 buf_temp += skip;
2461 size_temp -= skip;
2462 rt->skip_bytes -= skip;
2463 continue;
2464 }
2465
2466 if (rt->flv_header_bytes < 11) {
2467 const uint8_t *header = rt->flv_header;
2468 int copy = FFMIN(11 - rt->flv_header_bytes, size_temp);
2469 bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy);
2470 rt->flv_header_bytes += copy;
2471 size_temp -= copy;
2472 if (rt->flv_header_bytes < 11)
2473 break;
6bf22e18 2474
b14629e5
MS
2475 pkttype = bytestream_get_byte(&header);
2476 pktsize = bytestream_get_be24(&header);
2477 ts = bytestream_get_be24(&header);
2478 ts |= bytestream_get_byte(&header) << 24;
2479 bytestream_get_be24(&header);
6bf22e18
S
2480 rt->flv_size = pktsize;
2481
2482 //force 12bytes header
2483 if (((pkttype == RTMP_PT_VIDEO || pkttype == RTMP_PT_AUDIO) && ts == 0) ||
2484 pkttype == RTMP_PT_NOTIFY) {
2485 if (pkttype == RTMP_PT_NOTIFY)
2486 pktsize += 16;
2487 rt->prev_pkt[1][RTMP_SOURCE_CHANNEL].channel_id = 0;
2488 }
2489
2490 //this can be a big packet, it's better to send it right here
f645f1d6
SP
2491 if ((ret = ff_rtmp_packet_create(&rt->out_pkt, RTMP_SOURCE_CHANNEL,
2492 pkttype, ts, pktsize)) < 0)
2493 return ret;
2494
6bf22e18
S
2495 rt->out_pkt.extra = rt->main_channel_id;
2496 rt->flv_data = rt->out_pkt.data;
2497
2498 if (pkttype == RTMP_PT_NOTIFY)
2499 ff_amf_write_string(&rt->flv_data, "@setDataFrame");
2500 }
2501
2502 if (rt->flv_size - rt->flv_off > size_temp) {
2503 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, size_temp);
2504 rt->flv_off += size_temp;
a14c7842 2505 size_temp = 0;
6bf22e18
S
2506 } else {
2507 bytestream_get_buffer(&buf_temp, rt->flv_data + rt->flv_off, rt->flv_size - rt->flv_off);
a14c7842 2508 size_temp -= rt->flv_size - rt->flv_off;
6bf22e18
S
2509 rt->flv_off += rt->flv_size - rt->flv_off;
2510 }
2511
2512 if (rt->flv_off == rt->flv_size) {
b14629e5
MS
2513 rt->skip_bytes = 4;
2514
f89584ca 2515 if ((ret = rtmp_send_packet(rt, &rt->out_pkt, 0)) < 0)
bba287fd 2516 return ret;
6bf22e18
S
2517 rt->flv_size = 0;
2518 rt->flv_off = 0;
b14629e5 2519 rt->flv_header_bytes = 0;
46743a85 2520 rt->flv_nb_packets++;
6bf22e18 2521 }
a14c7842 2522 } while (buf_temp - buf < size);
7dc747f5 2523
46743a85
SP
2524 if (rt->flv_nb_packets < rt->flush_interval)
2525 return size;
2526 rt->flv_nb_packets = 0;
2527
7dc747f5
SP
2528 /* set stream into nonblocking mode */
2529 rt->stream->flags |= AVIO_FLAG_NONBLOCK;
2530
2531 /* try to read one byte from the stream */
2532 ret = ffurl_read(rt->stream, &c, 1);
2533
2534 /* switch the stream back into blocking mode */
2535 rt->stream->flags &= ~AVIO_FLAG_NONBLOCK;
2536
2537 if (ret == AVERROR(EAGAIN)) {
2538 /* no incoming data to handle */
2539 return size;
2540 } else if (ret < 0) {
2541 return ret;
2542 } else if (ret == 1) {
2543 RTMPPacket rpkt = { 0 };
2544
2545 if ((ret = ff_rtmp_packet_read_internal(rt->stream, &rpkt,
f5ce90f2 2546 rt->in_chunk_size,
7dc747f5
SP
2547 rt->prev_pkt[0], c)) <= 0)
2548 return ret;
2549
2550 if ((ret = rtmp_parse_result(s, rt, &rpkt)) < 0)
2551 return ret;
2552
2553 ff_rtmp_packet_destroy(&rpkt);
2554 }
2555
6bf22e18 2556 return size;
9fd6b843
KS
2557}
2558
6465562e
SP
2559#define OFFSET(x) offsetof(RTMPContext, x)
2560#define DEC AV_OPT_FLAG_DECODING_PARAM
2561#define ENC AV_OPT_FLAG_ENCODING_PARAM
2562
2563static const AVOption rtmp_options[] = {
2564 {"rtmp_app", "Name of application to connect to on the RTMP server", OFFSET(app), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e6153f17 2565 {"rtmp_buffer", "Set buffer time in milliseconds. The default is 3000.", OFFSET(client_buffer_time), AV_OPT_TYPE_INT, {.i64 = 3000}, 0, INT_MAX, DEC|ENC},
8ee3e187 2566 {"rtmp_conn", "Append arbitrary AMF data to the Connect message", OFFSET(conn), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e64673e4 2567 {"rtmp_flashver", "Version of the Flash plugin used to run the SWF player.", OFFSET(flashver), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e6153f17
MS
2568 {"rtmp_flush_interval", "Number of packets flushed in the same request (RTMPT only).", OFFSET(flush_interval), AV_OPT_TYPE_INT, {.i64 = 10}, 0, INT_MAX, ENC},
2569 {"rtmp_live", "Specify that the media is a live stream.", OFFSET(live), AV_OPT_TYPE_INT, {.i64 = -2}, INT_MIN, INT_MAX, DEC, "rtmp_live"},
124134e4
MS
2570 {"any", "both", 0, AV_OPT_TYPE_CONST, {.i64 = -2}, 0, 0, DEC, "rtmp_live"},
2571 {"live", "live stream", 0, AV_OPT_TYPE_CONST, {.i64 = -1}, 0, 0, DEC, "rtmp_live"},
2572 {"recorded", "recorded stream", 0, AV_OPT_TYPE_CONST, {.i64 = 0}, 0, 0, DEC, "rtmp_live"},
758377a2 2573 {"rtmp_pageurl", "URL of the web page in which the media was embedded. By default no value will be sent.", OFFSET(pageurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
b3b17512 2574 {"rtmp_playpath", "Stream identifier to play or to publish", OFFSET(playpath), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
00cb52c6 2575 {"rtmp_subscribe", "Name of live stream to subscribe to. Defaults to rtmp_playpath.", OFFSET(subscribe), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
635ac8e1 2576 {"rtmp_swfhash", "SHA256 hash of the decompressed SWF file (32 bytes).", OFFSET(swfhash), AV_OPT_TYPE_BINARY, .flags = DEC},
e6153f17 2577 {"rtmp_swfsize", "Size of the decompressed SWF file, required for SWFVerification.", OFFSET(swfsize), AV_OPT_TYPE_INT, {.i64 = 0}, 0, INT_MAX, DEC},
05945db9 2578 {"rtmp_swfurl", "URL of the SWF player. By default no value will be sent", OFFSET(swfurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
93f257db 2579 {"rtmp_swfverify", "URL to player swf file, compute hash/size automatically.", OFFSET(swfverify), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC},
63ffa154 2580 {"rtmp_tcurl", "URL of the target stream. Defaults to proto://host[:port]/app.", OFFSET(tcurl), AV_OPT_TYPE_STRING, {.str = NULL }, 0, 0, DEC|ENC},
e6153f17
MS
2581 {"rtmp_listen", "Listen for incoming rtmp connections", OFFSET(listen), AV_OPT_TYPE_INT, {.i64 = 0}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
2582 {"timeout", "Maximum timeout (in seconds) to wait for incoming connections. -1 is infinite. Implies -rtmp_listen 1", OFFSET(listen_timeout), AV_OPT_TYPE_INT, {.i64 = -1}, INT_MIN, INT_MAX, DEC, "rtmp_listen" },
6465562e
SP
2583 { NULL },
2584};
2585
12127b65
SP
2586#define RTMP_PROTOCOL(flavor) \
2587static const AVClass flavor##_class = { \
2588 .class_name = #flavor, \
2589 .item_name = av_default_item_name, \
2590 .option = rtmp_options, \
2591 .version = LIBAVUTIL_VERSION_INT, \
2592}; \
2593 \
2594URLProtocol ff_##flavor##_protocol = { \
2595 .name = #flavor, \
2596 .url_open = rtmp_open, \
2597 .url_read = rtmp_read, \
2598 .url_write = rtmp_write, \
2599 .url_close = rtmp_close, \
2600 .priv_data_size = sizeof(RTMPContext), \
2601 .flags = URL_PROTOCOL_FLAG_NETWORK, \
2602 .priv_data_class= &flavor##_class, \
6465562e
SP
2603};
2604
08cd95e8 2605
12127b65
SP
2606RTMP_PROTOCOL(rtmp)
2607RTMP_PROTOCOL(rtmpe)
2608RTMP_PROTOCOL(rtmps)
2609RTMP_PROTOCOL(rtmpt)
2610RTMP_PROTOCOL(rtmpte)
2611RTMP_PROTOCOL(rtmpts)