curl_rtmp.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                      _   _ ____  _
00003  *  Project         ___| | | |  _ \| |
00004  *                 / __| | | | |_) | |
00005  *                | (__| |_| |  _ <| |___
00006  *                 \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 2012 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com>
00010  *
00011  * This software is licensed as described in the file COPYING, which
00012  * you should have received as part of this distribution. The terms
00013  * are also available at https://curl.haxx.se/docs/copyright.html.
00014  *
00015  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00016  * copies of the Software, and permit persons to whom the Software is
00017  * furnished to do so, under the terms of the COPYING file.
00018  *
00019  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00020  * KIND, either express or implied.
00021  *
00022  ***************************************************************************/
00023 
00024 #include "curl_setup.h"
00025 
00026 #ifdef USE_LIBRTMP
00027 
00028 #include "urldata.h"
00029 #include "nonblock.h" /* for curlx_nonblock */
00030 #include "progress.h" /* for Curl_pgrsSetUploadSize */
00031 #include "transfer.h"
00032 #include "warnless.h"
00033 #include <curl/curl.h>
00034 #include <librtmp/rtmp.h>
00035 #include "curl_memory.h"
00036 /* The last #include file should be: */
00037 #include "memdebug.h"
00038 
00039 #ifdef _WIN32
00040 #define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e)
00041 #define SET_RCVTIMEO(tv,s)   int tv = s*1000
00042 #else
00043 #define SET_RCVTIMEO(tv,s)   struct timeval tv = {s,0}
00044 #endif
00045 
00046 #define DEF_BUFTIME    (2*60*60*1000)    /* 2 hours */
00047 
00048 static CURLcode rtmp_setup_connection(struct connectdata *conn);
00049 static CURLcode rtmp_do(struct connectdata *conn, bool *done);
00050 static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
00051 static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
00052 static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
00053 
00054 static Curl_recv rtmp_recv;
00055 static Curl_send rtmp_send;
00056 
00057 /*
00058  * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
00059  */
00060 
00061 const struct Curl_handler Curl_handler_rtmp = {
00062   "RTMP",                               /* scheme */
00063   rtmp_setup_connection,                /* setup_connection */
00064   rtmp_do,                              /* do_it */
00065   rtmp_done,                            /* done */
00066   ZERO_NULL,                            /* do_more */
00067   rtmp_connect,                         /* connect_it */
00068   ZERO_NULL,                            /* connecting */
00069   ZERO_NULL,                            /* doing */
00070   ZERO_NULL,                            /* proto_getsock */
00071   ZERO_NULL,                            /* doing_getsock */
00072   ZERO_NULL,                            /* domore_getsock */
00073   ZERO_NULL,                            /* perform_getsock */
00074   rtmp_disconnect,                      /* disconnect */
00075   ZERO_NULL,                            /* readwrite */
00076   PORT_RTMP,                            /* defport */
00077   CURLPROTO_RTMP,                       /* protocol */
00078   PROTOPT_NONE                          /* flags*/
00079 };
00080 
00081 const struct Curl_handler Curl_handler_rtmpt = {
00082   "RTMPT",                              /* scheme */
00083   rtmp_setup_connection,                /* setup_connection */
00084   rtmp_do,                              /* do_it */
00085   rtmp_done,                            /* done */
00086   ZERO_NULL,                            /* do_more */
00087   rtmp_connect,                         /* connect_it */
00088   ZERO_NULL,                            /* connecting */
00089   ZERO_NULL,                            /* doing */
00090   ZERO_NULL,                            /* proto_getsock */
00091   ZERO_NULL,                            /* doing_getsock */
00092   ZERO_NULL,                            /* domore_getsock */
00093   ZERO_NULL,                            /* perform_getsock */
00094   rtmp_disconnect,                      /* disconnect */
00095   ZERO_NULL,                            /* readwrite */
00096   PORT_RTMPT,                           /* defport */
00097   CURLPROTO_RTMPT,                      /* protocol */
00098   PROTOPT_NONE                          /* flags*/
00099 };
00100 
00101 const struct Curl_handler Curl_handler_rtmpe = {
00102   "RTMPE",                              /* scheme */
00103   rtmp_setup_connection,                /* setup_connection */
00104   rtmp_do,                              /* do_it */
00105   rtmp_done,                            /* done */
00106   ZERO_NULL,                            /* do_more */
00107   rtmp_connect,                         /* connect_it */
00108   ZERO_NULL,                            /* connecting */
00109   ZERO_NULL,                            /* doing */
00110   ZERO_NULL,                            /* proto_getsock */
00111   ZERO_NULL,                            /* doing_getsock */
00112   ZERO_NULL,                            /* domore_getsock */
00113   ZERO_NULL,                            /* perform_getsock */
00114   rtmp_disconnect,                      /* disconnect */
00115   ZERO_NULL,                            /* readwrite */
00116   PORT_RTMP,                            /* defport */
00117   CURLPROTO_RTMPE,                      /* protocol */
00118   PROTOPT_NONE                          /* flags*/
00119 };
00120 
00121 const struct Curl_handler Curl_handler_rtmpte = {
00122   "RTMPTE",                             /* scheme */
00123   rtmp_setup_connection,                /* setup_connection */
00124   rtmp_do,                              /* do_it */
00125   rtmp_done,                            /* done */
00126   ZERO_NULL,                            /* do_more */
00127   rtmp_connect,                         /* connect_it */
00128   ZERO_NULL,                            /* connecting */
00129   ZERO_NULL,                            /* doing */
00130   ZERO_NULL,                            /* proto_getsock */
00131   ZERO_NULL,                            /* doing_getsock */
00132   ZERO_NULL,                            /* domore_getsock */
00133   ZERO_NULL,                            /* perform_getsock */
00134   rtmp_disconnect,                      /* disconnect */
00135   ZERO_NULL,                            /* readwrite */
00136   PORT_RTMPT,                           /* defport */
00137   CURLPROTO_RTMPTE,                     /* protocol */
00138   PROTOPT_NONE                          /* flags*/
00139 };
00140 
00141 const struct Curl_handler Curl_handler_rtmps = {
00142   "RTMPS",                              /* scheme */
00143   rtmp_setup_connection,                /* setup_connection */
00144   rtmp_do,                              /* do_it */
00145   rtmp_done,                            /* done */
00146   ZERO_NULL,                            /* do_more */
00147   rtmp_connect,                         /* connect_it */
00148   ZERO_NULL,                            /* connecting */
00149   ZERO_NULL,                            /* doing */
00150   ZERO_NULL,                            /* proto_getsock */
00151   ZERO_NULL,                            /* doing_getsock */
00152   ZERO_NULL,                            /* domore_getsock */
00153   ZERO_NULL,                            /* perform_getsock */
00154   rtmp_disconnect,                      /* disconnect */
00155   ZERO_NULL,                            /* readwrite */
00156   PORT_RTMPS,                           /* defport */
00157   CURLPROTO_RTMPS,                      /* protocol */
00158   PROTOPT_NONE                          /* flags*/
00159 };
00160 
00161 const struct Curl_handler Curl_handler_rtmpts = {
00162   "RTMPTS",                             /* scheme */
00163   rtmp_setup_connection,                /* setup_connection */
00164   rtmp_do,                              /* do_it */
00165   rtmp_done,                            /* done */
00166   ZERO_NULL,                            /* do_more */
00167   rtmp_connect,                         /* connect_it */
00168   ZERO_NULL,                            /* connecting */
00169   ZERO_NULL,                            /* doing */
00170   ZERO_NULL,                            /* proto_getsock */
00171   ZERO_NULL,                            /* doing_getsock */
00172   ZERO_NULL,                            /* domore_getsock */
00173   ZERO_NULL,                            /* perform_getsock */
00174   rtmp_disconnect,                      /* disconnect */
00175   ZERO_NULL,                            /* readwrite */
00176   PORT_RTMPS,                           /* defport */
00177   CURLPROTO_RTMPTS,                     /* protocol */
00178   PROTOPT_NONE                          /* flags*/
00179 };
00180 
00181 static CURLcode rtmp_setup_connection(struct connectdata *conn)
00182 {
00183   RTMP *r = RTMP_Alloc();
00184   if(!r)
00185     return CURLE_OUT_OF_MEMORY;
00186 
00187   RTMP_Init(r);
00188   RTMP_SetBufferMS(r, DEF_BUFTIME);
00189   if(!RTMP_SetupURL(r, conn->data->change.url)) {
00190     RTMP_Free(r);
00191     return CURLE_URL_MALFORMAT;
00192   }
00193   conn->proto.generic = r;
00194   return CURLE_OK;
00195 }
00196 
00197 static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
00198 {
00199   RTMP *r = conn->proto.generic;
00200   SET_RCVTIMEO(tv, 10);
00201 
00202   r->m_sb.sb_socket = conn->sock[FIRSTSOCKET];
00203 
00204   /* We have to know if it's a write before we send the
00205    * connect request packet
00206    */
00207   if(conn->data->set.upload)
00208     r->Link.protocol |= RTMP_FEATURE_WRITE;
00209 
00210   /* For plain streams, use the buffer toggle trick to keep data flowing */
00211   if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
00212      !(r->Link.protocol & RTMP_FEATURE_HTTP))
00213     r->Link.lFlags |= RTMP_LF_BUFX;
00214 
00215   (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
00216   setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
00217              (char *)&tv, sizeof(tv));
00218 
00219   if(!RTMP_Connect1(r, NULL))
00220     return CURLE_FAILED_INIT;
00221 
00222   /* Clients must send a periodic BytesReceived report to the server */
00223   r->m_bSendCounter = true;
00224 
00225   *done = TRUE;
00226   conn->recv[FIRSTSOCKET] = rtmp_recv;
00227   conn->send[FIRSTSOCKET] = rtmp_send;
00228   return CURLE_OK;
00229 }
00230 
00231 static CURLcode rtmp_do(struct connectdata *conn, bool *done)
00232 {
00233   RTMP *r = conn->proto.generic;
00234 
00235   if(!RTMP_ConnectStream(r, 0))
00236     return CURLE_FAILED_INIT;
00237 
00238   if(conn->data->set.upload) {
00239     Curl_pgrsSetUploadSize(conn->data, conn->data->state.infilesize);
00240     Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
00241   }
00242   else
00243     Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
00244   *done = TRUE;
00245   return CURLE_OK;
00246 }
00247 
00248 static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
00249                           bool premature)
00250 {
00251   (void)conn; /* unused */
00252   (void)status; /* unused */
00253   (void)premature; /* unused */
00254 
00255   return CURLE_OK;
00256 }
00257 
00258 static CURLcode rtmp_disconnect(struct connectdata *conn,
00259                                 bool dead_connection)
00260 {
00261   RTMP *r = conn->proto.generic;
00262   (void)dead_connection;
00263   if(r) {
00264     conn->proto.generic = NULL;
00265     RTMP_Close(r);
00266     RTMP_Free(r);
00267   }
00268   return CURLE_OK;
00269 }
00270 
00271 static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
00272                          size_t len, CURLcode *err)
00273 {
00274   RTMP *r = conn->proto.generic;
00275   ssize_t nread;
00276 
00277   (void)sockindex; /* unused */
00278 
00279   nread = RTMP_Read(r, buf, curlx_uztosi(len));
00280   if(nread < 0) {
00281     if(r->m_read.status == RTMP_READ_COMPLETE ||
00282         r->m_read.status == RTMP_READ_EOF) {
00283       conn->data->req.size = conn->data->req.bytecount;
00284       nread = 0;
00285     }
00286     else
00287       *err = CURLE_RECV_ERROR;
00288   }
00289   return nread;
00290 }
00291 
00292 static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
00293                          const void *buf, size_t len, CURLcode *err)
00294 {
00295   RTMP *r = conn->proto.generic;
00296   ssize_t num;
00297 
00298   (void)sockindex; /* unused */
00299 
00300   num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
00301   if(num < 0)
00302     *err = CURLE_SEND_ERROR;
00303 
00304   return num;
00305 }
00306 #endif  /* USE_LIBRTMP */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02