xref: /third_party/curl/lib/curl_rtmp.c (revision 13498266)
113498266Sopenharmony_ci/***************************************************************************
213498266Sopenharmony_ci *                      _   _ ____  _
313498266Sopenharmony_ci *  Project         ___| | | |  _ \| |
413498266Sopenharmony_ci *                 / __| | | | |_) | |
513498266Sopenharmony_ci *                | (__| |_| |  _ <| |___
613498266Sopenharmony_ci *                 \___|\___/|_| \_\_____|
713498266Sopenharmony_ci *
813498266Sopenharmony_ci * Copyright (C) Daniel Stenberg, <daniel@haxx.se>, et al.
913498266Sopenharmony_ci * Copyright (C) Howard Chu, <hyc@highlandsun.com>
1013498266Sopenharmony_ci *
1113498266Sopenharmony_ci * This software is licensed as described in the file COPYING, which
1213498266Sopenharmony_ci * you should have received as part of this distribution. The terms
1313498266Sopenharmony_ci * are also available at https://curl.se/docs/copyright.html.
1413498266Sopenharmony_ci *
1513498266Sopenharmony_ci * You may opt to use, copy, modify, merge, publish, distribute and/or sell
1613498266Sopenharmony_ci * copies of the Software, and permit persons to whom the Software is
1713498266Sopenharmony_ci * furnished to do so, under the terms of the COPYING file.
1813498266Sopenharmony_ci *
1913498266Sopenharmony_ci * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
2013498266Sopenharmony_ci * KIND, either express or implied.
2113498266Sopenharmony_ci *
2213498266Sopenharmony_ci * SPDX-License-Identifier: curl
2313498266Sopenharmony_ci *
2413498266Sopenharmony_ci ***************************************************************************/
2513498266Sopenharmony_ci
2613498266Sopenharmony_ci#include "curl_setup.h"
2713498266Sopenharmony_ci
2813498266Sopenharmony_ci#ifdef USE_LIBRTMP
2913498266Sopenharmony_ci
3013498266Sopenharmony_ci#include "curl_rtmp.h"
3113498266Sopenharmony_ci#include "urldata.h"
3213498266Sopenharmony_ci#include "nonblock.h" /* for curlx_nonblock */
3313498266Sopenharmony_ci#include "progress.h" /* for Curl_pgrsSetUploadSize */
3413498266Sopenharmony_ci#include "transfer.h"
3513498266Sopenharmony_ci#include "warnless.h"
3613498266Sopenharmony_ci#include <curl/curl.h>
3713498266Sopenharmony_ci#include <librtmp/rtmp.h>
3813498266Sopenharmony_ci#include "curl_memory.h"
3913498266Sopenharmony_ci/* The last #include file should be: */
4013498266Sopenharmony_ci#include "memdebug.h"
4113498266Sopenharmony_ci
4213498266Sopenharmony_ci#if defined(_WIN32) && !defined(USE_LWIPSOCK)
4313498266Sopenharmony_ci#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
4413498266Sopenharmony_ci#define SET_RCVTIMEO(tv,s)   int tv = s*1000
4513498266Sopenharmony_ci#elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
4613498266Sopenharmony_ci#define SET_RCVTIMEO(tv,s)   int tv = s*1000
4713498266Sopenharmony_ci#else
4813498266Sopenharmony_ci#define SET_RCVTIMEO(tv,s)   struct timeval tv = {s,0}
4913498266Sopenharmony_ci#endif
5013498266Sopenharmony_ci
5113498266Sopenharmony_ci#define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
5213498266Sopenharmony_ci
5313498266Sopenharmony_cistatic CURLcode rtmp_setup_connection(struct Curl_easy *data,
5413498266Sopenharmony_ci                                      struct connectdata *conn);
5513498266Sopenharmony_cistatic CURLcode rtmp_do(struct Curl_easy *data, bool *done);
5613498266Sopenharmony_cistatic CURLcode rtmp_done(struct Curl_easy *data, CURLcode, bool premature);
5713498266Sopenharmony_cistatic CURLcode rtmp_connect(struct Curl_easy *data, bool *done);
5813498266Sopenharmony_cistatic CURLcode rtmp_disconnect(struct Curl_easy *data,
5913498266Sopenharmony_ci                                struct connectdata *conn, bool dead);
6013498266Sopenharmony_ci
6113498266Sopenharmony_cistatic Curl_recv rtmp_recv;
6213498266Sopenharmony_cistatic Curl_send rtmp_send;
6313498266Sopenharmony_ci
6413498266Sopenharmony_ci/*
6513498266Sopenharmony_ci * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
6613498266Sopenharmony_ci */
6713498266Sopenharmony_ci
6813498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmp = {
6913498266Sopenharmony_ci  "RTMP",                               /* scheme */
7013498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
7113498266Sopenharmony_ci  rtmp_do,                              /* do_it */
7213498266Sopenharmony_ci  rtmp_done,                            /* done */
7313498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
7413498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
7513498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
7613498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
7713498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
7813498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
7913498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
8013498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
8113498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
8213498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
8313498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
8413498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
8513498266Sopenharmony_ci  PORT_RTMP,                            /* defport */
8613498266Sopenharmony_ci  CURLPROTO_RTMP,                       /* protocol */
8713498266Sopenharmony_ci  CURLPROTO_RTMP,                       /* family */
8813498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
8913498266Sopenharmony_ci};
9013498266Sopenharmony_ci
9113498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmpt = {
9213498266Sopenharmony_ci  "RTMPT",                              /* scheme */
9313498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
9413498266Sopenharmony_ci  rtmp_do,                              /* do_it */
9513498266Sopenharmony_ci  rtmp_done,                            /* done */
9613498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
9713498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
9813498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
9913498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
10013498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
10113498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
10213498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
10313498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
10413498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
10513498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
10613498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
10713498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
10813498266Sopenharmony_ci  PORT_RTMPT,                           /* defport */
10913498266Sopenharmony_ci  CURLPROTO_RTMPT,                      /* protocol */
11013498266Sopenharmony_ci  CURLPROTO_RTMPT,                      /* family */
11113498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
11213498266Sopenharmony_ci};
11313498266Sopenharmony_ci
11413498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmpe = {
11513498266Sopenharmony_ci  "RTMPE",                              /* scheme */
11613498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
11713498266Sopenharmony_ci  rtmp_do,                              /* do_it */
11813498266Sopenharmony_ci  rtmp_done,                            /* done */
11913498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
12013498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
12113498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
12213498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
12313498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
12413498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
12513498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
12613498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
12713498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
12813498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
12913498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
13013498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
13113498266Sopenharmony_ci  PORT_RTMP,                            /* defport */
13213498266Sopenharmony_ci  CURLPROTO_RTMPE,                      /* protocol */
13313498266Sopenharmony_ci  CURLPROTO_RTMPE,                      /* family */
13413498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
13513498266Sopenharmony_ci};
13613498266Sopenharmony_ci
13713498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmpte = {
13813498266Sopenharmony_ci  "RTMPTE",                             /* scheme */
13913498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
14013498266Sopenharmony_ci  rtmp_do,                              /* do_it */
14113498266Sopenharmony_ci  rtmp_done,                            /* done */
14213498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
14313498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
14413498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
14513498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
14613498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
14713498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
14813498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
14913498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
15013498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
15113498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
15213498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
15313498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
15413498266Sopenharmony_ci  PORT_RTMPT,                           /* defport */
15513498266Sopenharmony_ci  CURLPROTO_RTMPTE,                     /* protocol */
15613498266Sopenharmony_ci  CURLPROTO_RTMPTE,                     /* family */
15713498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
15813498266Sopenharmony_ci};
15913498266Sopenharmony_ci
16013498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmps = {
16113498266Sopenharmony_ci  "RTMPS",                              /* scheme */
16213498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
16313498266Sopenharmony_ci  rtmp_do,                              /* do_it */
16413498266Sopenharmony_ci  rtmp_done,                            /* done */
16513498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
16613498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
16713498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
16813498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
16913498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
17013498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
17113498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
17213498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
17313498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
17413498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
17513498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
17613498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
17713498266Sopenharmony_ci  PORT_RTMPS,                           /* defport */
17813498266Sopenharmony_ci  CURLPROTO_RTMPS,                      /* protocol */
17913498266Sopenharmony_ci  CURLPROTO_RTMP,                       /* family */
18013498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
18113498266Sopenharmony_ci};
18213498266Sopenharmony_ci
18313498266Sopenharmony_ciconst struct Curl_handler Curl_handler_rtmpts = {
18413498266Sopenharmony_ci  "RTMPTS",                             /* scheme */
18513498266Sopenharmony_ci  rtmp_setup_connection,                /* setup_connection */
18613498266Sopenharmony_ci  rtmp_do,                              /* do_it */
18713498266Sopenharmony_ci  rtmp_done,                            /* done */
18813498266Sopenharmony_ci  ZERO_NULL,                            /* do_more */
18913498266Sopenharmony_ci  rtmp_connect,                         /* connect_it */
19013498266Sopenharmony_ci  ZERO_NULL,                            /* connecting */
19113498266Sopenharmony_ci  ZERO_NULL,                            /* doing */
19213498266Sopenharmony_ci  ZERO_NULL,                            /* proto_getsock */
19313498266Sopenharmony_ci  ZERO_NULL,                            /* doing_getsock */
19413498266Sopenharmony_ci  ZERO_NULL,                            /* domore_getsock */
19513498266Sopenharmony_ci  ZERO_NULL,                            /* perform_getsock */
19613498266Sopenharmony_ci  rtmp_disconnect,                      /* disconnect */
19713498266Sopenharmony_ci  ZERO_NULL,                            /* write_resp */
19813498266Sopenharmony_ci  ZERO_NULL,                            /* connection_check */
19913498266Sopenharmony_ci  ZERO_NULL,                            /* attach connection */
20013498266Sopenharmony_ci  PORT_RTMPS,                           /* defport */
20113498266Sopenharmony_ci  CURLPROTO_RTMPTS,                     /* protocol */
20213498266Sopenharmony_ci  CURLPROTO_RTMPT,                      /* family */
20313498266Sopenharmony_ci  PROTOPT_NONE                          /* flags */
20413498266Sopenharmony_ci};
20513498266Sopenharmony_ci
20613498266Sopenharmony_cistatic CURLcode rtmp_setup_connection(struct Curl_easy *data,
20713498266Sopenharmony_ci                                      struct connectdata *conn)
20813498266Sopenharmony_ci{
20913498266Sopenharmony_ci  RTMP *r = RTMP_Alloc();
21013498266Sopenharmony_ci  if(!r)
21113498266Sopenharmony_ci    return CURLE_OUT_OF_MEMORY;
21213498266Sopenharmony_ci
21313498266Sopenharmony_ci  RTMP_Init(r);
21413498266Sopenharmony_ci  RTMP_SetBufferMS(r, DEF_BUFTIME);
21513498266Sopenharmony_ci  if(!RTMP_SetupURL(r, data->state.url)) {
21613498266Sopenharmony_ci    RTMP_Free(r);
21713498266Sopenharmony_ci    return CURLE_URL_MALFORMAT;
21813498266Sopenharmony_ci  }
21913498266Sopenharmony_ci  conn->proto.rtmp = r;
22013498266Sopenharmony_ci  return CURLE_OK;
22113498266Sopenharmony_ci}
22213498266Sopenharmony_ci
22313498266Sopenharmony_cistatic CURLcode rtmp_connect(struct Curl_easy *data, bool *done)
22413498266Sopenharmony_ci{
22513498266Sopenharmony_ci  struct connectdata *conn = data->conn;
22613498266Sopenharmony_ci  RTMP *r = conn->proto.rtmp;
22713498266Sopenharmony_ci  SET_RCVTIMEO(tv, 10);
22813498266Sopenharmony_ci
22913498266Sopenharmony_ci  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
23013498266Sopenharmony_ci
23113498266Sopenharmony_ci  /* We have to know if it's a write before we send the
23213498266Sopenharmony_ci   * connect request packet
23313498266Sopenharmony_ci   */
23413498266Sopenharmony_ci  if(data->state.upload)
23513498266Sopenharmony_ci    r->Link.protocol |= RTMP_FEATURE_WRITE;
23613498266Sopenharmony_ci
23713498266Sopenharmony_ci  /* For plain streams, use the buffer toggle trick to keep data flowing */
23813498266Sopenharmony_ci  if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
23913498266Sopenharmony_ci     !(r->Link.protocol & RTMP_FEATURE_HTTP))
24013498266Sopenharmony_ci    r->Link.lFlags |= RTMP_LF_BUFX;
24113498266Sopenharmony_ci
24213498266Sopenharmony_ci  (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
24313498266Sopenharmony_ci  setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
24413498266Sopenharmony_ci             (char *)&tv, sizeof(tv));
24513498266Sopenharmony_ci
24613498266Sopenharmony_ci  if(!RTMP_Connect1(r, NULL))
24713498266Sopenharmony_ci    return CURLE_FAILED_INIT;
24813498266Sopenharmony_ci
24913498266Sopenharmony_ci  /* Clients must send a periodic BytesReceived report to the server */
25013498266Sopenharmony_ci  r->m_bSendCounter = true;
25113498266Sopenharmony_ci
25213498266Sopenharmony_ci  *done = TRUE;
25313498266Sopenharmony_ci  conn->recv[FIRSTSOCKET] = rtmp_recv;
25413498266Sopenharmony_ci  conn->send[FIRSTSOCKET] = rtmp_send;
25513498266Sopenharmony_ci  return CURLE_OK;
25613498266Sopenharmony_ci}
25713498266Sopenharmony_ci
25813498266Sopenharmony_cistatic CURLcode rtmp_do(struct Curl_easy *data, bool *done)
25913498266Sopenharmony_ci{
26013498266Sopenharmony_ci  struct connectdata *conn = data->conn;
26113498266Sopenharmony_ci  RTMP *r = conn->proto.rtmp;
26213498266Sopenharmony_ci
26313498266Sopenharmony_ci  if(!RTMP_ConnectStream(r, 0))
26413498266Sopenharmony_ci    return CURLE_FAILED_INIT;
26513498266Sopenharmony_ci
26613498266Sopenharmony_ci  if(data->state.upload) {
26713498266Sopenharmony_ci    Curl_pgrsSetUploadSize(data, data->state.infilesize);
26813498266Sopenharmony_ci    Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
26913498266Sopenharmony_ci  }
27013498266Sopenharmony_ci  else
27113498266Sopenharmony_ci    Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
27213498266Sopenharmony_ci  *done = TRUE;
27313498266Sopenharmony_ci  return CURLE_OK;
27413498266Sopenharmony_ci}
27513498266Sopenharmony_ci
27613498266Sopenharmony_cistatic CURLcode rtmp_done(struct Curl_easy *data, CURLcode status,
27713498266Sopenharmony_ci                          bool premature)
27813498266Sopenharmony_ci{
27913498266Sopenharmony_ci  (void)data; /* unused */
28013498266Sopenharmony_ci  (void)status; /* unused */
28113498266Sopenharmony_ci  (void)premature; /* unused */
28213498266Sopenharmony_ci
28313498266Sopenharmony_ci  return CURLE_OK;
28413498266Sopenharmony_ci}
28513498266Sopenharmony_ci
28613498266Sopenharmony_cistatic CURLcode rtmp_disconnect(struct Curl_easy *data,
28713498266Sopenharmony_ci                                struct connectdata *conn,
28813498266Sopenharmony_ci                                bool dead_connection)
28913498266Sopenharmony_ci{
29013498266Sopenharmony_ci  RTMP *r = conn->proto.rtmp;
29113498266Sopenharmony_ci  (void)data;
29213498266Sopenharmony_ci  (void)dead_connection;
29313498266Sopenharmony_ci  if(r) {
29413498266Sopenharmony_ci    conn->proto.rtmp = NULL;
29513498266Sopenharmony_ci    RTMP_Close(r);
29613498266Sopenharmony_ci    RTMP_Free(r);
29713498266Sopenharmony_ci  }
29813498266Sopenharmony_ci  return CURLE_OK;
29913498266Sopenharmony_ci}
30013498266Sopenharmony_ci
30113498266Sopenharmony_cistatic ssize_t rtmp_recv(struct Curl_easy *data, int sockindex, char *buf,
30213498266Sopenharmony_ci                         size_t len, CURLcode *err)
30313498266Sopenharmony_ci{
30413498266Sopenharmony_ci  struct connectdata *conn = data->conn;
30513498266Sopenharmony_ci  RTMP *r = conn->proto.rtmp;
30613498266Sopenharmony_ci  ssize_t nread;
30713498266Sopenharmony_ci
30813498266Sopenharmony_ci  (void)sockindex; /* unused */
30913498266Sopenharmony_ci
31013498266Sopenharmony_ci  nread = RTMP_Read(r, buf, curlx_uztosi(len));
31113498266Sopenharmony_ci  if(nread < 0) {
31213498266Sopenharmony_ci    if(r->m_read.status == RTMP_READ_COMPLETE ||
31313498266Sopenharmony_ci       r->m_read.status == RTMP_READ_EOF) {
31413498266Sopenharmony_ci      data->req.size = data->req.bytecount;
31513498266Sopenharmony_ci      nread = 0;
31613498266Sopenharmony_ci    }
31713498266Sopenharmony_ci    else
31813498266Sopenharmony_ci      *err = CURLE_RECV_ERROR;
31913498266Sopenharmony_ci  }
32013498266Sopenharmony_ci  return nread;
32113498266Sopenharmony_ci}
32213498266Sopenharmony_ci
32313498266Sopenharmony_cistatic ssize_t rtmp_send(struct Curl_easy *data, int sockindex,
32413498266Sopenharmony_ci                         const void *buf, size_t len, CURLcode *err)
32513498266Sopenharmony_ci{
32613498266Sopenharmony_ci  struct connectdata *conn = data->conn;
32713498266Sopenharmony_ci  RTMP *r = conn->proto.rtmp;
32813498266Sopenharmony_ci  ssize_t num;
32913498266Sopenharmony_ci
33013498266Sopenharmony_ci  (void)sockindex; /* unused */
33113498266Sopenharmony_ci
33213498266Sopenharmony_ci  num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
33313498266Sopenharmony_ci  if(num < 0)
33413498266Sopenharmony_ci    *err = CURLE_SEND_ERROR;
33513498266Sopenharmony_ci
33613498266Sopenharmony_ci  return num;
33713498266Sopenharmony_ci}
33813498266Sopenharmony_ci#endif  /* USE_LIBRTMP */
339