Annotation of embedaddon/curl/lib/curl_rtmp.c, revision 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>