00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "curl_setup.h"
00025
00026 #ifdef USE_LIBRTMP
00027
00028 #include "urldata.h"
00029 #include "nonblock.h"
00030 #include "progress.h"
00031 #include "transfer.h"
00032 #include "warnless.h"
00033 #include <curl/curl.h>
00034 #include <librtmp/rtmp.h>
00035 #include "curl_memory.h"
00036
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)
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
00059
00060
00061 const struct Curl_handler Curl_handler_rtmp = {
00062 "RTMP",
00063 rtmp_setup_connection,
00064 rtmp_do,
00065 rtmp_done,
00066 ZERO_NULL,
00067 rtmp_connect,
00068 ZERO_NULL,
00069 ZERO_NULL,
00070 ZERO_NULL,
00071 ZERO_NULL,
00072 ZERO_NULL,
00073 ZERO_NULL,
00074 rtmp_disconnect,
00075 ZERO_NULL,
00076 PORT_RTMP,
00077 CURLPROTO_RTMP,
00078 PROTOPT_NONE
00079 };
00080
00081 const struct Curl_handler Curl_handler_rtmpt = {
00082 "RTMPT",
00083 rtmp_setup_connection,
00084 rtmp_do,
00085 rtmp_done,
00086 ZERO_NULL,
00087 rtmp_connect,
00088 ZERO_NULL,
00089 ZERO_NULL,
00090 ZERO_NULL,
00091 ZERO_NULL,
00092 ZERO_NULL,
00093 ZERO_NULL,
00094 rtmp_disconnect,
00095 ZERO_NULL,
00096 PORT_RTMPT,
00097 CURLPROTO_RTMPT,
00098 PROTOPT_NONE
00099 };
00100
00101 const struct Curl_handler Curl_handler_rtmpe = {
00102 "RTMPE",
00103 rtmp_setup_connection,
00104 rtmp_do,
00105 rtmp_done,
00106 ZERO_NULL,
00107 rtmp_connect,
00108 ZERO_NULL,
00109 ZERO_NULL,
00110 ZERO_NULL,
00111 ZERO_NULL,
00112 ZERO_NULL,
00113 ZERO_NULL,
00114 rtmp_disconnect,
00115 ZERO_NULL,
00116 PORT_RTMP,
00117 CURLPROTO_RTMPE,
00118 PROTOPT_NONE
00119 };
00120
00121 const struct Curl_handler Curl_handler_rtmpte = {
00122 "RTMPTE",
00123 rtmp_setup_connection,
00124 rtmp_do,
00125 rtmp_done,
00126 ZERO_NULL,
00127 rtmp_connect,
00128 ZERO_NULL,
00129 ZERO_NULL,
00130 ZERO_NULL,
00131 ZERO_NULL,
00132 ZERO_NULL,
00133 ZERO_NULL,
00134 rtmp_disconnect,
00135 ZERO_NULL,
00136 PORT_RTMPT,
00137 CURLPROTO_RTMPTE,
00138 PROTOPT_NONE
00139 };
00140
00141 const struct Curl_handler Curl_handler_rtmps = {
00142 "RTMPS",
00143 rtmp_setup_connection,
00144 rtmp_do,
00145 rtmp_done,
00146 ZERO_NULL,
00147 rtmp_connect,
00148 ZERO_NULL,
00149 ZERO_NULL,
00150 ZERO_NULL,
00151 ZERO_NULL,
00152 ZERO_NULL,
00153 ZERO_NULL,
00154 rtmp_disconnect,
00155 ZERO_NULL,
00156 PORT_RTMPS,
00157 CURLPROTO_RTMPS,
00158 PROTOPT_NONE
00159 };
00160
00161 const struct Curl_handler Curl_handler_rtmpts = {
00162 "RTMPTS",
00163 rtmp_setup_connection,
00164 rtmp_do,
00165 rtmp_done,
00166 ZERO_NULL,
00167 rtmp_connect,
00168 ZERO_NULL,
00169 ZERO_NULL,
00170 ZERO_NULL,
00171 ZERO_NULL,
00172 ZERO_NULL,
00173 ZERO_NULL,
00174 rtmp_disconnect,
00175 ZERO_NULL,
00176 PORT_RTMPS,
00177 CURLPROTO_RTMPTS,
00178 PROTOPT_NONE
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
00205
00206
00207 if(conn->data->set.upload)
00208 r->Link.protocol |= RTMP_FEATURE_WRITE;
00209
00210
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
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;
00252 (void)status;
00253 (void)premature;
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;
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;
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