curl_rtmp.c
Go to the documentation of this file.
1 /***************************************************************************
2  * _ _ ____ _
3  * Project ___| | | | _ \| |
4  * / __| | | | |_) | |
5  * | (__| |_| | _ <| |___
6  * \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2012 - 2015, 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 #ifdef _WIN32
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 #else
44 #define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0}
45 #endif
46 
47 #define DEF_BUFTIME (2*60*60*1000) /* 2 hours */
48 
49 static CURLcode rtmp_setup_connection(struct connectdata *conn);
50 static CURLcode rtmp_do(struct connectdata *conn, bool *done);
51 static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature);
52 static CURLcode rtmp_connect(struct connectdata *conn, bool *done);
53 static CURLcode rtmp_disconnect(struct connectdata *conn, bool dead);
54 
55 static Curl_recv rtmp_recv;
56 static Curl_send rtmp_send;
57 
58 /*
59  * RTMP protocol handler.h, based on https://rtmpdump.mplayerhq.hu
60  */
61 
62 const struct Curl_handler Curl_handler_rtmp = {
63  "RTMP", /* scheme */
64  rtmp_setup_connection, /* setup_connection */
65  rtmp_do, /* do_it */
66  rtmp_done, /* done */
67  ZERO_NULL, /* do_more */
68  rtmp_connect, /* connect_it */
69  ZERO_NULL, /* connecting */
70  ZERO_NULL, /* doing */
71  ZERO_NULL, /* proto_getsock */
72  ZERO_NULL, /* doing_getsock */
73  ZERO_NULL, /* domore_getsock */
74  ZERO_NULL, /* perform_getsock */
75  rtmp_disconnect, /* disconnect */
76  ZERO_NULL, /* readwrite */
77  ZERO_NULL, /* connection_check */
78  PORT_RTMP, /* defport */
79  CURLPROTO_RTMP, /* protocol */
80  PROTOPT_NONE /* flags*/
81 };
82 
83 const struct Curl_handler Curl_handler_rtmpt = {
84  "RTMPT", /* scheme */
85  rtmp_setup_connection, /* setup_connection */
86  rtmp_do, /* do_it */
87  rtmp_done, /* done */
88  ZERO_NULL, /* do_more */
89  rtmp_connect, /* connect_it */
90  ZERO_NULL, /* connecting */
91  ZERO_NULL, /* doing */
92  ZERO_NULL, /* proto_getsock */
93  ZERO_NULL, /* doing_getsock */
94  ZERO_NULL, /* domore_getsock */
95  ZERO_NULL, /* perform_getsock */
96  rtmp_disconnect, /* disconnect */
97  ZERO_NULL, /* readwrite */
98  ZERO_NULL, /* connection_check */
99  PORT_RTMPT, /* defport */
100  CURLPROTO_RTMPT, /* protocol */
101  PROTOPT_NONE /* flags*/
102 };
103 
104 const struct Curl_handler Curl_handler_rtmpe = {
105  "RTMPE", /* scheme */
106  rtmp_setup_connection, /* setup_connection */
107  rtmp_do, /* do_it */
108  rtmp_done, /* done */
109  ZERO_NULL, /* do_more */
110  rtmp_connect, /* connect_it */
111  ZERO_NULL, /* connecting */
112  ZERO_NULL, /* doing */
113  ZERO_NULL, /* proto_getsock */
114  ZERO_NULL, /* doing_getsock */
115  ZERO_NULL, /* domore_getsock */
116  ZERO_NULL, /* perform_getsock */
117  rtmp_disconnect, /* disconnect */
118  ZERO_NULL, /* readwrite */
119  ZERO_NULL, /* connection_check */
120  PORT_RTMP, /* defport */
121  CURLPROTO_RTMPE, /* protocol */
122  PROTOPT_NONE /* flags*/
123 };
124 
125 const struct Curl_handler Curl_handler_rtmpte = {
126  "RTMPTE", /* scheme */
127  rtmp_setup_connection, /* setup_connection */
128  rtmp_do, /* do_it */
129  rtmp_done, /* done */
130  ZERO_NULL, /* do_more */
131  rtmp_connect, /* connect_it */
132  ZERO_NULL, /* connecting */
133  ZERO_NULL, /* doing */
134  ZERO_NULL, /* proto_getsock */
135  ZERO_NULL, /* doing_getsock */
136  ZERO_NULL, /* domore_getsock */
137  ZERO_NULL, /* perform_getsock */
138  rtmp_disconnect, /* disconnect */
139  ZERO_NULL, /* readwrite */
140  ZERO_NULL, /* connection_check */
141  PORT_RTMPT, /* defport */
142  CURLPROTO_RTMPTE, /* protocol */
143  PROTOPT_NONE /* flags*/
144 };
145 
146 const struct Curl_handler Curl_handler_rtmps = {
147  "RTMPS", /* scheme */
148  rtmp_setup_connection, /* setup_connection */
149  rtmp_do, /* do_it */
150  rtmp_done, /* done */
151  ZERO_NULL, /* do_more */
152  rtmp_connect, /* connect_it */
153  ZERO_NULL, /* connecting */
154  ZERO_NULL, /* doing */
155  ZERO_NULL, /* proto_getsock */
156  ZERO_NULL, /* doing_getsock */
157  ZERO_NULL, /* domore_getsock */
158  ZERO_NULL, /* perform_getsock */
159  rtmp_disconnect, /* disconnect */
160  ZERO_NULL, /* readwrite */
161  ZERO_NULL, /* connection_check */
162  PORT_RTMPS, /* defport */
163  CURLPROTO_RTMPS, /* protocol */
164  PROTOPT_NONE /* flags*/
165 };
166 
167 const struct Curl_handler Curl_handler_rtmpts = {
168  "RTMPTS", /* scheme */
169  rtmp_setup_connection, /* setup_connection */
170  rtmp_do, /* do_it */
171  rtmp_done, /* done */
172  ZERO_NULL, /* do_more */
173  rtmp_connect, /* connect_it */
174  ZERO_NULL, /* connecting */
175  ZERO_NULL, /* doing */
176  ZERO_NULL, /* proto_getsock */
177  ZERO_NULL, /* doing_getsock */
178  ZERO_NULL, /* domore_getsock */
179  ZERO_NULL, /* perform_getsock */
180  rtmp_disconnect, /* disconnect */
181  ZERO_NULL, /* readwrite */
182  ZERO_NULL, /* connection_check */
183  PORT_RTMPS, /* defport */
184  CURLPROTO_RTMPTS, /* protocol */
185  PROTOPT_NONE /* flags*/
186 };
187 
188 static CURLcode rtmp_setup_connection(struct connectdata *conn)
189 {
190  RTMP *r = RTMP_Alloc();
191  if(!r)
192  return CURLE_OUT_OF_MEMORY;
193 
194  RTMP_Init(r);
195  RTMP_SetBufferMS(r, DEF_BUFTIME);
196  if(!RTMP_SetupURL(r, conn->data->change.url)) {
197  RTMP_Free(r);
198  return CURLE_URL_MALFORMAT;
199  }
200  conn->proto.generic = r;
201  return CURLE_OK;
202 }
203 
204 static CURLcode rtmp_connect(struct connectdata *conn, bool *done)
205 {
206  RTMP *r = conn->proto.generic;
207  SET_RCVTIMEO(tv, 10);
208 
209  r->m_sb.sb_socket = (int)conn->sock[FIRSTSOCKET];
210 
211  /* We have to know if it's a write before we send the
212  * connect request packet
213  */
214  if(conn->data->set.upload)
215  r->Link.protocol |= RTMP_FEATURE_WRITE;
216 
217  /* For plain streams, use the buffer toggle trick to keep data flowing */
218  if(!(r->Link.lFlags & RTMP_LF_LIVE) &&
219  !(r->Link.protocol & RTMP_FEATURE_HTTP))
220  r->Link.lFlags |= RTMP_LF_BUFX;
221 
222  (void)curlx_nonblock(r->m_sb.sb_socket, FALSE);
223  setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO,
224  (char *)&tv, sizeof(tv));
225 
226  if(!RTMP_Connect1(r, NULL))
227  return CURLE_FAILED_INIT;
228 
229  /* Clients must send a periodic BytesReceived report to the server */
230  r->m_bSendCounter = true;
231 
232  *done = TRUE;
233  conn->recv[FIRSTSOCKET] = rtmp_recv;
234  conn->send[FIRSTSOCKET] = rtmp_send;
235  return CURLE_OK;
236 }
237 
238 static CURLcode rtmp_do(struct connectdata *conn, bool *done)
239 {
240  RTMP *r = conn->proto.generic;
241 
242  if(!RTMP_ConnectStream(r, 0))
243  return CURLE_FAILED_INIT;
244 
245  if(conn->data->set.upload) {
247  Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL);
248  }
249  else
250  Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
251  *done = TRUE;
252  return CURLE_OK;
253 }
254 
255 static CURLcode rtmp_done(struct connectdata *conn, CURLcode status,
256  bool premature)
257 {
258  (void)conn; /* unused */
259  (void)status; /* unused */
260  (void)premature; /* unused */
261 
262  return CURLE_OK;
263 }
264 
265 static CURLcode rtmp_disconnect(struct connectdata *conn,
266  bool dead_connection)
267 {
268  RTMP *r = conn->proto.generic;
269  (void)dead_connection;
270  if(r) {
271  conn->proto.generic = NULL;
272  RTMP_Close(r);
273  RTMP_Free(r);
274  }
275  return CURLE_OK;
276 }
277 
278 static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf,
279  size_t len, CURLcode *err)
280 {
281  RTMP *r = conn->proto.generic;
282  ssize_t nread;
283 
284  (void)sockindex; /* unused */
285 
286  nread = RTMP_Read(r, buf, curlx_uztosi(len));
287  if(nread < 0) {
288  if(r->m_read.status == RTMP_READ_COMPLETE ||
289  r->m_read.status == RTMP_READ_EOF) {
290  conn->data->req.size = conn->data->req.bytecount;
291  nread = 0;
292  }
293  else
294  *err = CURLE_RECV_ERROR;
295  }
296  return nread;
297 }
298 
299 static ssize_t rtmp_send(struct connectdata *conn, int sockindex,
300  const void *buf, size_t len, CURLcode *err)
301 {
302  RTMP *r = conn->proto.generic;
303  ssize_t num;
304 
305  (void)sockindex; /* unused */
306 
307  num = RTMP_Write(r, (char *)buf, curlx_uztosi(len));
308  if(num < 0)
309  *err = CURLE_SEND_ERROR;
310 
311  return num;
312 }
313 #endif /* USE_LIBRTMP */
ssize_t( Curl_recv)(struct connectdata *conn, int sockindex, char *buf, size_t len, CURLcode *err)
Definition: urldata.h:737
struct UserDefined set
Definition: urldata.h:1762
Curl_recv * recv[2]
Definition: urldata.h:881
#define PORT_RTMPS
Definition: urldata.h:50
curl_off_t size
Definition: urldata.h:519
char * url
Definition: urldata.h:1372
#define FIRSTSOCKET
Definition: urldata.h:487
CURLcode
Definition: curl.h:454
int curlx_uztosi(size_t uznum)
Definition: warnless.c:203
#define CURLPROTO_RTMPTS
Definition: curl.h:868
#define PORT_RTMP
Definition: urldata.h:48
struct DynamicStatic change
Definition: urldata.h:1763
int curlx_nonblock(curl_socket_t sockfd, int nonblock)
Definition: nonblock.c:47
size_t len
Definition: curl_sasl.c:55
#define ZERO_NULL
Definition: curlx.c:131
void Curl_setup_transfer(struct connectdata *conn, int sockindex, curl_off_t size, bool getheader, curl_off_t *bytecountp, int writesockindex, curl_off_t *writecountp)
Definition: transfer.c:1989
#define FALSE
struct SingleRequest req
Definition: urldata.h:1761
Curl_done_func done
Definition: urldata.h:630
curl_off_t infilesize
Definition: urldata.h:1345
void Curl_pgrsSetUploadSize(struct Curl_easy *data, curl_off_t size)
Definition: progress.c:334
#define CURLPROTO_RTMP
Definition: curl.h:863
Curl_send * send[2]
Definition: urldata.h:882
#define PORT_RTMPT
Definition: urldata.h:49
Definition: curl.h:455
ssize_t( Curl_send)(struct connectdata *conn, int sockindex, const void *buf, size_t len, CURLcode *err)
Definition: urldata.h:730
#define PROTOPT_NONE
Definition: urldata.h:699
#define CURLPROTO_RTMPE
Definition: curl.h:865
struct UrlState state
Definition: urldata.h:1769
#define CURLPROTO_RTMPTE
Definition: curl.h:866
void * generic
Definition: urldata.h:1007
#define CURLPROTO_RTMPT
Definition: curl.h:864
#define ssize_t
Definition: config-win32.h:382
curl_socket_t sock[2]
Definition: urldata.h:876
bool done
Definition: urldata.h:1185
char buf[3]
Definition: unit1398.c:32
union connectdata::@34 proto
#define TRUE
#define CURLPROTO_RTMPS
Definition: curl.h:867
bool upload
Definition: urldata.h:1632
curl_off_t bytecount
Definition: urldata.h:526
struct Curl_easy * data
Definition: urldata.h:791


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:08