File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / curl_rtmp.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    1: /***************************************************************************
    2:  *                      _   _ ____  _
    3:  *  Project         ___| | | |  _ \| |
    4:  *                 / __| | | | |_) | |
    5:  *                | (__| |_| |  _ <| |___
    6:  *                 \___|\___/|_| \_\_____|
    7:  *
    8:  * Copyright (C) 2012 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
    9:  * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
   10:  *
   11:  * This software is licensed as described in the file COPYING, which
   12:  * you should have received as part of this distribution. The terms
   13:  * are also available at https://curl.haxx.se/docs/copyright.html.
   14:  *
   15:  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
   16:  * copies of the Software, and permit persons to whom the Software is
   17:  * furnished to do so, under the terms of the COPYING file.
   18:  *
   19:  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
   20:  * KIND, either express or implied.
   21:  *
   22:  ***************************************************************************/
   23: 
   24: #include "curl_setup.h"
   25: 
   26: #ifdef USE_LIBRTMP
   27: 
   28: #include "curl_rtmp.h"
   29: #include "urldata.h"
   30: #include "nonblock.h" /* for curlx_nonblock */
   31: #include "progress.h" /* for Curl_pgrsSetUploadSize */
   32: #include "transfer.h"
   33: #include "warnless.h"
   34: #include <curl/curl.h>
   35: #include <librtmp/rtmp.h>
   36: #include "curl_memory.h"
   37: /* The last #include file should be: */
   38: #include "memdebug.h"
   39: 
   40: #if defined(WIN32) && !defined(USE_LWIPSOCK)
   41: #define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
   42: #define SET_RCVTIMEO(tv,s)   int tv = s*1000
   43: #elif defined(LWIP_SO_SNDRCVTIMEO_NONSTANDARD)
   44: #define SET_RCVTIMEO(tv,s)   int tv = s*1000
   45: #else
   46: #define SET_RCVTIMEO(tv,s)   struct timeval tv = {s,0}
   47: #endif
   48: 
   49: #define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
   50: 
   51: static CURLcode rtmp_setup_connection(struct connectdata *conn);
   52: static CURLcode rtmp_do(struct connectdata *conn, bool *done);
   53: static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
   54: static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
   55: static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
   56: 
   57: static Curl_recv rtmp_recv;
   58: static Curl_send rtmp_send;
   59: 
   60: /*
   61:  * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
   62:  */
   63: 
   64: const struct Curl_handler Curl_handler_rtmp = {
   65:   "RTMP",                               /* scheme */
   66:   rtmp_setup_connection,                /* setup_connection */
   67:   rtmp_do,                              /* do_it */
   68:   rtmp_done,                            /* done */
   69:   ZERO_NULL,                            /* do_more */
   70:   rtmp_connect,                         /* connect_it */
   71:   ZERO_NULL,                            /* connecting */
   72:   ZERO_NULL,                            /* doing */
   73:   ZERO_NULL,                            /* proto_getsock */
   74:   ZERO_NULL,                            /* doing_getsock */
   75:   ZERO_NULL,                            /* domore_getsock */
   76:   ZERO_NULL,                            /* perform_getsock */
   77:   rtmp_disconnect,                      /* disconnect */
   78:   ZERO_NULL,                            /* readwrite */
   79:   ZERO_NULL,                            /* connection_check */
   80:   PORT_RTMP,                            /* defport */
   81:   CURLPROTO_RTMP,                       /* protocol */
   82:   PROTOPT_NONE                          /* flags*/
   83: };
   84: 
   85: const struct Curl_handler Curl_handler_rtmpt = {
   86:   "RTMPT",                              /* scheme */
   87:   rtmp_setup_connection,                /* setup_connection */
   88:   rtmp_do,                              /* do_it */
   89:   rtmp_done,                            /* done */
   90:   ZERO_NULL,                            /* do_more */
   91:   rtmp_connect,                         /* connect_it */
   92:   ZERO_NULL,                            /* connecting */
   93:   ZERO_NULL,                            /* doing */
   94:   ZERO_NULL,                            /* proto_getsock */
   95:   ZERO_NULL,                            /* doing_getsock */
   96:   ZERO_NULL,                            /* domore_getsock */
   97:   ZERO_NULL,                            /* perform_getsock */
   98:   rtmp_disconnect,                      /* disconnect */
   99:   ZERO_NULL,                            /* readwrite */
  100:   ZERO_NULL,                            /* connection_check */
  101:   PORT_RTMPT,                           /* defport */
  102:   CURLPROTO_RTMPT,                      /* protocol */
  103:   PROTOPT_NONE                          /* flags*/
  104: };
  105: 
  106: const struct Curl_handler Curl_handler_rtmpe = {
  107:   "RTMPE",                              /* scheme */
  108:   rtmp_setup_connection,                /* setup_connection */
  109:   rtmp_do,                              /* do_it */
  110:   rtmp_done,                            /* done */
  111:   ZERO_NULL,                            /* do_more */
  112:   rtmp_connect,                         /* connect_it */
  113:   ZERO_NULL,                            /* connecting */
  114:   ZERO_NULL,                            /* doing */
  115:   ZERO_NULL,                            /* proto_getsock */
  116:   ZERO_NULL,                            /* doing_getsock */
  117:   ZERO_NULL,                            /* domore_getsock */
  118:   ZERO_NULL,                            /* perform_getsock */
  119:   rtmp_disconnect,                      /* disconnect */
  120:   ZERO_NULL,                            /* readwrite */
  121:   ZERO_NULL,                            /* connection_check */
  122:   PORT_RTMP,                            /* defport */
  123:   CURLPROTO_RTMPE,                      /* protocol */
  124:   PROTOPT_NONE                          /* flags*/
  125: };
  126: 
  127: const struct Curl_handler Curl_handler_rtmpte = {
  128:   "RTMPTE",                             /* scheme */
  129:   rtmp_setup_connection,                /* setup_connection */
  130:   rtmp_do,                              /* do_it */
  131:   rtmp_done,                            /* done */
  132:   ZERO_NULL,                            /* do_more */
  133:   rtmp_connect,                         /* connect_it */
  134:   ZERO_NULL,                            /* connecting */
  135:   ZERO_NULL,                            /* doing */
  136:   ZERO_NULL,                            /* proto_getsock */
  137:   ZERO_NULL,                            /* doing_getsock */
  138:   ZERO_NULL,                            /* domore_getsock */
  139:   ZERO_NULL,                            /* perform_getsock */
  140:   rtmp_disconnect,                      /* disconnect */
  141:   ZERO_NULL,                            /* readwrite */
  142:   ZERO_NULL,                            /* connection_check */
  143:   PORT_RTMPT,                           /* defport */
  144:   CURLPROTO_RTMPTE,                     /* protocol */
  145:   PROTOPT_NONE                          /* flags*/
  146: };
  147: 
  148: const struct Curl_handler Curl_handler_rtmps = {
  149:   "RTMPS",                              /* scheme */
  150:   rtmp_setup_connection,                /* setup_connection */
  151:   rtmp_do,                              /* do_it */
  152:   rtmp_done,                            /* done */
  153:   ZERO_NULL,                            /* do_more */
  154:   rtmp_connect,                         /* connect_it */
  155:   ZERO_NULL,                            /* connecting */
  156:   ZERO_NULL,                            /* doing */
  157:   ZERO_NULL,                            /* proto_getsock */
  158:   ZERO_NULL,                            /* doing_getsock */
  159:   ZERO_NULL,                            /* domore_getsock */
  160:   ZERO_NULL,                            /* perform_getsock */
  161:   rtmp_disconnect,                      /* disconnect */
  162:   ZERO_NULL,                            /* readwrite */
  163:   ZERO_NULL,                            /* connection_check */
  164:   PORT_RTMPS,                           /* defport */
  165:   CURLPROTO_RTMPS,                      /* protocol */
  166:   PROTOPT_NONE                          /* flags*/
  167: };
  168: 
  169: const struct Curl_handler Curl_handler_rtmpts = {
  170:   "RTMPTS",                             /* scheme */
  171:   rtmp_setup_connection,                /* setup_connection */
  172:   rtmp_do,                              /* do_it */
  173:   rtmp_done,                            /* done */
  174:   ZERO_NULL,                            /* do_more */
  175:   rtmp_connect,                         /* connect_it */
  176:   ZERO_NULL,                            /* connecting */
  177:   ZERO_NULL,                            /* doing */
  178:   ZERO_NULL,                            /* proto_getsock */
  179:   ZERO_NULL,                            /* doing_getsock */
  180:   ZERO_NULL,                            /* domore_getsock */
  181:   ZERO_NULL,                            /* perform_getsock */
  182:   rtmp_disconnect,                      /* disconnect */
  183:   ZERO_NULL,                            /* readwrite */
  184:   ZERO_NULL,                            /* connection_check */
  185:   PORT_RTMPS,                           /* defport */
  186:   CURLPROTO_RTMPTS,                     /* protocol */
  187:   PROTOPT_NONE                          /* flags*/
  188: };
  189: 
  190: static CURLcode rtmp_setup_connection(struct connectdata *conn)
  191: {
  192:   RTMP *r = RTMP_Alloc();
  193:   if(!r)
  194:     return CURLE_OUT_OF_MEMORY;
  195: 
  196:   RTMP_Init(r);
  197:   RTMP_SetBufferMS(r, DEF_BUFTIME);
  198:   if(!RTMP_SetupURL(r, conn->data->change.url)) {
  199:     RTMP_Free(r);
  200:     return CURLE_URL_MALFORMAT;
  201:   }
  202:   conn->proto.rtmp = r;
  203:   return CURLE_OK;
  204: }
  205: 
  206: static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
  207: {
  208:   RTMP *r = conn->proto.rtmp;
  209:   SET_RCVTIMEO(tv, 10);
  210: 
  211:   r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
  212: 
  213:   /* We have to know if it's a write before we send the
  214:    * connect request packet
  215:    */
  216:   if(conn->data->set.upload)
  217:     r->Link.protocol |= RTMP_FEATURE_WRITE;
  218: 
  219:   /* For plain streams, use the buffer toggle trick to keep data flowing */
  220:   if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
  221:      !(r->Link.protocol & RTMP_FEATURE_HTTP))
  222:     r->Link.lFlags |= RTMP_LF_BUFX;
  223: 
  224:   (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
  225:   setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
  226:              (char *)&tv, sizeof(tv));
  227: 
  228:   if(!RTMP_Connect1(r, NULL))
  229:     return CURLE_FAILED_INIT;
  230: 
  231:   /* Clients must send a periodic BytesReceived report to the server */
  232:   r->m_bSendCounter = true;
  233: 
  234:   *done = TRUE;
  235:   conn->recv[FIRSTSOCKET] = rtmp_recv;
  236:   conn->send[FIRSTSOCKET] = rtmp_send;
  237:   return CURLE_OK;
  238: }
  239: 
  240: static CURLcode rtmp_do(struct connectdata *conn, bool *done)
  241: {
  242:   struct Curl_easy *data = conn->data;
  243:   RTMP *r = conn->proto.rtmp;
  244: 
  245:   if(!RTMP_ConnectStream(r, 0))
  246:     return CURLE_FAILED_INIT;
  247: 
  248:   if(conn->data->set.upload) {
  249:     Curl_pgrsSetUploadSize(data, data->state.infilesize);
  250:     Curl_setup_transfer(data, -1, -1, FALSE, FIRSTSOCKET);
  251:   }
  252:   else
  253:     Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
  254:   *done = TRUE;
  255:   return CURLE_OK;
  256: }
  257: 
  258: static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
  259:                           bool premature)
  260: {
  261:   (void)conn; /* unused */
  262:   (void)status; /* unused */
  263:   (void)premature; /* unused */
  264: 
  265:   return CURLE_OK;
  266: }
  267: 
  268: static CURLcode rtmp_disconnect(struct connectdata *conn,
  269:                                 bool dead_connection)
  270: {
  271:   RTMP *r = conn->proto.rtmp;
  272:   (void)dead_connection;
  273:   if(r) {
  274:     conn->proto.rtmp = NULL;
  275:     RTMP_Close(r);
  276:     RTMP_Free(r);
  277:   }
  278:   return CURLE_OK;
  279: }
  280: 
  281: static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
  282:                          size_t len, CURLcode *err)
  283: {
  284:   RTMP *r = conn->proto.rtmp;
  285:   ssize_t nread;
  286: 
  287:   (void)sockindex; /* unused */
  288: 
  289:   nread = RTMP_Read(r, buf, curlx_uztosi(len));
  290:   if(nread < 0) {
  291:     if(r->m_read.status == RTMP_READ_COMPLETE ||
  292:         r->m_read.status == RTMP_READ_EOF) {
  293:       conn->data->req.size = conn->data->req.bytecount;
  294:       nread = 0;
  295:     }
  296:     else
  297:       *err = CURLE_RECV_ERROR;
  298:   }
  299:   return nread;
  300: }
  301: 
  302: static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
  303:                          const void *buf, size_t len, CURLcode *err)
  304: {
  305:   RTMP *r = conn->proto.rtmp;
  306:   ssize_t num;
  307: 
  308:   (void)sockindex; /* unused */
  309: 
  310:   num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
  311:   if(num < 0)
  312:     *err = CURLE_SEND_ERROR;
  313: 
  314:   return num;
  315: }
  316: #endif  /* USE_LIBRTMP */

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>