diff options
author | Howard Chu <hyc@highlandsun.com> | 2010-05-12 23:07:20 +0200 |
---|---|---|
committer | Daniel Stenberg <daniel@haxx.se> | 2010-05-12 23:07:20 +0200 |
commit | 04cb15ae9dc0e863487ee55de2226cf5033311c0 (patch) | |
tree | bce4eb1a51164342cf35ba456a225fc1fefa9766 /lib | |
parent | bc8fc9803fbd0fa9daf0dba796d42d03faf49120 (diff) |
RTMP: initial support added, powered by librtmp
librtmp is found at http://rtmpdump.mplayerhq.hu/
Diffstat (limited to 'lib')
-rw-r--r-- | lib/Makefile.inc | 4 | ||||
-rw-r--r-- | lib/curl_rtmp.c | 267 | ||||
-rw-r--r-- | lib/curl_rtmp.h | 34 | ||||
-rw-r--r-- | lib/url.c | 10 | ||||
-rw-r--r-- | lib/urldata.h | 18 |
5 files changed, 327 insertions, 6 deletions
diff --git a/lib/Makefile.inc b/lib/Makefile.inc index e35e8bb57..e0c091f4a 100644 --- a/lib/Makefile.inc +++ b/lib/Makefile.inc @@ -12,7 +12,7 @@ CSOURCES = file.c timeval.c base64.c hostip.c progress.c formdata.c \ strdup.c socks.c ssh.c nss.c qssl.c rawstr.c curl_addrinfo.c \ socks_gssapi.c socks_sspi.c curl_sspi.c slist.c nonblock.c \ curl_memrchr.c imap.c pop3.c smtp.c pingpong.c rtsp.c curl_threads.c \ - warnless.c hmac.c polarssl.c + warnless.c hmac.c polarssl.c curl_rtmp.c HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ progress.h formdata.h cookie.h http.h sendf.h ftp.h url.h dict.h \ @@ -25,4 +25,4 @@ HHEADERS = arpa_telnet.h netrc.h file.h timeval.h qssl.h hostip.h \ tftp.h sockaddr.h splay.h strdup.h setup_once.h socks.h ssh.h nssg.h \ curl_base64.h rawstr.h curl_addrinfo.h curl_sspi.h slist.h nonblock.h \ curl_memrchr.h imap.h pop3.h smtp.h pingpong.h rtsp.h curl_threads.h \ - warnless.h curl_hmac.h polarssl.h + warnless.h curl_hmac.h polarssl.h curl_rtmp.h diff --git a/lib/curl_rtmp.c b/lib/curl_rtmp.c new file mode 100644 index 000000000..4700719ba --- /dev/null +++ b/lib/curl_rtmp.c @@ -0,0 +1,267 @@ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +#include "setup.h" + +#ifdef USE_LIBRTMP + +#include "urldata.h" +#include <curl/curl.h> +#include <librtmp/rtmp.h> + +#ifdef _WIN32 +#define setsockopt(a,b,c,d,e) (setsockopt)(a,b,c,(const char *)d,(int)e) +#define SET_RCVTIMEO(tv,s) int tv = s*1000 +#else +#define SET_RCVTIMEO(tv,s) struct timeval tv = {s,0} +#endif + +#define DEF_BUFTIME (2*60*60*1000) /* 2 hours */ + +static CURLcode rtmp_setup(struct connectdata *conn); +static CURLcode rtmp_do(struct connectdata *conn, bool *done); +static CURLcode rtmp_done(struct connectdata *conn, CURLcode, bool premature); +static CURLcode rtmp_connect(struct connectdata *conn, bool *done); +static CURLcode rtmp_disconnect(struct connectdata *conn); + +static Curl_recv rtmp_recv; +static Curl_send rtmp_send; + +/* + * RTMP protocol handler.h, based on http://rtmpdump.mplayerhq.hu + */ + +const struct Curl_handler Curl_handler_rtmp = { + "RTMP", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMP, /* defport */ + PROT_RTMP /* protocol */ +}; + +const struct Curl_handler Curl_handler_rtmpt = { + "RTMPT", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMPT, /* defport */ + PROT_RTMPT /* protocol */ +}; + +const struct Curl_handler Curl_handler_rtmpe = { + "RTMPE", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMP, /* defport */ + PROT_RTMPE /* protocol */ +}; + +const struct Curl_handler Curl_handler_rtmpte = { + "RTMPTE", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMPT, /* defport */ + PROT_RTMPTE /* protocol */ +}; + +const struct Curl_handler Curl_handler_rtmps = { + "RTMPS", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMPS, /* defport */ + PROT_RTMPS /* protocol */ +}; +const struct Curl_handler Curl_handler_rtmpts = { + "RTMPTS", /* scheme */ + rtmp_setup, /* setup_connection */ + rtmp_do, /* do_it */ + rtmp_done, /* done */ + ZERO_NULL, /* do_more */ + rtmp_connect, /* connect_it */ + ZERO_NULL, /* connecting */ + ZERO_NULL, /* doing */ + ZERO_NULL, /* proto_getsock */ + ZERO_NULL, /* doing_getsock */ + ZERO_NULL, /* perform_getsock */ + rtmp_disconnect, /* disconnect */ + PORT_RTMPS, /* defport */ + PROT_RTMPTS /* protocol */ +}; + +static CURLcode rtmp_setup(struct connectdata *conn) +{ + int rc; + RTMP *r = RTMP_Alloc(); + + if (!r) + return CURLE_OUT_OF_MEMORY; + + RTMP_Init(r); + RTMP_SetBufferMS(r, DEF_BUFTIME); + if (!RTMP_SetupURL(r, conn->data->change.url)) { + RTMP_Free(r); + return CURLE_URL_MALFORMAT; + } + conn->proto.generic = r; + return CURLE_OK; +} + +static CURLcode rtmp_connect(struct connectdata *conn, bool *done) +{ + RTMP *r = conn->proto.generic; + SET_RCVTIMEO(tv,10); + + r->m_sb.sb_socket = conn->sock[FIRSTSOCKET]; + + /* We have to know if it's a write before we send the + * connect request packet + */ + if (conn->data->set.upload) + r->Link.protocol |= RTMP_FEATURE_WRITE; + + /* For plain streams, use the buffer toggle trick to keep data flowing */ + if (!(r->Link.lFlags & RTMP_LF_LIVE) && !(r->Link.protocol & RTMP_FEATURE_HTTP)) + r->Link.lFlags |= RTMP_LF_BUFX; + + curlx_nonblock(r->m_sb.sb_socket, FALSE); + setsockopt(r->m_sb.sb_socket, SOL_SOCKET, SO_RCVTIMEO, (char *)&tv, sizeof(tv)); + + if (!RTMP_Connect1(r, NULL)) + return CURLE_FAILED_INIT; + + /* Clients must send a periodic BytesReceived report to the server */ + r->m_bSendCounter = true; + + *done = TRUE; + conn->recv[FIRSTSOCKET] = rtmp_recv; + conn->send[FIRSTSOCKET] = rtmp_send; + return CURLE_OK; +} + +static CURLcode rtmp_do(struct connectdata *conn, bool *done) +{ + RTMP *r = conn->proto.generic; + + if (!RTMP_ConnectStream(r, 0)) + return CURLE_FAILED_INIT; + + if (conn->data->set.upload) { + Curl_pgrsSetUploadSize(conn->data, conn->data->set.infilesize); + Curl_setup_transfer(conn, -1, -1, FALSE, NULL, FIRSTSOCKET, NULL); + } else + Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); + *done = TRUE; + return CURLE_OK; +} + +static CURLcode rtmp_done(struct connectdata *conn, CURLcode status, + bool premature) +{ + return CURLE_OK; +} + +static CURLcode rtmp_disconnect(struct connectdata *conn) +{ + RTMP *r = conn->proto.generic; + if (r) { + conn->proto.generic = NULL; + RTMP_Close(r); + RTMP_Free(r); + } + return CURLE_OK; +} + +static ssize_t rtmp_recv(struct connectdata *conn, int sockindex, char *buf, + size_t len, CURLcode *err) +{ + RTMP *r = conn->proto.generic; + ssize_t nread; + + nread = RTMP_Read(r, buf, len); + if (nread < 0) { + if (r->m_read.status == RTMP_READ_COMPLETE || + r->m_read.status == RTMP_READ_EOF) { + conn->data->req.size = conn->data->req.bytecount; + nread = 0; + } else + *err = CURLE_RECV_ERROR; + } + return nread; +} + +static ssize_t rtmp_send(struct connectdata *conn, int sockindex, + const void *buf, size_t len, CURLcode *err) +{ + RTMP *r = conn->proto.generic; + ssize_t num; + + num = RTMP_Write(r, (char *)buf, len); + if (num < 0) { + *err = CURLE_SEND_ERROR; + } + return num; +} +#endif /* USE_LIBRTMP */ diff --git a/lib/curl_rtmp.h b/lib/curl_rtmp.h new file mode 100644 index 000000000..35776aaa6 --- /dev/null +++ b/lib/curl_rtmp.h @@ -0,0 +1,34 @@ +#ifndef __CURL_RTMP_H +#define __CURL_RTMP_H + +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 2010, Howard Chu, <hyc@highlandsun.com> + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ +#ifndef CURL_DISABLE_RTMP +extern const struct Curl_handler Curl_handler_rtmp; +extern const struct Curl_handler Curl_handler_rtmpt; +extern const struct Curl_handler Curl_handler_rtmpe; +extern const struct Curl_handler Curl_handler_rtmpte; +extern const struct Curl_handler Curl_handler_rtmps; +extern const struct Curl_handler Curl_handler_rtmpts; +#endif + +#endif /* __CURL_RTMP_H */ @@ -137,6 +137,7 @@ void idn_free (void *ptr); /* prototype from idn-free.h, not provided by #include "http_ntlm.h" #include "socks.h" #include "rtsp.h" +#include "curl_rtmp.h" #define _MPRINTF_REPLACE /* use our functions only */ #include <curl/mprintf.h> @@ -226,6 +227,15 @@ static const struct Curl_handler * const protocols[] = { &Curl_handler_rtsp, #endif +#ifdef USE_LIBRTMP + &Curl_handler_rtmp, + &Curl_handler_rtmpt, + &Curl_handler_rtmpe, + &Curl_handler_rtmpte, + &Curl_handler_rtmps, + &Curl_handler_rtmpts, +#endif + (struct Curl_handler *) NULL }; diff --git a/lib/urldata.h b/lib/urldata.h index 30782c2a2..94e904fe5 100644 --- a/lib/urldata.h +++ b/lib/urldata.h @@ -43,6 +43,9 @@ #define PORT_SMTP 25 #define PORT_SMTPS 465 /* sometimes called SSMTP */ #define PORT_RTSP 554 +#define PORT_RTMP 1935 +#define PORT_RTMPT PORT_HTTP +#define PORT_RTMPS PORT_HTTPS #define DICT_MATCH "/MATCH:" #define DICT_MATCH2 "/M:" @@ -706,13 +709,19 @@ struct connectdata { #define PROT_SMTP CURLPROTO_SMTP #define PROT_SMTPS CURLPROTO_SMTPS #define PROT_RTSP CURLPROTO_RTSP - -/* (1<<18) is currently the highest used bit in the public bitmask. We make +#define PROT_RTMP CURLPROTO_RTMP +#define PROT_RTMPT CURLPROTO_RTMPT +#define PROT_RTMPE CURLPROTO_RTMPE +#define PROT_RTMPTE CURLPROTO_RTMPTE +#define PROT_RTMPS CURLPROTO_RTMPS +#define PROT_RTMPTS CURLPROTO_RTMPTS + +/* (1<<24) is currently the highest used bit in the public bitmask. We make sure we use "private bits" above the public ones to make things easier. */ -#define PROT_EXTMASK 0xfffff +#define PROT_EXTMASK 0xffffff -#define PROT_SSL (1<<25) /* protocol requires SSL */ +#define PROT_SSL (1<<29) /* protocol requires SSL */ /* these ones need action before socket close */ #define PROT_CLOSEACTION (PROT_FTP | PROT_IMAP | PROT_POP3) @@ -864,6 +873,7 @@ struct connectdata { struct pop3_conn pop3c; struct smtp_conn smtpc; struct rtsp_conn rtspc; + void *generic; } proto; int cselect_bits; /* bitmask of socket events */ |