Web lists-archives.com

[MPlayer-dev-eng] Patch adding GNU TLS support to mplayer




Lately more of youtube videos are streamed over https, which makes smtube with mplayer back-end fail with an error message stating there was no stream to handle. In order to solve this issue, I made this patch adding GNU TLS support to mplayer (see attached gnu_tls_draft.patch and the TLS implementation in tls.h and tls.c, both files to be copied to 'stream' subdirectory) and would like to send it in for a review. I also took into consideration a previous attempt to add similar functionality to mplayer (see http://lists.mplayerhq.hu/pipermail/mplayer-dev-eng/2007-February/049277.html).

It works for me with youtube https streams.

Oleksandr
Index: Makefile
===================================================================
--- Makefile	(revision 37263)
+++ Makefile	(working copy)
@@ -174,6 +174,8 @@
                                         stream/librtsp/rtsp_rtp.c       \
                                         stream/librtsp/rtsp_session.c   \
 
+SRCS_COMMON-$(GNU_TLS)               += stream/tls.c
+
 SRCS_COMMON-$(NETWORKING)            += stream/stream_netstream.c       \
                                         stream/asf_mmst_streaming.c     \
                                         stream/asf_streaming.c          \
Index: configure
===================================================================
--- configure	(revision 37263)
+++ configure	(working copy)
@@ -351,6 +351,7 @@
   --disable-pvr          disable Video4Linux2 MPEG PVR [autodetect]
   --disable-rtc          disable RTC (/dev/rtc) on Linux [autodetect]
   --disable-networking   disable networking [enable]
+  --disable-gnu-tls      disable GNU TLS [enable]
   --enable-winsock2_h    enable winsock2_h [autodetect]
   --enable-smb           enable Samba (SMB) input [autodetect]
   --enable-live          enable LIVE555 Streaming Media [autodetect]
@@ -785,6 +786,7 @@
 _tv_dshow=auto
 _pvr=auto
 networking=yes
+_gnu_tls=auto
 _winsock2_h=auto
 _struct_addrinfo=auto
 _getaddrinfo=auto
@@ -1240,6 +1242,8 @@
   --disable-hardcoded-tables) hardcoded_tables=no  ;;
   --enable-networking)     networking=yes    ;;
   --disable-networking)    networking=no     ;;
+  --enable-gnu-tls)     _gnu_tls=yes    ;;
+  --disable-gnu-tls)    _gnu_tls=no     ;;
   --enable-winsock2_h)  _winsock2_h=yes ;;
   --disable-winsock2_h) _winsock2_h=no  ;;
   --enable-smb)         _smb=yes        ;;
@@ -3649,6 +3653,27 @@
 echores "$networking"
 
 
+echocheck "GNU TLS library"
+if test "$networking" = yes ; then
+  if test "$_gnu_tls" = auto ; then
+    cat > $TMPC << EOF
+#include <gnutls/gnutls.h>
+#include <gnutls/x509.h>
+int main(void) { return 0; }
+EOF
+    _gnu_tls=no
+    cc_check -lgnutls -lcrypto && _gnu_tls=yes
+    if test "$_gnu_tls" = yes ; then
+      def_gnu_tls='#define HAVE_GNU_TLS 1'
+      extra_ldflags="$extra_ldflags -lgnutls -lcrypto"
+    else
+      def_gnu_tls='#undef HAVE_GNU_TLS'
+    fi
+  fi
+fi
+echores "$_gnu_tls"
+
+
 echocheck "inet6"
 if test "$_inet6" = auto ; then
   cat > $TMPC << EOF
@@ -8535,6 +8560,7 @@
 NAS = $_nas
 NATIVE_RTSP = $_native_rtsp
 NETWORKING = $networking
+GNU_TLS = $_gnu_tls
 OPENAL = $_openal
 OSS = $_ossaudio
 PE_EXECUTABLE = $_pe_executable
@@ -9063,6 +9089,7 @@
 $def_live
 $def_nemesi
 $def_networking
+$def_gnu_tls
 $def_smb
 $def_vstream
 
Index: stream/asf_streaming.c
===================================================================
--- stream/asf_streaming.c	(revision 37263)
+++ stream/asf_streaming.c	(working copy)
@@ -48,12 +48,20 @@
 
 #include "libmpdemux/asfguid.h"
 
+#ifdef HAVE_GNU_TLS
+#include "tls.h"
+#endif
+
 static int asf_http_streaming_start(stream_t *stream, int *demuxer_type);
 
 static int asf_read_wrapper(int fd, void *buffer, int len, streaming_ctrl_t *stream_ctrl) {
     uint8_t *buf = buffer;
     while (len > 0) {
+#ifdef HAVE_GNU_TLS
+        int got = nop_streaming_read(fd, 0, buf, len, stream_ctrl);
+#else
         int got = nop_streaming_read(fd, buf, len, stream_ctrl);
+#endif
         if (got <= 0) {
             mp_msg(MSGT_NETWORK, MSGL_ERR, MSGTR_MPDEMUX_ASF_ErrReadingNetworkStream);
             return got;
@@ -152,6 +160,10 @@
 }
 
 static void close_s(stream_t *stream) {
+	#ifdef HAVE_GNU_TLS
+	if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+	stream->tls_sid = 0;
+#endif
 	closesocket(stream->fd);
 	stream->fd=-1;
 }
@@ -699,7 +711,16 @@
 
 	do {
 		done = 1;
-		if( fd>0 ) closesocket( fd );
+		if( fd>0 ) 
+#ifdef HAVE_GNU_TLS
+		{
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
+			closesocket( fd );
+#ifdef HAVE_GNU_TLS
+		}
+#endif
 
 		if( !strcasecmp( url->protocol, "http_proxy" ) ) {
 			if( url->port==0 ) url->port = 8080;
@@ -802,6 +823,10 @@
 	return 0;
 
 err_out:
+#ifdef HAVE_GNU_TLS
+	if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+	stream->tls_sid = 0;
+#endif
 	if (fd > 0)
 		closesocket(fd);
 	stream->fd = -1;
Index: stream/http.c
===================================================================
--- stream/http.c	(revision 37263)
+++ stream/http.c	(working copy)
@@ -45,6 +45,10 @@
 
 #include "libavutil/base64.h"
 
+#ifdef HAVE_GNU_TLS
+#include "tls.h"
+#endif
+
 typedef struct {
   unsigned metaint;
   unsigned metapos;
@@ -223,9 +227,18 @@
 
 	fd = stream->fd;
 	if( fd<0 ) {
+#ifdef HAVE_GNU_TLS
+		stream->tls_sid = 0;
+		fd = http_send_request( stream->streaming_ctrl->url, 0, &stream->tls_sid, 0 );
+#else
 		fd = http_send_request( stream->streaming_ctrl->url, 0 );
+#endif
 		if( fd<0 ) return -1;
+#ifdef HAVE_GNU_TLS
+		http_hdr = http_read_response( fd, stream->tls_sid );
+#else
 		http_hdr = http_read_response( fd );
+#endif
 		if( http_hdr==NULL ) return -1;
 
 		switch( http_hdr->status_code ) {
@@ -253,6 +266,10 @@
 					ret=nop_streaming_start(stream); //recursively get streaming started
 				} else {
 					mp_msg(MSGT_NETWORK,MSGL_ERR,"Redirection failed\n");
+#ifdef HAVE_GNU_TLS
+					if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+					stream->tls_sid = 0;
+#endif
 					closesocket( fd );
 					fd = -1;
 				}
@@ -264,6 +281,10 @@
 			case 500: //Server Error
 			default:
 				mp_msg(MSGT_NETWORK,MSGL_ERR,"Server returned code %d: %s\n", http_hdr->status_code, http_hdr->reason_phrase );
+#ifdef HAVE_GNU_TLS
+				if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+				stream->tls_sid = 0;
+#endif
 				closesocket( fd );
 				fd = -1;
 				return -1;
@@ -723,14 +744,29 @@
 	do
 	{
 		redirect = 0;
-		if (fd >= 0) closesocket(fd);
+		if (fd >= 0) 
+#ifdef HAVE_GNU_TLS
+		{
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
+			closesocket( fd );
+#ifdef HAVE_GNU_TLS
+		}
+		fd = http_send_request( url, 0, &stream->tls_sid, 0 );
+#else
 		fd = http_send_request( url, 0 );
+#endif
 		if( fd<0 ) {
 			goto err_out;
 		}
 
 		http_free(http_hdr);
+#ifdef HAVE_GNU_TLS
+		http_hdr = http_read_response( fd, stream->tls_sid );
+#else
 		http_hdr = http_read_response( fd );
+#endif
 		if( http_hdr==NULL ) {
 			goto err_out;
 		}
@@ -853,7 +889,16 @@
 	} while( redirect );
 
 err_out:
-	if (fd >= 0) closesocket( fd );
+	if (fd >= 0) 
+#ifdef HAVE_GNU_TLS
+	{
+		if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+		stream->tls_sid = 0;
+#endif
+		closesocket( fd );
+#ifdef HAVE_GNU_TLS
+	}
+#endif
 	fd = -1;
 	http_free( http_hdr );
 	http_hdr = NULL;
@@ -879,7 +924,15 @@
 	if(nop_streaming_start( stream )) {
 		mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_start failed\n");
 		if (stream->fd >= 0)
+#ifdef HAVE_GNU_TLS
+		{
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
 			closesocket(stream->fd);
+#ifdef HAVE_GNU_TLS
+		}
+#endif
 		stream->fd = -1;
 		streaming_ctrl_free(stream->streaming_ctrl);
 		stream->streaming_ctrl = NULL;
@@ -904,7 +957,15 @@
 	seekable = http_streaming_start(stream, file_format);
 	if((seekable < 0) || (*file_format == DEMUXER_TYPE_ASF)) {
 		if (stream->fd >= 0)
+#ifdef HAVE_GNU_TLS
+		{
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
 			closesocket(stream->fd);
+#ifdef HAVE_GNU_TLS
+		}
+#endif
 		stream->fd = -1;
 		if (seekable == STREAM_REDIRECTED)
 			return seekable;
@@ -930,7 +991,15 @@
 	seekable = http_streaming_start(stream, file_format);
 	if(seekable < 0) {
 		if (stream->fd >= 0)
+#ifdef HAVE_GNU_TLS
+		{
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
 			closesocket(stream->fd);
+#ifdef HAVE_GNU_TLS
+		}
+#endif
 		stream->fd = -1;
 		streaming_ctrl_free(stream->streaming_ctrl);
 		stream->streaming_ctrl = NULL;
@@ -947,7 +1016,11 @@
   "Bertrand, Albeau, Reimar Doeffinger, Arpi?",
   "plain http",
   open_s1,
-  {"http", "http_proxy", "unsv", "icyx", "noicyx", NULL},
+  {"http", 
+#ifdef HAVE_GNU_TLS
+	 "https",
+#endif
+	 "http_proxy", "unsv", "icyx", "noicyx", NULL},
   NULL,
   0 // Urls are an option string
 };
@@ -958,7 +1031,11 @@
   "Bertrand, Albeu, Arpi? who?",
   "plain http, also used as fallback for many other protocols",
   open_s2,
-  {"http", "http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL},	//all the others as fallback
+  {"http", 
+#ifdef HAVE_GNU_TLS
+	 "https",
+#endif
+		"http_proxy", "pnm", "mms", "mmsu", "mmst", "rtsp", NULL},	//all the others as fallback
   NULL,
   0 // Urls are an option string
 };
Index: stream/network.c
===================================================================
--- stream/network.c	(revision 37263)
+++ stream/network.c	(working copy)
@@ -48,6 +48,10 @@
 #include "cookies.h"
 #include "url.h"
 
+#ifdef HAVE_GNU_TLS
+#include "tls.h"
+#endif
+
 /* Variables for the command line option -user, -passwd, -bandwidth,
    -user-agent and -nocookies */
 
@@ -62,7 +66,6 @@
 /* IPv6 options */
 int   network_ipv4_only_proxy = 0;
 
-
 const mime_struct_t mime_type_table[] = {
 #ifdef CONFIG_FFMPEG
 	// Flash Video
@@ -197,7 +200,11 @@
 }
 
 int
-http_send_request( URL_t *url, int64_t pos ) {
+http_send_request( URL_t *url, int64_t pos
+#ifdef HAVE_GNU_TLS
+	, int *tls_sid, int force_secure
+#endif
+) {
 	HTTP_header_t *http_hdr;
 	URL_t *server_url;
 	char str[256];
@@ -205,6 +212,24 @@
 	int ret;
 	int proxy = 0;		// Boolean
 
+#ifdef HAVE_GNU_TLS
+	int l_tls_sid = -1;
+	int tls = 0;		// Boolean
+
+	if((force_secure==1) || !strcasecmp(url->protocol, "https") ) {
+		mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - TLS enabled for HTTP request\n");
+		tls = 1;
+  }
+	
+	if((tls==1)&&(tls_sid==NULL))
+		return -1; // invalid params
+		
+	if((tls_sid!=NULL)&&((*tls_sid)>0)) { // valid session ID
+		mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - a TLS session is already open\n");
+		tls = 1;
+	}
+#endif
+
 	http_hdr = http_new_header();
 
 	if( !strcasecmp(url->protocol, "http_proxy") ) {
@@ -278,15 +303,40 @@
 		url_free( server_url );
 		server_url = NULL;
 	} else {
-		if( server_url->port==0 ) server_url->port = 80;	// Default port for the web server
+		if( server_url->port==0 )
+#ifdef HAVE_GNU_TLS
+			if(tls)
+				server_url->port = 443;
+			else
+#endif
+				server_url->port = 80;  // Default port for the web server
+#ifdef HAVE_GNU_TLS
+		if(tls && mp_gnutls_client_init() < 0) {
+			mp_msg(MSGT_NETWORK, MSGL_ERR, "Could not initialize a GNU TLS Client\n");
+			goto err_out;
+		}
+#endif
 		fd = connect2Server( server_url->hostname, server_url->port,1 );
 	}
 	if( fd<0 ) {
 		goto err_out;
 	}
+#ifdef HAVE_GNU_TLS
+	else if(tls==1) {
+		if((*tls_sid)==0) l_tls_sid = mp_gnutls_session_open(fd,NULL);
+		else { l_tls_sid = (*tls_sid); mp_gnutls_session_set_int(l_tls_sid, fd); }
+		if(l_tls_sid<=0) goto err_out;
+		if(mp_gnutls_handshake_perform(l_tls_sid,NULL) < 0) goto err_out;
+	}
+#endif
+
 	mp_msg(MSGT_NETWORK,MSGL_DBG2,"Request: [%s]\n", http_hdr->buffer );
-
-	ret = send( fd, http_hdr->buffer, http_hdr->buffer_size, DEFAULT_SEND_FLAGS );
+#ifdef HAVE_GNU_TLS
+	if(tls==1)
+		ret = mp_gnutls_send(l_tls_sid, http_hdr->buffer, http_hdr->buffer_size);
+	else
+#endif
+		ret = send( fd, http_hdr->buffer, http_hdr->buffer_size, DEFAULT_SEND_FLAGS );
 	if( ret!=(int)http_hdr->buffer_size ) {
 		mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrSendingHTTPRequest);
 		goto err_out;
@@ -293,9 +343,17 @@
 	}
 
 	http_free( http_hdr );
-
+#ifdef HAVE_GNU_TLS
+	if(tls==1)
+		(*tls_sid) = l_tls_sid;
+	else
+		(*tls_sid) = 0;
+#endif
 	return fd;
 err_out:
+#ifdef HAVE_GNU_TLS
+	if(l_tls_sid > 0) mp_gnutls_session_close(l_tls_sid);
+#endif
 	if (fd > 0) closesocket(fd);
 	http_free(http_hdr);
 	if (proxy && server_url)
@@ -304,7 +362,11 @@
 }
 
 HTTP_header_t *
-http_read_response( int fd ) {
+http_read_response( int fd 
+#ifdef HAVE_GNU_TLS
+	, int tls_sid
+#endif
+) {
 	HTTP_header_t *http_hdr;
 	char response[BUFFER_SIZE];
 	int i;
@@ -315,7 +377,12 @@
 	}
 
 	do {
-		i = recv( fd, response, BUFFER_SIZE, 0 );
+#ifdef HAVE_GNU_TLS
+		if(tls_sid > 0)
+			i = mp_gnutls_recv(tls_sid, response, BUFFER_SIZE);
+		else
+#endif
+			i = recv( fd, response, BUFFER_SIZE, 0 );
 		if( i<0 ) {
 			mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ReadFailed);
 			http_free( http_hdr );
@@ -388,11 +455,26 @@
 	int fd;
 	if( stream==NULL ) return 0;
 
+#ifdef HAVE_GNU_TLS
+	if( stream->tls_sid>0 ) {
+		mp_gnutls_session_close(stream->tls_sid);
+		stream->tls_sid = 0;
+	}
+#endif
 	if( stream->fd>0 ) closesocket(stream->fd); // need to reconnect to seek in http-stream
-	fd = http_send_request( stream->streaming_ctrl->url, pos );
+
+	fd = http_send_request( stream->streaming_ctrl->url, pos
+#ifdef HAVE_GNU_TLS
+		, &stream->tls_sid, 0 
+#endif
+		);
 	if( fd<0 ) return 0;
 
-	http_hdr = http_read_response( fd );
+	http_hdr = http_read_response( fd 
+#ifdef HAVE_GNU_TLS
+		, stream->tls_sid
+#endif
+		);
 
 	if( http_hdr==NULL ) return 0;
 
@@ -413,6 +495,10 @@
 			break;
 		default:
 			mp_msg(MSGT_NETWORK,MSGL_ERR,MSGTR_MPDEMUX_NW_ErrServerReturned, http_hdr->status_code, http_hdr->reason_phrase );
+#ifdef HAVE_GNU_TLS
+			if(stream->tls_sid>0) mp_gnutls_session_close(stream->tls_sid);
+			stream->tls_sid = 0;
+#endif
 			closesocket( fd );
 			fd = -1;
 	}
@@ -443,7 +529,11 @@
 }
 
 int
-nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl ) {
+nop_streaming_read( int fd, 
+#ifdef HAVE_GNU_TLS
+	int tls_sid, 
+#endif
+	char *buffer, int size, streaming_ctrl_t *stream_ctrl ) {
 	int len=0;
 //printf("nop_streaming_read\n");
 	if( stream_ctrl->buffer_size!=0 ) {
@@ -465,9 +555,19 @@
 
 	if( len<size ) {
 		int ret;
-		ret = recv( fd, buffer+len, size-len, 0 );
+#ifdef HAVE_GNU_TLS
+		if(tls_sid>0)
+			ret = mp_gnutls_recv(tls_sid, buffer+len, size-len);
+		else
+#endif
+			ret = recv( fd, buffer+len, size-len, 0 );
 		if( ret<0 ) {
-			mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : %s\n",strerror(errno));
+#ifdef HAVE_GNU_TLS
+			if(tls_sid>0)
+				mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : GNU TLS - %s\n",gnutls_strerror(ret));
+			else
+#endif
+				mp_msg(MSGT_NETWORK,MSGL_ERR,"nop_streaming_read error : %s\n",strerror(errno));
 			ret = 0;
 		} else if (ret == 0)
 			stream_ctrl->status = streaming_stopped_e;
Index: stream/network.h
===================================================================
--- stream/network.h	(revision 37263)
+++ stream/network.h	(working copy)
@@ -75,12 +75,21 @@
 streaming_ctrl_t *streaming_ctrl_new(void);
 int streaming_bufferize( streaming_ctrl_t *streaming_ctrl, char *buffer, int size);
 
+#ifdef HAVE_GNU_TLS
+int nop_streaming_read( int fd, int tls_sid, char *buffer, int size, streaming_ctrl_t *stream_ctrl );
+#else
 int nop_streaming_read( int fd, char *buffer, int size, streaming_ctrl_t *stream_ctrl );
+#endif
 int nop_streaming_seek( int fd, int64_t pos, streaming_ctrl_t *stream_ctrl );
 void streaming_ctrl_free( streaming_ctrl_t *streaming_ctrl );
 
+#ifdef HAVE_GNU_TLS
+int http_send_request(URL_t *url, int64_t pos, int *tls_sid, int force_secure);
+HTTP_header_t *http_read_response(int fd, int tls_sid);
+#else
 int http_send_request(URL_t *url, int64_t pos);
 HTTP_header_t *http_read_response(int fd);
+#endif
 
 int http_authenticate(HTTP_header_t *http_hdr, URL_t *url, int *auth_retry);
 URL_t* check4proxies(const URL_t *url);
Index: stream/stream.c
===================================================================
--- stream/stream.c	(revision 37263)
+++ stream/stream.c	(working copy)
@@ -52,6 +52,10 @@
 
 #include "cache2.h"
 
+#ifdef HAVE_GNU_TLS
+#include "tls.h"
+#endif
+
 static int (*stream_check_interrupt_cb)(int time) = NULL;
 
 extern const stream_info_t stream_info_bd;
@@ -306,7 +310,11 @@
   case STREAMTYPE_STREAM:
 #ifdef CONFIG_NETWORKING
     if( s->streaming_ctrl!=NULL && s->streaming_ctrl->streaming_read ) {
+#ifdef HAVE_GNU_TLS
+      len=s->streaming_ctrl->streaming_read(s->fd, s->tls_sid, buf, len, s->streaming_ctrl);
+#else
       len=s->streaming_ctrl->streaming_read(s->fd, buf, len, s->streaming_ctrl);
+#endif
       if (s->streaming_ctrl->status == streaming_stopped_e &&
           (!s->end_pos || s->pos == s->end_pos))
         s->eof = 1;
@@ -547,7 +555,15 @@
        on windows however we have to distinguish between
        network socket and file */
     if(s->url && strstr(s->url,"://"))
+#ifdef HAVE_GNU_TLS
+		{
+			if(s->tls_sid>0) mp_gnutls_session_close(s->tls_sid);
+			s->tls_sid = 0;
+#endif
       closesocket(s->fd);
+#ifdef HAVE_GNU_TLS
+		}
+#endif
     else close(s->fd);
   }
 #if HAVE_WINSOCK2_H
Index: stream/stream.h
===================================================================
--- stream/stream.h	(revision 37263)
+++ stream/stream.h	(working copy)
@@ -124,7 +124,11 @@
 	unsigned int buffer_size;
 	unsigned int buffer_pos;
 	unsigned int bandwidth;	// The downstream available
+#ifdef HAVE_GNU_TLS
+	int (*streaming_read)( int fd, int tls_sid, char *buffer, int buffer_size, struct streaming_control *stream_ctrl );
+#else
 	int (*streaming_read)( int fd, char *buffer, int buffer_size, struct streaming_control *stream_ctrl );
+#endif
 	int (*streaming_seek)( int fd, int64_t pos, struct streaming_control *stream_ctrl );
 	void *data;
 } streaming_ctrl_t;
@@ -161,6 +165,9 @@
   void (*close)(struct stream *s);
 
   int fd;   // file descriptor, see man open(2)
+#ifdef HAVE_GNU_TLS
+  int tls_sid; // GNU TLS session identifier (see tls.c for details)
+#endif
   int type; // see STREAMTYPE_*
   int flags;
   int sector_size; // sector size (seek will be aligned on this size if non 0)
Index: stream/stream_cddb.c
===================================================================
--- stream/stream_cddb.c	(revision 37263)
+++ stream/stream_cddb.c	(working copy)
@@ -393,8 +393,11 @@
         mp_msg(MSGT_DEMUX, MSGL_ERR, MSGTR_MPDEMUX_CDDB_NotAValidURL);
         goto out;
     }
-
+#ifdef HAVE_GNU_TLS
+		fd = http_send_request(url, 0, NULL, 0);
+#else
     fd = http_send_request(url,0);
+#endif
     if (fd < 0) {
         mp_msg(MSGT_DEMUX, MSGL_ERR,
                MSGTR_MPDEMUX_CDDB_FailedToSendHTTPRequest);
@@ -401,7 +404,11 @@
         goto out;
     }
 
+#ifdef HAVE_GNU_TLS
+		http_hdr = http_read_response(fd, 0);
+#else
     http_hdr = http_read_response(fd);
+#endif
     if (http_hdr == NULL) {
         mp_msg(MSGT_DEMUX, MSGL_ERR,
                MSGTR_MPDEMUX_CDDB_FailedToReadHTTPResponse);


/*
 * Transport Layer Security Implementation for MPlayer
 *
 * Copyright (C) 2014
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */ 

#ifndef MPLAYER_TLS_H
#define MPLAYER_TLS_H

#include "config.h"

#ifdef HAVE_GNU_TLS

#include <gnutls/gnutls.h>

/* TLS client data structure */
typedef struct tagGnuTLS_Client GnuTLS_Client;

/* TLS client singleton  */
extern GnuTLS_Client gnuTLSClient;

/* Code below was "borrowed" from VLC with some modifications */

int mp_gnutls_init(void);
#if (GNUTLS_VERSION_NUMBER >= 0x030300)
# define mp_gnutls_deinit() (void)0
#else
void mp_gnutls_deinit(void);
#endif

int mp_gnutls_client_init_(GnuTLS_Client *client);
void mp_gnutls_client_free_(GnuTLS_Client *client);

int mp_gnutls_handshake_perform_(GnuTLS_Client *client, int tls_id, char **restrict alp);

int mp_gnutls_session_open_(GnuTLS_Client *client, int fd, const char *const *alpn);
void mp_gnutls_session_close_(GnuTLS_Client *client, int tls_id);
void mp_gnutls_session_set_int_(GnuTLS_Client *client, int tls_id, int fd);

int mp_gnutls_send_(GnuTLS_Client *client, int tls_id, const void *buf, size_t length);
int mp_gnutls_recv_(GnuTLS_Client *client, int tls_id, void *buf, size_t length);

#define mp_gnutls_client_init() mp_gnutls_client_init_(&gnuTLSClient)
#define mp_gnutls_client_free() mp_gnutls_client_free_(&gnuTLSClient)
#define mp_gnutls_handshake_perform(i, a) mp_gnutls_handshake_perform_(&gnuTLSClient, i, a)
#define mp_gnutls_session_open(f, a) mp_gnutls_session_open_(&gnuTLSClient, f, a)
#define mp_gnutls_session_close(i) mp_gnutls_session_close_(&gnuTLSClient, i)
#define mp_gnutls_session_set_int(i, f) mp_gnutls_session_set_int_(&gnuTLSClient, i, f)
#define mp_gnutls_send(i, b, l) mp_gnutls_send_(&gnuTLSClient, i, b, l)
#define mp_gnutls_recv(i, b, l) mp_gnutls_recv_(&gnuTLSClient, i, b, l)

#endif /* HAVE_GNU_TLS */

#endif /* MPLAYER_TLS_H */
/*
 * Transport Layer Security Implementation for MPlayer
 *
 * Copyright (C) 2014
 *
 * This is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * It is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with MPlayer; if not, write to the Free Software Foundation, Inc.,
 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
 */ 

#include "config.h"

#ifdef HAVE_GNU_TLS

#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include <pthread.h>

#include <gnutls/gnutls.h>
#include <gnutls/x509.h>

#include "mp_msg.h"
#include "help_mp.h"
#include "mpcommon.h"

#include "tls.h"

struct tagGnuTLS_Client {
	int init_done;
	gnutls_certificate_credentials_t x509;
	gnutls_session_t	*openSessions;
	int	unOpenSessions, unLenOpenSessions;
};

struct tagGnuTLS_Client gnuTLSClient;

/**
 * Forward declarations
 */
char *strndup (const char *, size_t);

#if (GNUTLS_VERSION_NUMBER >= 0x030300)
/**
 * Initializes GNU TLS.
 */
int mp_gnutls_init()
{
	const char *version = gnutls_check_version ("3.3.0");
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Initializing... ");
	if (version == NULL)
	{
		mp_msg(MSGT_NETWORK, MSGL_FATAL, "GNU TLS 3.3.0 or later is required\n");
		return -1;
	}
	mp_msg(MSGT_NETWORK, MSGL_INFO, "using GNU TLS verson %s\n", version);
	return 0;
}
#else
static pthread_mutex_t gnutls_mutex;

/**
 * Initializes GNU TLS (older version).
 */
int mp_gnutls_init()
{
	const char *version = gnutls_check_version ("3.1.11");
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Initializing... ");
	if (version == NULL)
	{
		mp_msg(MSGT_NETWORK, MSGL_FATAL, "GNU TLS 3.1.11 or later is required\n");
		return -1;
	}
	mp_msg(MSGT_NETWORK, MSGL_INFO, "using GNU TLS verson %s\n", version);

	if (gnutls_check_version ("3.3.0") == NULL) // check if necessary
	{
		int err = 0;

		pthread_mutex_lock(&gnutls_mutex);
		err = gnutls_global_init();
		pthread_mutex_unlock(&gnutls_mutex);

		if (err)
		{
			mp_msg(MSGT_NETWORK, MSGL_FATAL, "GNU TLS initialisation failed\n");
			return -1;
		}
	}
	return 0;
}

/**
 * Deinitializes GNU TLS.
 */
void mp_gnutls_deinit(void)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Deinitializing...\n");
	pthread_mutex_lock(&gnutls_mutex);
	gnutls_global_deinit();
	pthread_mutex_unlock(&gnutls_mutex);
}
#endif

/**
 * Initializes client-side TLS credentials.
 */
int mp_gnutls_client_init_(struct tagGnuTLS_Client *client)
{
	int err = 0;

	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Setting up the client\n");

	if(client->init_done==1)
		return 0;
	
	if (mp_gnutls_init()<0)
		return -1;
	
  err = gnutls_certificate_allocate_credentials(&client->x509);
	if (err != 0)
	{
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - cannot allocate credentials: %s\n",
			gnutls_strerror(err));
		mp_gnutls_deinit();
		return -1;
	}

	err = gnutls_certificate_set_x509_system_trust(client->x509);
	if (err < 0)
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - cannot load trusted Certificate Authorities: %s\n",
			gnutls_strerror(err));
	else
		mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - loaded %d trusted CAs\n", err);

	gnutls_certificate_set_verify_flags(client->x509, GNUTLS_VERIFY_ALLOW_X509_V1_CA_CRT);

	client->openSessions = NULL; client->unOpenSessions = client->unLenOpenSessions = 0;
	
	client->init_done=1;

	return 0;
}

/**
 * Frees client-side TLS credentials.
 */
void mp_gnutls_client_free_(struct tagGnuTLS_Client *client)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Cleaning up the client\n");

	if(client->init_done==0)
		return;

	if(client->openSessions!=NULL) {
		for(int i =0; i < client->unOpenSessions; i++) {
			gnutls_bye(client->openSessions[i], GNUTLS_SHUT_WR);
			gnutls_deinit(client->openSessions[i]);
		}
		free(client->openSessions); client->openSessions = NULL;
	}
	
	client->unOpenSessions = client->unLenOpenSessions = 0;

	gnutls_certificate_free_credentials(client->x509);
	mp_gnutls_deinit();
	
	client->init_done=0;
}

/**
 * Performs TLS handshake.
 */
int mp_gnutls_handshake_perform_(struct tagGnuTLS_Client *client, int tls_id, char **restrict alp)
{
	int err = 0;
	gnutls_session_t *session = &client->openSessions[tls_id-1];

	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Performing handshake for session #%i\n", tls_id);

	gnutls_handshake_set_timeout(*session, GNUTLS_DEFAULT_HANDSHAKE_TIMEOUT);

#ifdef _WIN32
	WSASetLastError(0);
#endif
		/* Perform the TLS handshake */
	do {
		err = gnutls_handshake(*session);
		mp_msg(MSGT_NETWORK, MSGL_DBG3, "GNU TLS - TLS Handshake '%s'\n", gnutls_strerror(err));
	}
	while (err < 0 && gnutls_error_is_fatal(err) == 0);
	
#ifdef _WIN32
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "Winsock error %d", WSAGetLastError());
#endif

	if (err < 0) {
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - Handshake failed: '%s'\n", gnutls_strerror(err));
		return -1;
	} else {
		char *desc;
		desc = gnutls_session_get_desc(*session);
		mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Session info: '%s'\n", desc);
		gnutls_free(desc);
	}

	if (alp != NULL)
	{
#ifdef GNUTLS_ALPN_MAND
		gnutls_datum_t datum;

		err = gnutls_alpn_get_selected_protocol (*session, &datum);
		if (err == 0)
		{
			if (memchr (datum.data, 0, datum.size) != NULL)
				return -1; /* Other end is doing something fishy?! */

			*alp = strndup ((char *)datum.data, datum.size);
			if (unlikely(*alp == NULL))
				return -1;
		}
		else
#endif
			*alp = NULL;
	}
	return 0;
}

/**
 * Opens a new GNU TLS session
 */
int mp_gnutls_session_open_(struct tagGnuTLS_Client *client, int fd, const char *const *alpn)
{
	int err = 0;
	const char *errp = NULL;
	gnutls_session_t *session = NULL;
	
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Opening a new session... ");
	
	if(client->unOpenSessions >= client->unLenOpenSessions)
	{ /* allocate more memory */
		gnutls_session_t *tmp = realloc(client->openSessions, (client->unLenOpenSessions+5)*sizeof(gnutls_session_t));
		if(NULL == tmp)
		{
			mp_msg(MSGT_NETWORK, MSGL_FATAL, MSGTR_MemAllocFailed);
			return -1;
		}
		client->openSessions = tmp;
		client->unLenOpenSessions += 5;
	}
	session = &(client->openSessions[client->unOpenSessions++]);

	err = gnutls_init (session, GNUTLS_CLIENT);
	if (err != 0)
	{
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - cannot initialize TLS session: %s\n",
			gnutls_strerror (err));
		return -1;
	}

	/* use default priorities */
	err = gnutls_set_default_priority(*session);
	if (err < 0) {
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - cannot set TLS priorities \"%s\": %s\n", errp,
			gnutls_strerror (err));
		goto error;
	}

	err = gnutls_credentials_set (*session, GNUTLS_CRD_CERTIFICATE, client->x509);
	if (err < 0)
	{
		mp_msg(MSGT_NETWORK, MSGL_ERR, "GNU TLS - cannot set TLS session credentials: %s\n",
			gnutls_strerror (err));
		goto error;
	}

	if (alpn != NULL)
	{
#ifdef GNUTLS_ALPN_MAND
		gnutls_datum_t *protv = NULL;
		unsigned protc = 0;

		while (*alpn != NULL)
		{
			gnutls_datum_t *n = realloc(protv, sizeof (*protv) * (protc + 1));
			if (n == NULL)
			{
				free(protv);
				goto error;
			}
			protv = n;

			protv[protc].data = (void *)*alpn;
			protv[protc].size = strlen(*alpn);
			protc++;
			alpn++;
		}

		err = gnutls_alpn_set_protocols(*session, protv, protc, 0);
		free (protv);
#else
		goto error;
#endif
	}

	/* Set the socket descriptor */
	gnutls_transport_set_int(*session, fd);
	
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "Session #%i opened\n", client->unOpenSessions);
	
	return client->unOpenSessions;

error:
	gnutls_deinit (*session);
	client->unOpenSessions--;
	return -1;
}

/**
 * Terminates TLS session and releases session data.
 * You still have to close the socket yourself.
 */
void mp_gnutls_session_close_(struct tagGnuTLS_Client *client, int tls_id)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Closing session #%i\n", tls_id);

	gnutls_bye (client->openSessions[tls_id-1], GNUTLS_SHUT_WR);
	gnutls_deinit (client->openSessions[tls_id-1]);
	
	if(tls_id < client->unOpenSessions)
		memmove(client->openSessions+tls_id-1, client->openSessions+tls_id, (client->unOpenSessions-tls_id-2)*sizeof(gnutls_session_t*));
	client->unOpenSessions--;
	
	if(client->unOpenSessions == 0)
		mp_gnutls_client_free_(client);
}

/**
 * Set a new Socket handle for a given TLS session.
 */
void mp_gnutls_session_set_int_(GnuTLS_Client *client, int tls_id, int fd)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG2, "GNU TLS - Setting new descriptor for session #%i\n", tls_id);
  gnutls_transport_set_int(client->openSessions[tls_id-1], fd);
}

/**
 * Sends data through a TLS session.
 */
int mp_gnutls_send_(struct tagGnuTLS_Client *client, int tls_id, const void *buf, size_t length)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG5, "GNU TLS - Sending %zu bytes of data for session #%i\n", length, tls_id);
	return gnutls_record_send(client->openSessions[tls_id-1], buf, length);
}


/**
 * Receives data through a TLS session.
 */
int mp_gnutls_recv_(struct tagGnuTLS_Client *client, int tls_id, void *buf, size_t length)
{
	mp_msg(MSGT_NETWORK, MSGL_DBG5, "GNU TLS - Receiving %zu bytes of data for session #%i\n", length, tls_id);
	return gnutls_record_recv(client->openSessions[tls_id-1], buf, length);
}

/**
 * Implement the strndup function.
 * Copyright (C) 2005 Free Software Foundation, Inc.
 * Written by Kaveh R. Ghazi <ghazi@xxxxxxxxxxxxxxxx>.
 * Is part of the libiberty library.
 */
char *strndup (const char *s, size_t n)
{
  char *result;
  size_t len = strlen (s);

  if (n < len)
    len = n;

  result = (char *) malloc (len + 1);
  if (!result)
    return 0;

  result[len] = '\0';
  return (char *) memcpy (result, s, len);
}

#endif /* HAVE_GNU_TLS */
_______________________________________________
MPlayer-dev-eng mailing list
MPlayer-dev-eng@xxxxxxxxxxxx
https://lists.mplayerhq.hu/mailman/listinfo/mplayer-dev-eng