rtmpproto.c 47.5 KB
Newer Older
1 2 3 4
/*
 * RTMP network protocol
 * Copyright (c) 2009 Kostya Shishkov
 *
5
 * This file is part of Libav.
6
 *
7
 * Libav is free software; you can redistribute it and/or
8 9 10 11
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
12
 * Libav is distributed in the hope that it will be useful,
13 14 15 16 17
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
18
 * License along with Libav; if not, write to the Free Software
19 20 21 22
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
 */

/**
23
 * @file
24 25 26 27 28
 * RTMP protocol
 */

#include "libavcodec/bytestream.h"
#include "libavutil/avstring.h"
29
#include "libavutil/intfloat.h"
30
#include "libavutil/lfg.h"
31
#include "libavutil/opt.h"
32 33
#include "libavutil/sha.h"
#include "avformat.h"
34
#include "internal.h"
35 36 37 38 39 40

#include "network.h"

#include "flv.h"
#include "rtmp.h"
#include "rtmppkt.h"
41
#include "url.h"
42

43 44
//#define DEBUG

45
#define APP_MAX_LENGTH 128
46
#define PLAYPATH_MAX_LENGTH 256
47
#define TCURL_MAX_LENGTH 512
48
#define FLASHVER_MAX_LENGTH 64
49

50 51 52 53
/** RTMP protocol handler state */
typedef enum {
    STATE_START,      ///< client has not done anything yet
    STATE_HANDSHAKED, ///< client has performed handshake
54 55
    STATE_RELEASING,  ///< client releasing stream before publish it (for output)
    STATE_FCPUBLISH,  ///< client FCPublishing stream (for output)
56 57 58
    STATE_CONNECTING, ///< client connected to server successfully
    STATE_READY,      ///< client has sent all needed commands and waits for server reply
    STATE_PLAYING,    ///< client has started receiving multimedia data from server
59
    STATE_PUBLISHING, ///< client has started sending multimedia data to server (for output)
60
    STATE_STOPPED,    ///< the broadcast has been stopped
61 62 63 64
} ClientState;

/** protocol handler context */
typedef struct RTMPContext {
65
    const AVClass *class;
66 67 68
    URLContext*   stream;                     ///< TCP stream used in interactions with RTMP server
    RTMPPacket    prev_pkt[2][RTMP_CHANNELS]; ///< packet history used when reading and sending packets
    int           chunk_size;                 ///< size of the chunks RTMP packets are divided into
69
    int           is_input;                   ///< input/output flag
70
    char          *playpath;                  ///< stream identifier to play (with possible "mp4:" prefix)
71
    int           live;                       ///< 0: recorded, -1: live, -2: both
72
    char          *app;                       ///< name of application
73
    char          *conn;                      ///< append arbitrary AMF data to the Connect message
74 75 76 77 78
    ClientState   state;                      ///< current state
    int           main_channel_id;            ///< an additional channel ID which is used for some invocations
    uint8_t*      flv_data;                   ///< buffer with data for demuxer
    int           flv_size;                   ///< current buffer size
    int           flv_off;                    ///< number of bytes read from current buffer
79
    RTMPPacket    out_pkt;                    ///< rtmp packet, created from flv a/v or metadata (for output)
80 81 82
    uint32_t      client_report_size;         ///< number of bytes after which client should report to server
    uint32_t      bytes_read;                 ///< number of bytes read from server
    uint32_t      last_bytes_read;            ///< number of bytes read last reported to server
83
    int           skip_bytes;                 ///< number of bytes to skip from the input FLV stream in the next write call
84 85
    uint8_t       flv_header[11];             ///< partial incoming flv packet header
    int           flv_header_bytes;           ///< number of initialized bytes in flv_header
86
    int           nb_invokes;                 ///< keeps track of invoke messages
87
    int           create_stream_invoke;       ///< invoke id for the create stream command
88
    char*         tcurl;                      ///< url of the target stream
89
    char*         flashver;                   ///< version of the flash plugin
90
    char*         swfurl;                     ///< url of the swf player
91
    int           server_bw;                  ///< server bandwidth
92
    int           client_buffer_time;         ///< client buffer time in ms
93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117
} RTMPContext;

#define PLAYER_KEY_OPEN_PART_LEN 30   ///< length of partial key used for first client digest signing
/** Client key used for digest signing */
static const uint8_t rtmp_player_key[] = {
    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
    'F', 'l', 'a', 's', 'h', ' ', 'P', 'l', 'a', 'y', 'e', 'r', ' ', '0', '0', '1',

    0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
    0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
    0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
};

#define SERVER_KEY_OPEN_PART_LEN 36   ///< length of partial key used for first server digest signing
/** Key used for RTMP server digest signing */
static const uint8_t rtmp_server_key[] = {
    'G', 'e', 'n', 'u', 'i', 'n', 'e', ' ', 'A', 'd', 'o', 'b', 'e', ' ',
    'F', 'l', 'a', 's', 'h', ' ', 'M', 'e', 'd', 'i', 'a', ' ',
    'S', 'e', 'r', 'v', 'e', 'r', ' ', '0', '0', '1',

    0xF0, 0xEE, 0xC2, 0x4A, 0x80, 0x68, 0xBE, 0xE8, 0x2E, 0x00, 0xD0, 0xD1, 0x02,
    0x9E, 0x7E, 0x57, 0x6E, 0xEC, 0x5D, 0x2D, 0x29, 0x80, 0x6F, 0xAB, 0x93, 0xB8,
    0xE6, 0x36, 0xCF, 0xEB, 0x31, 0xAE
};

118 119
static int rtmp_write_amf_data(URLContext *s, char *param, uint8_t **p)
{
120
    char *field, *value;
121 122 123 124 125 126 127 128 129 130 131 132 133 134
    char type;

    /* The type must be B for Boolean, N for number, S for string, O for
     * object, or Z for null. For Booleans the data must be either 0 or 1 for
     * FALSE or TRUE, respectively. Likewise for Objects the data must be
     * 0 or 1 to end or begin an object, respectively. Data items in subobjects
     * may be named, by prefixing the type with 'N' and specifying the name
     * before the value (ie. NB:myFlag:1). This option may be used multiple times
     * to construct arbitrary AMF sequences. */
    if (param[0] && param[1] == ':') {
        type = param[0];
        value = param + 2;
    } else if (param[0] == 'N' && param[1] && param[2] == ':') {
        type = param[1];
135 136 137 138 139 140
        field = param + 3;
        value = strchr(field, ':');
        if (!value)
            goto fail;
        *value = '\0';
        value++;
141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180

        if (!field || !value)
            goto fail;

        ff_amf_write_field_name(p, field);
    } else {
        goto fail;
    }

    switch (type) {
    case 'B':
        ff_amf_write_bool(p, value[0] != '0');
        break;
    case 'S':
        ff_amf_write_string(p, value);
        break;
    case 'N':
        ff_amf_write_number(p, strtod(value, NULL));
        break;
    case 'Z':
        ff_amf_write_null(p);
        break;
    case 'O':
        if (value[0] != '0')
            ff_amf_write_object_start(p);
        else
            ff_amf_write_object_end(p);
        break;
    default:
        goto fail;
        break;
    }

    return 0;

fail:
    av_log(s, AV_LOG_ERROR, "Invalid AMF parameter: %s\n", param);
    return AVERROR(EINVAL);
}

181
/**
182
 * Generate 'connect' call and send it to the server.
183
 */
184
static int gen_connect(URLContext *s, RTMPContext *rt)
185 186
{
    RTMPPacket pkt;
187
    uint8_t *p;
188 189 190 191 192
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 4096)) < 0)
        return ret;
193 194 195 196

    p = pkt.data;

    ff_amf_write_string(&p, "connect");
197
    ff_amf_write_number(&p, ++rt->nb_invokes);
198 199
    ff_amf_write_object_start(&p);
    ff_amf_write_field_name(&p, "app");
200
    ff_amf_write_string(&p, rt->app);
201

202
    if (!rt->is_input) {
203 204 205
        ff_amf_write_field_name(&p, "type");
        ff_amf_write_string(&p, "nonprivate");
    }
206
    ff_amf_write_field_name(&p, "flashVer");
207
    ff_amf_write_string(&p, rt->flashver);
208 209 210 211 212 213

    if (rt->swfurl) {
        ff_amf_write_field_name(&p, "swfUrl");
        ff_amf_write_string(&p, rt->swfurl);
    }

214
    ff_amf_write_field_name(&p, "tcUrl");
215
    ff_amf_write_string(&p, rt->tcurl);
216
    if (rt->is_input) {
217 218 219 220
        ff_amf_write_field_name(&p, "fpad");
        ff_amf_write_bool(&p, 0);
        ff_amf_write_field_name(&p, "capabilities");
        ff_amf_write_number(&p, 15.0);
221 222 223 224

        /* Tell the server we support all the audio codecs except
         * SUPPORT_SND_INTEL (0x0008) and SUPPORT_SND_UNUSED (0x0010)
         * which are unused in the RTMP protocol implementation. */
225
        ff_amf_write_field_name(&p, "audioCodecs");
226
        ff_amf_write_number(&p, 4071.0);
227 228 229 230
        ff_amf_write_field_name(&p, "videoCodecs");
        ff_amf_write_number(&p, 252.0);
        ff_amf_write_field_name(&p, "videoFunction");
        ff_amf_write_number(&p, 1.0);
231
    }
232 233
    ff_amf_write_object_end(&p);

234
    if (rt->conn) {
235
        char *param = rt->conn;
236 237 238

        // Write arbitrary AMF data to the Connect message.
        while (param != NULL) {
239 240 241 242 243 244 245
            char *sep;
            param += strspn(param, " ");
            if (!*param)
                break;
            sep = strchr(param, ' ');
            if (sep)
                *sep = '\0';
246 247 248 249 250 251
            if ((ret = rtmp_write_amf_data(s, param, &p)) < 0) {
                // Invalid AMF parameter.
                ff_rtmp_packet_destroy(&pkt);
                return ret;
            }

252 253 254 255
            if (sep)
                param = sep + 1;
            else
                break;
256 257 258
        }
    }

259 260
    pkt.data_size = p - pkt.data;

261 262
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
263
    ff_rtmp_packet_destroy(&pkt);
264

265
    return ret;
266 267
}

268
/**
269
 * Generate 'releaseStream' call and send it to the server. It should make
270 271
 * the server release some channel for media streams.
 */
272
static int gen_release_stream(URLContext *s, RTMPContext *rt)
273 274 275
{
    RTMPPacket pkt;
    uint8_t *p;
276
    int ret;
277

278 279 280
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 29 + strlen(rt->playpath))) < 0)
        return ret;
281

282
    av_log(s, AV_LOG_DEBUG, "Releasing stream...\n");
283 284
    p = pkt.data;
    ff_amf_write_string(&p, "releaseStream");
285
    ff_amf_write_number(&p, ++rt->nb_invokes);
286 287 288
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

289 290
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
291
    ff_rtmp_packet_destroy(&pkt);
292

293
    return ret;
294 295 296
}

/**
297
 * Generate 'FCPublish' call and send it to the server. It should make
298 299
 * the server preapare for receiving media streams.
 */
300
static int gen_fcpublish_stream(URLContext *s, RTMPContext *rt)
301 302 303
{
    RTMPPacket pkt;
    uint8_t *p;
304
    int ret;
305

306 307 308
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 25 + strlen(rt->playpath))) < 0)
        return ret;
309

310
    av_log(s, AV_LOG_DEBUG, "FCPublish stream...\n");
311 312
    p = pkt.data;
    ff_amf_write_string(&p, "FCPublish");
313
    ff_amf_write_number(&p, ++rt->nb_invokes);
314 315 316
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

317 318
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
319
    ff_rtmp_packet_destroy(&pkt);
320

321
    return ret;
322 323 324
}

/**
325
 * Generate 'FCUnpublish' call and send it to the server. It should make
326 327
 * the server destroy stream.
 */
328
static int gen_fcunpublish_stream(URLContext *s, RTMPContext *rt)
329 330 331
{
    RTMPPacket pkt;
    uint8_t *p;
332
    int ret;
333

334 335 336
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 27 + strlen(rt->playpath))) < 0)
        return ret;
337

338
    av_log(s, AV_LOG_DEBUG, "UnPublishing stream...\n");
339 340
    p = pkt.data;
    ff_amf_write_string(&p, "FCUnpublish");
341
    ff_amf_write_number(&p, ++rt->nb_invokes);
342 343 344
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);

345 346
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
347
    ff_rtmp_packet_destroy(&pkt);
348

349
    return ret;
350 351
}

352
/**
353
 * Generate 'createStream' call and send it to the server. It should make
354 355
 * the server allocate some channel for media streams.
 */
356
static int gen_create_stream(URLContext *s, RTMPContext *rt)
357 358 359
{
    RTMPPacket pkt;
    uint8_t *p;
360
    int ret;
361

362
    av_log(s, AV_LOG_DEBUG, "Creating stream...\n");
363 364 365 366

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 25)) < 0)
        return ret;
367 368 369

    p = pkt.data;
    ff_amf_write_string(&p, "createStream");
370
    ff_amf_write_number(&p, ++rt->nb_invokes);
371
    ff_amf_write_null(&p);
372
    rt->create_stream_invoke = rt->nb_invokes;
373

374 375
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
376
    ff_rtmp_packet_destroy(&pkt);
377

378
    return ret;
379 380 381 382
}


/**
383
 * Generate 'deleteStream' call and send it to the server. It should make
384 385
 * the server remove some channel for media streams.
 */
386
static int gen_delete_stream(URLContext *s, RTMPContext *rt)
387 388 389
{
    RTMPPacket pkt;
    uint8_t *p;
390
    int ret;
391

392
    av_log(s, AV_LOG_DEBUG, "Deleting stream...\n");
393 394 395 396

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 34)) < 0)
        return ret;
397 398 399

    p = pkt.data;
    ff_amf_write_string(&p, "deleteStream");
400
    ff_amf_write_number(&p, ++rt->nb_invokes);
401
    ff_amf_write_null(&p);
402
    ff_amf_write_number(&p, rt->main_channel_id);
403

404 405
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
406
    ff_rtmp_packet_destroy(&pkt);
407

408
    return ret;
409 410
}

411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435
/**
 * Generate client buffer time and send it to the server.
 */
static int gen_buffer_time(URLContext *s, RTMPContext *rt)
{
    RTMPPacket pkt;
    uint8_t *p;
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
                                     1, 10)) < 0)
        return ret;

    p = pkt.data;
    bytestream_put_be16(&p, 3);
    bytestream_put_be32(&p, rt->main_channel_id);
    bytestream_put_be32(&p, rt->client_buffer_time);

    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
    ff_rtmp_packet_destroy(&pkt);

    return ret;
}

436
/**
437
 * Generate 'play' call and send it to the server, then ping the server
438 439
 * to start actual playing.
 */
440
static int gen_play(URLContext *s, RTMPContext *rt)
441 442 443
{
    RTMPPacket pkt;
    uint8_t *p;
444
    int ret;
445

446
    av_log(s, AV_LOG_DEBUG, "Sending play command for '%s'\n", rt->playpath);
447 448 449 450 451

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_VIDEO_CHANNEL, RTMP_PT_INVOKE,
                                     0, 29 + strlen(rt->playpath))) < 0)
        return ret;

452 453 454 455
    pkt.extra = rt->main_channel_id;

    p = pkt.data;
    ff_amf_write_string(&p, "play");
456
    ff_amf_write_number(&p, ++rt->nb_invokes);
457 458
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);
459
    ff_amf_write_number(&p, rt->live);
460

461 462
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
463 464
    ff_rtmp_packet_destroy(&pkt);

465
    return ret;
466 467
}

468
/**
469
 * Generate 'publish' call and send it to the server.
470
 */
471
static int gen_publish(URLContext *s, RTMPContext *rt)
472 473 474
{
    RTMPPacket pkt;
    uint8_t *p;
475
    int ret;
476

477
    av_log(s, AV_LOG_DEBUG, "Sending publish command for '%s'\n", rt->playpath);
478 479 480 481 482

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SOURCE_CHANNEL, RTMP_PT_INVOKE,
                                     0, 30 + strlen(rt->playpath))) < 0)
        return ret;

483 484 485 486
    pkt.extra = rt->main_channel_id;

    p = pkt.data;
    ff_amf_write_string(&p, "publish");
487
    ff_amf_write_number(&p, ++rt->nb_invokes);
488 489 490 491
    ff_amf_write_null(&p);
    ff_amf_write_string(&p, rt->playpath);
    ff_amf_write_string(&p, "live");

492 493
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
494
    ff_rtmp_packet_destroy(&pkt);
495 496

    return ret;
497 498
}

499
/**
500
 * Generate ping reply and send it to the server.
501
 */
502
static int gen_pong(URLContext *s, RTMPContext *rt, RTMPPacket *ppkt)
503 504 505
{
    RTMPPacket pkt;
    uint8_t *p;
506 507 508 509 510
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_PING,
                                     ppkt->timestamp + 1, 6)) < 0)
        return ret;
511 512 513

    p = pkt.data;
    bytestream_put_be16(&p, 7);
514
    bytestream_put_be32(&p, AV_RB32(ppkt->data+2));
515 516
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
517
    ff_rtmp_packet_destroy(&pkt);
518

519
    return ret;
520 521
}

522 523 524
/**
 * Generate server bandwidth message and send it to the server.
 */
525
static int gen_server_bw(URLContext *s, RTMPContext *rt)
526 527 528
{
    RTMPPacket pkt;
    uint8_t *p;
529 530 531 532 533
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_SERVER_BW,
                                     0, 4)) < 0)
        return ret;
534 535

    p = pkt.data;
536
    bytestream_put_be32(&p, rt->server_bw);
537 538
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
539
    ff_rtmp_packet_destroy(&pkt);
540

541
    return ret;
542 543
}

544 545 546
/**
 * Generate check bandwidth message and send it to the server.
 */
547
static int gen_check_bw(URLContext *s, RTMPContext *rt)
548 549 550
{
    RTMPPacket pkt;
    uint8_t *p;
551
    int ret;
552

553 554 555
    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_SYSTEM_CHANNEL, RTMP_PT_INVOKE,
                                     0, 21)) < 0)
        return ret;
556 557 558 559 560 561

    p = pkt.data;
    ff_amf_write_string(&p, "_checkbw");
    ff_amf_write_number(&p, ++rt->nb_invokes);
    ff_amf_write_null(&p);

562 563
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
564
    ff_rtmp_packet_destroy(&pkt);
565 566

    return ret;
567 568
}

569
/**
570
 * Generate report on bytes read so far and send it to the server.
571
 */
572
static int gen_bytes_read(URLContext *s, RTMPContext *rt, uint32_t ts)
573 574 575
{
    RTMPPacket pkt;
    uint8_t *p;
576 577 578 579 580
    int ret;

    if ((ret = ff_rtmp_packet_create(&pkt, RTMP_NETWORK_CHANNEL, RTMP_PT_BYTES_READ,
                                     ts, 4)) < 0)
        return ret;
581 582 583

    p = pkt.data;
    bytestream_put_be32(&p, rt->bytes_read);
584 585
    ret = ff_rtmp_packet_write(rt->stream, &pkt, rt->chunk_size,
                               rt->prev_pkt[1]);
586
    ff_rtmp_packet_destroy(&pkt);
587

588
    return ret;
589 590
}

591 592 593 594 595
//TODO: Move HMAC code somewhere. Eventually.
#define HMAC_IPAD_VAL 0x36
#define HMAC_OPAD_VAL 0x5C

/**
596
 * Calculate HMAC-SHA2 digest for RTMP handshake packets.
597 598 599 600 601 602 603 604 605
 *
 * @param src    input buffer
 * @param len    input buffer length (should be 1536)
 * @param gap    offset in buffer where 32 bytes should not be taken into account
 *               when calculating digest (since it will be used to store that digest)
 * @param key    digest key
 * @param keylen digest key length
 * @param dst    buffer where calculated digest will be stored (32 bytes)
 */
Samuel Pitoiset's avatar
Samuel Pitoiset committed
606 607
static int rtmp_calc_digest(const uint8_t *src, int len, int gap,
                            const uint8_t *key, int keylen, uint8_t *dst)
608 609 610 611 612 613
{
    struct AVSHA *sha;
    uint8_t hmac_buf[64+32] = {0};
    int i;

    sha = av_mallocz(av_sha_size);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
614 615
    if (!sha)
        return AVERROR(ENOMEM);
616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643

    if (keylen < 64) {
        memcpy(hmac_buf, key, keylen);
    } else {
        av_sha_init(sha, 256);
        av_sha_update(sha,key, keylen);
        av_sha_final(sha, hmac_buf);
    }
    for (i = 0; i < 64; i++)
        hmac_buf[i] ^= HMAC_IPAD_VAL;

    av_sha_init(sha, 256);
    av_sha_update(sha, hmac_buf, 64);
    if (gap <= 0) {
        av_sha_update(sha, src, len);
    } else { //skip 32 bytes used for storing digest
        av_sha_update(sha, src, gap);
        av_sha_update(sha, src + gap + 32, len - gap - 32);
    }
    av_sha_final(sha, hmac_buf + 64);

    for (i = 0; i < 64; i++)
        hmac_buf[i] ^= HMAC_IPAD_VAL ^ HMAC_OPAD_VAL; //reuse XORed key for opad
    av_sha_init(sha, 256);
    av_sha_update(sha, hmac_buf, 64+32);
    av_sha_final(sha, dst);

    av_free(sha);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
644 645

    return 0;
646 647 648
}

/**
649
 * Put HMAC-SHA2 digest of packet data (except for the bytes where this digest
650 651 652 653 654 655 656 657
 * will be stored) into that packet.
 *
 * @param buf handshake data (1536 bytes)
 * @return offset to the digest inside input data
 */
static int rtmp_handshake_imprint_with_digest(uint8_t *buf)
{
    int i, digest_pos = 0;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
658
    int ret;
659 660 661 662 663

    for (i = 8; i < 12; i++)
        digest_pos += buf[i];
    digest_pos = (digest_pos % 728) + 12;

Samuel Pitoiset's avatar
Samuel Pitoiset committed
664 665 666 667 668 669
    ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
                           rtmp_player_key, PLAYER_KEY_OPEN_PART_LEN,
                           buf + digest_pos);
    if (ret < 0)
        return ret;

670 671 672 673
    return digest_pos;
}

/**
674
 * Verify that the received server response has the expected digest value.
675 676 677 678 679 680 681 682 683
 *
 * @param buf handshake data received from the server (1536 bytes)
 * @param off position to search digest offset from
 * @return 0 if digest is valid, digest position otherwise
 */
static int rtmp_validate_digest(uint8_t *buf, int off)
{
    int i, digest_pos = 0;
    uint8_t digest[32];
Samuel Pitoiset's avatar
Samuel Pitoiset committed
684
    int ret;
685 686 687 688 689

    for (i = 0; i < 4; i++)
        digest_pos += buf[i + off];
    digest_pos = (digest_pos % 728) + off + 4;

Samuel Pitoiset's avatar
Samuel Pitoiset committed
690 691 692 693 694 695
    ret = rtmp_calc_digest(buf, RTMP_HANDSHAKE_PACKET_SIZE, digest_pos,
                           rtmp_server_key, SERVER_KEY_OPEN_PART_LEN,
                           digest);
    if (ret < 0)
        return ret;

696 697 698 699 700 701
    if (!memcmp(digest, buf + digest_pos, 32))
        return digest_pos;
    return 0;
}

/**
702
 * Perform handshake with the server by means of exchanging pseudorandom data
703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722
 * signed with HMAC-SHA2 digest.
 *
 * @return 0 if handshake succeeds, negative value otherwise
 */
static int rtmp_handshake(URLContext *s, RTMPContext *rt)
{
    AVLFG rnd;
    uint8_t tosend    [RTMP_HANDSHAKE_PACKET_SIZE+1] = {
        3,                // unencrypted data
        0, 0, 0, 0,       // client uptime
        RTMP_CLIENT_VER1,
        RTMP_CLIENT_VER2,
        RTMP_CLIENT_VER3,
        RTMP_CLIENT_VER4,
    };
    uint8_t clientdata[RTMP_HANDSHAKE_PACKET_SIZE];
    uint8_t serverdata[RTMP_HANDSHAKE_PACKET_SIZE+1];
    int i;
    int server_pos, client_pos;
    uint8_t digest[32];
Samuel Pitoiset's avatar
Samuel Pitoiset committed
723
    int ret;
724

725
    av_log(s, AV_LOG_DEBUG, "Handshaking...\n");
726 727 728 729 730 731

    av_lfg_init(&rnd, 0xDEADC0DE);
    // generate handshake packet - 1536 bytes of pseudorandom data
    for (i = 9; i <= RTMP_HANDSHAKE_PACKET_SIZE; i++)
        tosend[i] = av_lfg_get(&rnd) >> 24;
    client_pos = rtmp_handshake_imprint_with_digest(tosend + 1);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
732 733
    if (client_pos < 0)
        return client_pos;
734

735 736 737 738 739 740
    if ((ret = ffurl_write(rt->stream, tosend,
                           RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
        av_log(s, AV_LOG_ERROR, "Cannot write RTMP handshake request\n");
        return ret;
    }

741 742
    if ((ret = ffurl_read_complete(rt->stream, serverdata,
                                   RTMP_HANDSHAKE_PACKET_SIZE + 1)) < 0) {
743
        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
744
        return ret;
745
    }
746 747 748

    if ((ret = ffurl_read_complete(rt->stream, clientdata,
                                   RTMP_HANDSHAKE_PACKET_SIZE)) < 0) {
749
        av_log(s, AV_LOG_ERROR, "Cannot read RTMP handshake response\n");
750
        return ret;
751 752
    }

753
    av_log(s, AV_LOG_DEBUG, "Server version %d.%d.%d.%d\n",
754 755
           serverdata[5], serverdata[6], serverdata[7], serverdata[8]);

756
    if (rt->is_input && serverdata[5] >= 3) {
757
        server_pos = rtmp_validate_digest(serverdata + 1, 772);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
758 759 760
        if (server_pos < 0)
            return server_pos;

761
        if (!server_pos) {
762
            server_pos = rtmp_validate_digest(serverdata + 1, 8);
Samuel Pitoiset's avatar
Samuel Pitoiset committed
763 764 765
            if (server_pos < 0)
                return server_pos;

766
            if (!server_pos) {
767
                av_log(s, AV_LOG_ERROR, "Server response validating failed\n");
768
                return AVERROR(EIO);
769
            }
770 771
        }

Samuel Pitoiset's avatar
Samuel Pitoiset committed
772 773 774 775 776 777 778 779 780 781
        ret = rtmp_calc_digest(tosend + 1 + client_pos, 32, 0, rtmp_server_key,
                               sizeof(rtmp_server_key), digest);
        if (ret < 0)
            return ret;

        ret = rtmp_calc_digest(clientdata, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
                               digest, 32, digest);
        if (ret < 0)
            return ret;

782
        if (memcmp(digest, clientdata + RTMP_HANDSHAKE_PACKET_SIZE - 32, 32)) {
783
            av_log(s, AV_LOG_ERROR, "Signature mismatch\n");
784
            return AVERROR(EIO);
785
        }
786

787 788
        for (i = 0; i < RTMP_HANDSHAKE_PACKET_SIZE; i++)
            tosend[i] = av_lfg_get(&rnd) >> 24;
Samuel Pitoiset's avatar
Samuel Pitoiset committed
789 790 791 792 793 794 795 796 797 798 799
        ret = rtmp_calc_digest(serverdata + 1 + server_pos, 32, 0,
                               rtmp_player_key, sizeof(rtmp_player_key),
                               digest);
        if (ret < 0)
            return ret;

        ret = rtmp_calc_digest(tosend, RTMP_HANDSHAKE_PACKET_SIZE - 32, 0,
                               digest, 32,
                               tosend + RTMP_HANDSHAKE_PACKET_SIZE - 32);
        if (ret < 0)
            return ret;
800 801

        // write reply back to the server
802 803 804
        if ((ret = ffurl_write(rt->stream, tosend,
                               RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
            return ret;
805
    } else {
806 807 808
        if ((ret = ffurl_write(rt->stream, serverdata + 1,
                               RTMP_HANDSHAKE_PACKET_SIZE)) < 0)
            return ret;
809 810
    }

811 812 813 814
    return 0;
}

/**
815
 * Parse received packet and possibly perform some action depending on
816 817 818 819 820 821 822 823
 * the packet contents.
 * @return 0 for no errors, negative values for serious errors which prevent
 *         further communications, positive values for uncritical errors
 */
static int rtmp_parse_result(URLContext *s, RTMPContext *rt, RTMPPacket *pkt)
{
    int i, t;
    const uint8_t *data_end = pkt->data + pkt->data_size;
824
    int ret;
825

826
#ifdef DEBUG
827
    ff_rtmp_packet_dump(s, pkt);
828 829
#endif

830 831 832
    switch (pkt->type) {
    case RTMP_PT_CHUNK_SIZE:
        if (pkt->data_size != 4) {
833
            av_log(s, AV_LOG_ERROR,
834 835 836
                   "Chunk size change packet is not 4 bytes long (%d)\n", pkt->data_size);
            return -1;
        }
837
        if (!rt->is_input)
838 839 840
            if ((ret = ff_rtmp_packet_write(rt->stream, pkt, rt->chunk_size,
                                            rt->prev_pkt[1])) < 0)
                return ret;
841 842
        rt->chunk_size = AV_RB32(pkt->data);
        if (rt->chunk_size <= 0) {
843
            av_log(s, AV_LOG_ERROR, "Incorrect chunk size %d\n", rt->chunk_size);
844 845
            return -1;
        }
846
        av_log(s, AV_LOG_DEBUG, "New chunk size = %d\n", rt->chunk_size);
847 848 849 850
        break;
    case RTMP_PT_PING:
        t = AV_RB16(pkt->data);
        if (t == 6)
851 852
            if ((ret = gen_pong(s, rt, pkt)) < 0)
                return ret;
853
        break;
854 855
    case RTMP_PT_CLIENT_BW:
        if (pkt->data_size < 4) {
856
            av_log(s, AV_LOG_ERROR,
857 858 859 860
                   "Client bandwidth report packet is less than 4 bytes long (%d)\n",
                   pkt->data_size);
            return -1;
        }
861
        av_log(s, AV_LOG_DEBUG, "Client bandwidth = %d\n", AV_RB32(pkt->data));
862 863
        rt->client_report_size = AV_RB32(pkt->data) >> 1;
        break;
864 865 866 867 868 869 870 871
    case RTMP_PT_SERVER_BW:
        rt->server_bw = AV_RB32(pkt->data);
        if (rt->server_bw <= 0) {
            av_log(s, AV_LOG_ERROR, "Incorrect server bandwidth %d\n", rt->server_bw);
            return AVERROR(EINVAL);
        }
        av_log(s, AV_LOG_DEBUG, "Server bandwidth = %d\n", rt->server_bw);
        break;
872 873 874 875 876 877 878
    case RTMP_PT_INVOKE:
        //TODO: check for the messages sent for wrong state?
        if (!memcmp(pkt->data, "\002\000\006_error", 9)) {
            uint8_t tmpstr[256];

            if (!ff_amf_get_field_value(pkt->data + 9, data_end,
                                        "description", tmpstr, sizeof(tmpstr)))
879
                av_log(s, AV_LOG_ERROR, "Server error: %s\n",tmpstr);
880 881 882 883
            return -1;
        } else if (!memcmp(pkt->data, "\002\000\007_result", 10)) {
            switch (rt->state) {
            case STATE_HANDSHAKED:
884
                if (!rt->is_input) {
885 886 887 888
                    if ((ret = gen_release_stream(s, rt)) < 0)
                        return ret;
                    if ((ret = gen_fcpublish_stream(s, rt)) < 0)
                        return ret;
889 890
                    rt->state = STATE_RELEASING;
                } else {
891 892
                    if ((ret = gen_server_bw(s, rt)) < 0)
                        return ret;
893 894
                    rt->state =