Bug 1117984: added proxy connection state enum. r=bwc draft
authorNils Ohlmeier [:drno] <drno@ohlmeier.org>
Wed, 20 Jan 2016 15:55:35 -0800
changeset 324944 46ddbc54e9bd7d9d543b12cfe6147fa80e80f742
parent 324744 d6d81655dd9e146c300a64c0fcaeb04ca3300a19
child 513423 72c29c4c47237d113d61c78a2902301c93a3b9f7
push id9950
push userdrno@ohlmeier.org
push dateSun, 24 Jan 2016 18:17:37 +0000
reviewersbwc
bugs1117984
milestone46.0a1
Bug 1117984: added proxy connection state enum. r=bwc
media/mtransport/third_party/nICEr/src/ice/ice_socket.c
media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c
--- a/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
+++ b/media/mtransport/third_party/nICEr/src/ice/ice_socket.c
@@ -60,17 +60,17 @@ static void nr_ice_socket_readable_cb(NR
 
     r_log(LOG_ICE,LOG_DEBUG,"ICE(%s): Socket ready to read",sock->ctx->label);
 
     /* Re-arm first! */
     if (sock->type != NR_ICE_SOCKET_TYPE_STREAM_TCP)
       NR_ASYNC_WAIT(s,how,nr_ice_socket_readable_cb,cb_arg);
 
     if(r=nr_socket_recvfrom(sock->sock,buf,sizeof(buf),&len_s,0,&addr)){
-      if (r != R_WOULDBLOCK && (sock->type == NR_ICE_SOCKET_TYPE_STREAM_TURN)) {
+      if (r != R_WOULDBLOCK && (sock->type != NR_ICE_SOCKET_TYPE_DGRAM)) {
         /* Report this error upward. Bug 946423 */
         r_log(LOG_ICE,LOG_ERR,"ICE(%s): Error %d on reliable socket. Abandoning.",sock->ctx->label, r);
         NR_ASYNC_CANCEL(s, NR_ASYNC_WAIT_READ);
       }
       return;
     }
 
     /* Deal with the fact that sizeof(int) and sizeof(size_t) may not
--- a/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
+++ b/media/mtransport/third_party/nICEr/src/net/nr_proxy_tunnel.c
@@ -42,23 +42,29 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 #define MAX_HTTP_CONNECT_ADDR_SIZE 256
 #define MAX_HTTP_CONNECT_BUFFER_SIZE 1024
 #define MAX_ALPN_LENGTH 64
 #ifndef CRLF
 #define CRLF "\r\n"
 #endif
 #define END_HEADERS CRLF CRLF
 
+typedef enum {
+  PROXY_TUNNEL_NONE=0,
+  PROXY_TUNNEL_REQUESTED,
+  PROXY_TUNNEL_CONNECTED,
+  PROXY_TUNNEL_CLOSED,
+  PROXY_TUNNEL_FAILED
+} nr_socket_proxy_tunnel_state;
+
 typedef struct nr_socket_proxy_tunnel_ {
   nr_proxy_tunnel_config *config;
   nr_socket *inner;
   nr_transport_addr remote_addr;
-  int connect_requested;
-  int connect_answered;
-  int connect_failed;
+  nr_socket_proxy_tunnel_state state;
   char buffer[MAX_HTTP_CONNECT_BUFFER_SIZE];
   size_t buffered_bytes;
   void *resolver_handle;
 } nr_socket_proxy_tunnel;
 
 typedef struct nr_socket_wrapper_factory_proxy_tunnel_ {
   nr_proxy_tunnel_config *config;
 } nr_socket_wrapper_factory_proxy_tunnel;
@@ -138,17 +144,17 @@ static int send_http_connect(nr_socket_p
   }
 
   if (bytes_sent < offset) {
     /* TODO(bug 1116583): buffering and wait for */
     r_log(LOG_GENERIC,LOG_DEBUG,"send_http_connect should be buffering %lu", (unsigned long)bytes_sent);
     ABORT(R_IO_ERROR);
   }
 
-  sock->connect_requested = 1;
+  sock->state = PROXY_TUNNEL_REQUESTED;
 
   _status = 0;
 abort:
   return(_status);
 }
 
 static char *find_http_terminator(char *response, size_t len)
 {
@@ -168,16 +174,19 @@ static char *find_http_terminator(char *
 static int parse_http_response(char *begin, char *end, unsigned int *status)
 {
   size_t len = end - begin;
   char response[MAX_HTTP_CONNECT_BUFFER_SIZE + 1];
 
   // len should *never* be greater than nr_socket_proxy_tunnel::buffered_bytes.
   // Which in turn should never be greater nr_socket_proxy_tunnel::buffer size.
   assert(len <= MAX_HTTP_CONNECT_BUFFER_SIZE);
+  if (len > MAX_HTTP_CONNECT_BUFFER_SIZE) {
+    return R_BAD_DATA;
+  }
 
   memcpy(response, begin, len);
   response[len] = '\0';
 
   // http://www.rfc-editor.org/rfc/rfc7230.txt
   // status-line    = HTTP-version SP status-code SP reason-phrase CRLF
   // HTTP-version   = HTTP-name "/" DIGIT "." DIGIT
   // HTTP-name      = "HTTP" ; "HTTP", case-sensitive
@@ -244,16 +253,20 @@ static int nr_socket_proxy_tunnel_resolv
 
   if (proxy_addr) {
     r_log(LOG_GENERIC,LOG_DEBUG,"Resolved proxy address %s -> %s",
         sock->config->proxy_host, proxy_addr->as_string);
   }
   else {
     r_log(LOG_GENERIC,LOG_WARNING,"Failed to resolve proxy %s",
         sock->config->proxy_host);
+    /* TODO: Mozilla bug 1241758: because of the callback the return value goes
+     * nowhere, so we can't mark the candidate as failed, so everything depends
+     * on the overall timeouts in this case. */
+    sock->state = PROXY_TUNNEL_FAILED;
     ABORT(R_NOT_FOUND);
   }
 
   if ((r=nr_socket_connect(sock->inner, proxy_addr))) {
     ABORT(r);
   }
 
   _status = 0;
@@ -331,23 +344,30 @@ abort:
 int nr_socket_proxy_tunnel_write(void *obj, const void *msg, size_t len,
                                  size_t *written)
 {
   int r, _status;
   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_write");
 
-  if (!sock->connect_requested) {
+  if (sock->state >= PROXY_TUNNEL_CLOSED) {
+    return R_FAILED;
+  }
+
+  if (sock->state == PROXY_TUNNEL_NONE) {
     if ((r=send_http_connect(sock))) {
       ABORT(r);
     }
   }
 
-  /* TODO (bug 1117984): we cannot assume it's safe to write until we receive a response. */
+  if (sock->state != PROXY_TUNNEL_CONNECTED) {
+    return R_WOULDBLOCK;
+  }
+
   if ((r=nr_socket_write(sock->inner, msg, len, written, 0))) {
     ABORT(r);
   }
 
   _status=0;
 abort:
   return(_status);
 }
@@ -361,21 +381,21 @@ int nr_socket_proxy_tunnel_read(void *ob
   size_t pending;
   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
   unsigned int http_status;
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_read");
 
   *len = 0;
 
-  if (sock->connect_failed) {
+  if (sock->state >= PROXY_TUNNEL_CLOSED) {
     return R_FAILED;
   }
 
-  if (sock->connect_answered) {
+  if (sock->state == PROXY_TUNNEL_CONNECTED) {
     return nr_socket_read(sock->inner, buf, maxlen, len, 0);
   }
 
   if (sock->buffered_bytes >= sizeof(sock->buffer)) {
     r_log(LOG_GENERIC,LOG_ERR,"buffer filled waiting for CONNECT response");
     assert(sock->buffered_bytes == sizeof(sock->buffer));
     ABORT(R_INTERNAL);
   }
@@ -386,61 +406,63 @@ int nr_socket_proxy_tunnel_read(void *ob
   if ((r=nr_socket_read(sock->inner, sock->buffer + sock->buffered_bytes,
           maxlen_int, &bytes_read, 0))) {
     ABORT(r);
   }
 
   sock->buffered_bytes += bytes_read;
 
   if (http_term = find_http_terminator(sock->buffer, sock->buffered_bytes)) {
-    sock->connect_answered = 1;
-
     if ((r = parse_http_response(sock->buffer, http_term, &http_status))) {
       ABORT(r);
     }
 
     /* TODO (bug 1115934): Handle authentication challenges. */
     if (http_status < 200 || http_status >= 300) {
       r_log(LOG_GENERIC,LOG_ERR,"nr_socket_proxy_tunnel_read unable to connect %u",
             http_status);
       ABORT(R_FAILED);
     }
 
+    sock->state = PROXY_TUNNEL_CONNECTED;
+
     ptr = http_term + strlen(END_HEADERS);
     pending = sock->buffered_bytes - (ptr - sock->buffer);
 
     if (pending == 0) {
       ABORT(R_WOULDBLOCK);
     }
 
     assert(pending <= maxlen);
     *len = pending;
 
     memcpy(buf, ptr, *len);
   }
 
   _status=0;
 abort:
   if (_status && _status != R_WOULDBLOCK) {
-      sock->connect_failed = 1;
+      sock->state = PROXY_TUNNEL_FAILED;
   }
   return(_status);
 }
 
 int nr_socket_proxy_tunnel_close(void *obj)
 {
   nr_socket_proxy_tunnel *sock = (nr_socket_proxy_tunnel*)obj;
 
   r_log(LOG_GENERIC,LOG_DEBUG,"nr_socket_proxy_tunnel_close");
 
   if (sock->resolver_handle) {
     nr_resolver_cancel(sock->config->resolver, sock->resolver_handle);
     sock->resolver_handle = 0;
   }
 
+  sock->state = PROXY_TUNNEL_CLOSED;
+
   return nr_socket_close(sock->inner);
 }
 
 int nr_proxy_tunnel_config_create(nr_proxy_tunnel_config **configpp)
 {
   int _status;
   nr_proxy_tunnel_config *configp=0;
 
--- a/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c
+++ b/media/mtransport/third_party/nICEr/src/stun/nr_socket_buffered_stun.c
@@ -519,16 +519,20 @@ abort:
 }
 
 static void nr_socket_buffered_stun_writable_cb(NR_SOCKET s, int how, void *arg)
 {
   nr_socket_buffered_stun *sock = (nr_socket_buffered_stun *)arg;
   int r,_status;
   nr_p_buf *n1, *n2;
 
+  if (sock->read_state == NR_ICE_SOCKET_READ_FAILED) {
+    ABORT(R_FAILED);
+  }
+
   /* Try to flush */
   STAILQ_FOREACH_SAFE(n1, &sock->pending_writes, entry, n2) {
     size_t written = 0;
 
     if ((r=nr_socket_write(sock->inner, n1->data + n1->r_offset,
                            n1->length - n1->r_offset,
                            &written, 0))) {