Annotation of embedaddon/curl/lib/curl_rtmp.c, revision 1.1.1.1

1.1       misho       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>