shithub: opusfile

Download patch

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);