ref: 98c7eb717003c981071a376a8bbb52f9d1d5e1f4
parent: b9e59d59ba24270b228d32e956c7d4ce5279250b
author: Timothy B. Terriberry <tterribe@xiph.org>
date: Sun Sep 23 20:27:42 EDT 2012
A bunch of minor improvements. The most important for the https backend: - Implement RFC 6066 Server Name Indication. - Implement SSL session resumption. This gives less of a speed improvement than you might think.
--- a/include/opusfile.h
+++ b/include/opusfile.h
@@ -99,6 +99,7 @@
See each individual function for more details on what a specific error code
means in that context.*/
/*@{*/
+
/**A request did not succeed.*/
#define OP_FALSE (-1)
/*Currently not used externally.*/
@@ -142,6 +143,7 @@
#define OP_ENOSEEK (-138)
/**The first or last granule position of a link failed basic validity checks.*/
#define OP_EBADTIMESTAMP (-139)
+
/*@}*/
/*@}*/
@@ -395,7 +397,8 @@
/**\defgroup url_flags URL Reading Flags*/
/*@{*/
-/**\name Flags for op_url_create_with_proxy() and associated functions.
+/**\name URL reading flags
+ Flags for op_url_create_with_proxy() and associated functions.
These may be expanded in the future.*/
/*@{*/
--- a/src/http.c
+++ b/src/http.c
@@ -26,8 +26,10 @@
OP_ASSERT(_start<=_end);
len=_end-_start;
ret=(char *)_ogg_malloc(sizeof(*ret)*(len+1));
- memcpy(ret,_start,sizeof(*ret)*(len));
- ret[len]='\0';
+ if(OP_LIKELY(ret!=NULL)){
+ memcpy(ret,_start,sizeof(*ret)*(len));
+ ret[len]='\0';
+ }
return ret;
}
@@ -493,6 +495,8 @@
OpusHTTPConn conns[OP_NCONNS_MAX];
/*The context object used as a framework for TLS/SSL functions.*/
SSL_CTX *ssl_ctx;
+ /*The cached session to reuse for future connections.*/
+ SSL_SESSION *ssl_session;
/*The LRU list (ordered from MRU to LRU) of connections.*/
OpusHTTPConn *lru_head;
/*The free list.*/
@@ -536,6 +540,7 @@
pnext=&_stream->conns[ci].next;
}
_stream->ssl_ctx=NULL;
+ _stream->ssl_session=NULL;
_stream->lru_head=NULL;
op_parsed_url_init(&_stream->url);
op_sb_init(&_stream->request);
@@ -555,6 +560,7 @@
static void op_http_stream_clear(OpusHTTPStream *_stream){
while(_stream->lru_head!=NULL)op_http_conn_close(_stream,_stream->lru_head);
+ if(_stream->ssl_session!=NULL)SSL_SESSION_free(_stream->ssl_session);
if(_stream->ssl_ctx!=NULL)SSL_CTX_free(_stream->ssl_ctx);
op_sb_clear(&_stream->request);
op_parsed_url_clear(&_stream->url);
@@ -583,11 +589,11 @@
/*Try to start a connection to the next address in the given list of a given
type.
- _fd: The socket to connect with.
- [out] _addr: A pointer to the list of addresses.
- This will be advanced to the first one that matches the given
- address family (possibly the current one).
- _ai_family: The address family to connect to.
+ _fd: The socket to connect with.
+ [inout] _addr: A pointer to the list of addresses.
+ This will be advanced to the first one that matches the given
+ address family (possibly the current one).
+ _ai_family: The address family to connect to.
Return: 1 If the connection was successful.
0 If the connection is in progress.
OP_FALSE If the connection failed and there were no more addresses
@@ -741,11 +747,25 @@
if(OP_LIKELY(ssl_conn!=NULL)){
ssl_bio=BIO_new_socket(fds[pi].fd,BIO_NOCLOSE);
if(OP_LIKELY(ssl_bio!=NULL)){
+# if !defined(OPENSSL_NO_TLSEXT)
+ /*Support for RFC 6066 Server Name Indication.*/
+ SSL_set_tlsext_host_name(ssl_conn,_stream->url.host);
+# endif
+ /*Resume a previous session if available.*/
+ if(_stream->ssl_session!=NULL){
+ SSL_set_session(ssl_conn,_stream->ssl_session);
+ }
SSL_set_bio(ssl_conn,ssl_bio,ssl_bio);
SSL_set_connect_state(ssl_conn);
ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_connect);
if(OP_LIKELY(ret>0)){
- ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_do_handshake);
+ if(_stream->ssl_session==NULL){
+ /*Save a session for later resumption.*/
+ ret=op_do_ssl_step(ssl_conn,fds[pi].fd,SSL_do_handshake);
+ if(OP_LIKELY(ret>0)){
+ _stream->ssl_session=SSL_get1_session(ssl_conn);
+ }
+ }
if(OP_LIKELY(ret>0)){
_conn->ssl_conn=ssl_conn;
_conn->fd=fds[pi].fd;
@@ -911,10 +931,11 @@
opus_int64 read_delta_bytes;
opus_int64 read_rate;
int ret;
+ read_delta_bytes=_conn->read_bytes;
+ if(read_delta_bytes<=0)return;
ret=ftime(&read_time);
OP_ASSERT(!ret);
read_delta_ms=op_time_diff_ms(&read_time,&_conn->read_time);
- read_delta_bytes=_conn->read_bytes;
read_rate=_conn->read_rate;
read_delta_ms=OP_MAX(read_delta_ms,1);
read_rate+=read_delta_bytes*1000/read_delta_ms-read_rate+4>>3;
@@ -1252,6 +1273,11 @@
addrs=NULL;
if(last_host!=NULL){
if(strcmp(last_host,host)==0&&last_port==port)addrs=&_stream->addr_info;
+ else if(_stream->ssl_session!=NULL){
+ /*Forget any cached SSL session from the last host.*/
+ SSL_SESSION_free(_stream->ssl_session);
+ _stream->ssl_session=NULL;
+ }
if(last_host!=_proxy_host)_ogg_free((void *)last_host);
}
last_host=host;
@@ -1588,7 +1614,10 @@
if(_size!=1){
ptrdiff_t n;
nread=0;
- /*Read individual items one at a time.*/
+ /*libopusfile doesn't read multi-byte items, but our abstract stream API
+ requires it for stdio compatibility.
+ Implement it for completeness' sake by reading individual items one at a
+ time.*/
do{
ptrdiff_t nread_item;
nread_item=0;
@@ -1794,7 +1823,7 @@
char *unescaped_path;
void *ret;
unescaped_path=op_string_dup(path);
- if(unescaped_path==NULL)return NULL;
+ if(OP_UNLIKELY(unescaped_path==NULL))return NULL;
ret=op_fopen(_cb,op_unescape_url_component(unescaped_path),"rb");
_ogg_free(unescaped_path);
return ret;
@@ -1805,7 +1834,7 @@
OpusHTTPStream *stream;
int ret;
stream=(OpusHTTPStream *)_ogg_malloc(sizeof(*stream));
- if(stream==NULL)return NULL;
+ if(OP_UNLIKELY(stream==NULL))return NULL;
op_http_stream_init(stream);
ret=op_http_stream_open(stream,_url,_flags,
_proxy_host,_proxy_port,_proxy_user,_proxy_pass);