trafficserver-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From shinr...@apache.org
Subject [trafficserver] branch master updated: Fix SSL handshake problems.
Date Fri, 02 Jun 2017 13:20:30 GMT
This is an automated email from the ASF dual-hosted git repository.

shinrich pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

The following commit(s) were added to refs/heads/master by this push:
       new  c128363   Fix SSL handshake problems.
c128363 is described below

commit c128363e2ce3ad435769221466627f7fbff86cb8
Author: Susan Hinrichs <shinrich@spellhotel.corp.ne1.yahoo.com>
AuthorDate: Thu May 18 15:08:21 2017 +0000

    Fix SSL handshake problems.
---
 iocore/net/SSLNetVConnection.cc         | 308 ++++++++++++++---------------
 tests/gold_tests/tls/gold/ssl-post.gold |   2 +
 tests/gold_tests/tls/ssl-post.c         | 330 ++++++++++++++++++++++++++++++++
 tests/gold_tests/tls/ssl/server.key     |  15 ++
 tests/gold_tests/tls/ssl/server.pem     |  32 ++++
 tests/gold_tests/tls/tls.test.py        | 101 ++++++++++
 6 files changed, 634 insertions(+), 154 deletions(-)

diff --git a/iocore/net/SSLNetVConnection.cc b/iocore/net/SSLNetVConnection.cc
index 8d64262..f36554a 100644
--- a/iocore/net/SSLNetVConnection.cc
+++ b/iocore/net/SSLNetVConnection.cc
@@ -323,79 +323,63 @@ ssl_read_from_net(SSLNetVConnection *sslvc, EThread *lthread, int64_t
&ret)
 int64_t
 SSLNetVConnection::read_raw_data()
 {
-  int64_t r      = 0;
-  int64_t toread = INT_MAX;
-
   // read data
-  int64_t rattempted = 0, total_read = 0;
-  unsigned niov = 0;
-  IOVec tiovec[NET_MAX_IOV];
-  if (toread) {
-    IOBufferBlock *b = this->handShakeBuffer->first_write_block();
-    do {
-      niov       = 0;
-      rattempted = 0;
-      while (b && niov < NET_MAX_IOV) {
-        int64_t a = b->write_avail();
-        if (a > 0) {
-          tiovec[niov].iov_base = b->_end;
-          int64_t togo          = toread - total_read - rattempted;
-          if (a > togo) {
-            a = togo;
-          }
-          tiovec[niov].iov_len = a;
-          rattempted += a;
-          niov++;
-          if (a >= togo) {
-            break;
-          }
-        }
-        b = b->next.get();
-      }
-
-      // If there was no room to write into the buffer then skip the read
-      if (niov > 0) {
-        ink_assert(niov > 0);
-        ink_assert(niov <= countof(tiovec));
-        r = socketManager.readv(this->con.fd, &tiovec[0], niov);
+  int64_t r          = 0;
+  int64_t total_read = 0;
+  int64_t rattempted = 0;
+  char *buffer       = 0;
+  int buf_len;
+  IOBufferBlock *b = this->handShakeBuffer->first_write_block();
+
+  rattempted = b->write_avail();
+  while (rattempted) {
+    buffer  = b->_end;
+    buf_len = rattempted;
+    b       = b->next.get();
+
+    r = socketManager.read(this->con.fd, buffer, buf_len);
+    NET_INCREMENT_DYN_STAT(net_calls_to_read_stat);
+    total_read += rattempted;
+
+    // last read failed or was incomplete
+    if (r != rattempted || !b)
+      break;
 
-        NET_INCREMENT_DYN_STAT(net_calls_to_read_stat);
-        total_read += rattempted;
-      } else { // No more space to write, break out
-        r = 0;
-        break;
-      }
-    } while (rattempted && r == rattempted && total_read < toread);
+    rattempted = b->write_avail();
+  }
 
-    // if we have already moved some bytes successfully, summarize in r
-    if (total_read != rattempted) {
-      if (r <= 0) {
-        r = total_read - rattempted;
-      } else {
-        r = total_read - rattempted + r;
-      }
-    }
-    // check for errors
-    if (r <= 0) {
-      if (r == -EAGAIN || r == -ENOTCONN) {
-        NET_INCREMENT_DYN_STAT(net_calls_to_read_nodata_stat);
-      }
-      return r;
-    }
-    NET_SUM_DYN_STAT(net_read_bytes_stat, r);
+  // If we have already moved some bytes successfully, adjust total_read to reflect reality
+  // If any read succeeded, we should return success
+  if (r != rattempted) {
+    if (r <= 0)
+      r = total_read - rattempted;
+    else
+      r = total_read - rattempted + r;
+  }
+  NET_SUM_DYN_STAT(net_read_bytes_stat, r);
 
+  if (r > 0) {
     this->handShakeBuffer->fill(r);
+
+    char *start              = this->handShakeReader->start();
+    char *end                = this->handShakeReader->end();
+    this->handShakeBioStored = end - start;
+
+    // Sets up the buffer as a read only bio target
+    // Must be reset on each read
+    BIO *rbio = BIO_new_mem_buf(start, this->handShakeBioStored);
+    BIO_set_mem_eof_return(rbio, -1);
+    SSL_set0_rbio(this->ssl, rbio);
   }
 
-  char *start              = this->handShakeReader->start();
-  char *end                = this->handShakeReader->end();
-  this->handShakeBioStored = end - start;
+  Debug("ssl", "%p read r=%" PRId64 " total=%" PRId64 " bio=%d\n", this, r, total_read, this->handShakeBioStored);
 
-  // Sets up the buffer as a read only bio target
-  // Must be reset on each read
-  BIO *rbio = BIO_new_mem_buf(start, this->handShakeBioStored);
-  BIO_set_mem_eof_return(rbio, -1);
-  SSL_set0_rbio(this->ssl, rbio);
+  // check for errors
+  if (r <= 0) {
+    if (r == -EAGAIN || r == -ENOTCONN) {
+      NET_INCREMENT_DYN_STAT(net_calls_to_read_nodata_stat);
+    }
+  }
 
   return r;
 }
@@ -456,45 +440,60 @@ SSLNetVConnection::net_read_io(NetHandler *nh, EThread *lthread)
       ret = sslStartHandShake(SSL_EVENT_SERVER, err);
     }
     // If we have flipped to blind tunnel, don't read ahead
-    if (this->handShakeReader && this->attributes != HttpProxyPort::TRANSPORT_BLIND_TUNNEL)
{
-      // Check and consume data that has been read
-      if (BIO_eof(SSL_get_rbio(this->ssl))) {
-        this->handShakeReader->consume(this->handShakeBioStored);
-        this->handShakeBioStored = 0;
-      }
-    } else if (this->attributes == HttpProxyPort::TRANSPORT_BLIND_TUNNEL) {
-      // Now in blind tunnel. Set things up to read what is in the buffer
-      // Must send the READ_COMPLETE here before considering
-      // forwarding on the handshake buffer, so the
-      // SSLNextProtocolTrampoline has a chance to do its
-      // thing before forwarding the buffers.
-      this->readSignalDone(VC_EVENT_READ_COMPLETE, nh);
-
-      // If the handshake isn't set yet, this means the tunnel
-      // decision was make in the SNI callback.  We must move
-      // the client hello message back into the standard read.vio
-      // so it will get forwarded onto the origin server
-      if (!this->getSSLHandShakeComplete()) {
-        this->sslHandShakeComplete = true;
-
-        // Copy over all data already read in during the SSL_accept
-        // (the client hello message)
-        NetState *s            = &this->read;
-        MIOBufferAccessor &buf = s->vio.buffer;
-        int64_t r              = buf.writer()->write(this->handShakeHolder);
-        s->vio.nbytes += r;
-        s->vio.ndone += r;
-
-        // Clean up the handshake buffers
-        this->free_handshake_buffers();
-
-        if (r > 0) {
-          // Kick things again, so the data that was copied into the
-          // vio.read buffer gets processed
-          this->readSignalDone(VC_EVENT_READ_COMPLETE, nh);
+    if (this->handShakeReader) {
+      if (this->attributes != HttpProxyPort::TRANSPORT_BLIND_TUNNEL) {
+        // Check and consume data that has been read
+        if (BIO_eof(SSL_get_rbio(this->ssl))) {
+          this->handShakeReader->consume(this->handShakeBioStored);
+          this->handShakeBioStored = 0;
+          // Load up the next block if present
+          if (this->handShakeReader->is_read_avail_more_than(0)) {
+            // Setup the next iobuffer block to drain
+            char *start              = this->handShakeReader->start();
+            char *end                = this->handShakeReader->end();
+            this->handShakeBioStored = end - start;
+
+            // Sets up the buffer as a read only bio target
+            // Must be reset on each read
+            BIO *rbio = BIO_new_mem_buf(start, this->handShakeBioStored);
+            BIO_set_mem_eof_return(rbio, -1);
+            SSL_set0_rbio(this->ssl, rbio);
+          }
         }
+      } else {
+        // Now in blind tunnel. Set things up to read what is in the buffer
+        // Must send the READ_COMPLETE here before considering
+        // forwarding on the handshake buffer, so the
+        // SSLNextProtocolTrampoline has a chance to do its
+        // thing before forwarding the buffers.
+        this->readSignalDone(VC_EVENT_READ_COMPLETE, nh);
+
+        // If the handshake isn't set yet, this means the tunnel
+        // decision was make in the SNI callback.  We must move
+        // the client hello message back into the standard read.vio
+        // so it will get forwarded onto the origin server
+        if (!this->getSSLHandShakeComplete()) {
+          this->sslHandShakeComplete = 1;
+
+          // Copy over all data already read in during the SSL_accept
+          // (the client hello message)
+          NetState *s            = &this->read;
+          MIOBufferAccessor &buf = s->vio.buffer;
+          int64_t r              = buf.writer()->write(this->handShakeHolder);
+          s->vio.nbytes += r;
+          s->vio.ndone += r;
+
+          // Clean up the handshake buffers
+          this->free_handshake_buffers();
+
+          if (r > 0) {
+            // Kick things again, so the data that was copied into the
+            // vio.read buffer gets processed
+            this->readSignalDone(VC_EVENT_READ_COMPLETE, nh);
+          }
+        }
+        return; // Leave if we are tunneling
       }
-      return;
     }
     if (ret == EVENT_ERROR) {
       this->read.triggered = 0;
@@ -512,6 +511,17 @@ SSLNetVConnection::net_read_io(NetHandler *nh, EThread *lthread)
           return;
         }
       }
+      // move over to the socket if we haven't already
+      if (this->handShakeBuffer) {
+        ink_release_assert(BIO_eof(SSL_get_rbio(this->ssl)) && !handShakeReader->is_read_avail_more_than(0));
+        // Done with the buffer after the first exchange, convert over to the socket buffer
+        BIO *rbio = BIO_new_fd(this->get_socket(), BIO_NOCLOSE);
+        BIO_set_mem_eof_return(rbio, -1);
+        SSL_set0_rbio(this->ssl, rbio);
+        free_handshake_buffers();
+      } else {
+        Debug("ssl", "Want read from socket");
+      }
       read.triggered = 0;
       nh->read_ready_list.remove(this);
       readReschedule(nh);
@@ -546,36 +556,7 @@ SSLNetVConnection::net_read_io(NetHandler *nh, EThread *lthread)
   }
 
   // At this point we are at the post-handshake SSL processing
-  // If the read BIO is not already a socket, consider changing it
-  if (this->handShakeReader) {
-    // Check out if there is anything left in the current bio
-    if (!BIO_eof(SSL_get_rbio(this->ssl))) {
-      // Still data remaining in the current BIO block
-    } else {
-      // Consume what SSL has read so far.
-      this->handShakeReader->consume(this->handShakeBioStored);
-
-      // If we are empty now, switch over
-      if (this->handShakeReader->read_avail() <= 0) {
-        // Switch the read bio over to a socket bio
-        SSL_set_rfd(this->ssl, this->get_socket());
-        this->free_handshake_buffers();
-      } else {
-        // Setup the next iobuffer block to drain
-        char *start              = this->handShakeReader->start();
-        char *end                = this->handShakeReader->end();
-        this->handShakeBioStored = end - start;
-
-        // Sets up the buffer as a read only bio target
-        // Must be reset on each read
-        BIO *rbio = BIO_new_mem_buf(start, this->handShakeBioStored);
-        BIO_set_mem_eof_return(rbio, -1);
-        SSL_set0_rbio(this->ssl, rbio);
-      }
-    }
-  }
-  // Otherwise, we already replaced the buffer bio with a socket bio
-
+  //
   // not sure if this do-while loop is really needed here, please replace
   // this comment if you know
   do {
@@ -1069,19 +1050,47 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
     sslHandShakeComplete = true;
     return EVENT_DONE;
   }
-
-  int retval = 1; // Initialze with a non-error value
-
   // All the pre-accept hooks have completed, proceed with the actual accept.
-  if (BIO_eof(SSL_get_rbio(this->ssl))) { // No more data in the buffer
-    // Read from socket to fill in the BIO buffer with the
-    // raw handshake data before calling the ssl accept calls.
-    retval = this->read_raw_data();
-    if (retval == 0) {
-      // EOF, go away, we stopped in the handshake
-      SSLDebugVC(this, "SSL handshake error: EOF");
-      return EVENT_ERROR;
-    }
+  if (this->handShakeReader) {
+    if (BIO_eof(SSL_get_rbio(this->ssl))) { // No more data in the buffer
+      // Is this the first read?
+      if (!this->handShakeReader->is_read_avail_more_than(0)) {
+        Debug("ssl", "%p first read\n", this);
+        // Read from socket to fill in the BIO buffer with the
+        // raw handshake data before calling the ssl accept calls.
+        int retval = this->read_raw_data();
+        if (retval < 0) {
+          if (retval == -EAGAIN) {
+            // No data at the moment, hang tight
+            // SSLDebugVC(this, "SSL handshake: EAGAIN");
+            return SSL_HANDSHAKE_WANT_READ;
+          } else {
+            // An error, make us go away
+            SSLDebugVC(this, "SSL handshake error: read_retval=%d", retval);
+            return EVENT_ERROR;
+          }
+        } else if (retval == 0) {
+          // EOF, go away, we stopped in the handshake
+          SSLDebugVC(this, "SSL handshake error: EOF");
+          return EVENT_ERROR;
+        }
+      } else {
+        this->handShakeReader->consume(this->handShakeBioStored);
+        this->handShakeBioStored = 0;
+        // There is more data in the buffer, reset the memory buffer
+        if (this->handShakeReader->is_read_avail_more_than(0)) {
+          char *start              = this->handShakeReader->start();
+          char *end                = this->handShakeReader->end();
+          this->handShakeBioStored = end - start;
+
+          // Sets up the buffer as a read only bio target
+          // Must be reset on each read
+          BIO *rbio = BIO_new_mem_buf(start, this->handShakeBioStored);
+          BIO_set_mem_eof_return(rbio, -1);
+          SSL_set0_rbio(this->ssl, rbio);
+        }
+      }
+    } // Still data in the BIO
   }
 
   ssl_error_t ssl_error = SSLAccept(ssl);
@@ -1092,7 +1101,7 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
     SSLDebugVC(this, "SSL handshake error: %s (%d), errno=%d", SSLErrorName(ssl_error), ssl_error,
err);
 
     // start a blind tunnel if tr-pass is set and data does not look like ClientHello
-    char *buf = handShakeBuffer->buf();
+    char *buf = handShakeBuffer ? handShakeBuffer->buf() : NULL;
     if (getTransparentPassThrough() && buf && *buf != SSL_OP_HANDSHAKE) {
       SSLDebugVC(this, "Data does not look like SSL handshake, starting blind tunnel");
       this->attributes     = HttpProxyPort::TRANSPORT_BLIND_TUNNEL;
@@ -1178,15 +1187,6 @@ SSLNetVConnection::sslServerHandShakeEvent(int &err)
 
   case SSL_ERROR_WANT_READ:
     TraceIn(trace, get_remote_addr(), get_remote_port(), "SSL server handshake ERROR_WANT_READ");
-    if (retval == -EAGAIN) {
-      // No data at the moment, hang tight
-      SSLDebugVC(this, "SSL handshake: EAGAIN");
-      return SSL_HANDSHAKE_WANT_READ;
-    } else if (retval < 0) {
-      // An error, make us go away
-      SSLDebugVC(this, "SSL handshake error: read_retval=%d", retval);
-      return EVENT_ERROR;
-    }
     return SSL_HANDSHAKE_WANT_READ;
 
 // This value is only defined in openssl has been patched to
diff --git a/tests/gold_tests/tls/gold/ssl-post.gold b/tests/gold_tests/tls/gold/ssl-post.gold
new file mode 100644
index 0000000..b71b025
--- /dev/null
+++ b/tests/gold_tests/tls/gold/ssl-post.gold
@@ -0,0 +1,2 @@
+Sent request
+All threads finished
diff --git a/tests/gold_tests/tls/ssl-post.c b/tests/gold_tests/tls/ssl-post.c
new file mode 100644
index 0000000..e4c9f4f
--- /dev/null
+++ b/tests/gold_tests/tls/ssl-post.c
@@ -0,0 +1,330 @@
+/** @file
+
+  SSL post test client
+
+  @section license License
+
+  Licensed to the Apache Software Foundation (ASF) under one
+  or more contributor license agreements.  See the NOTICE file
+  distributed with this work for additional information
+  regarding copyright ownership.  The ASF licenses this file
+  to you under the Apache License, Version 2.0 (the
+  "License"); you may not use this file except in compliance
+  with the License.  You may obtain a copy of the License at
+
+      http://www.apache.org/licenses/LICENSE-2.0
+
+  Unless required by applicable law or agreed to in writing, software
+  distributed under the License is distributed on an "AS IS" BASIS,
+  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  See the License for the specific language governing permissions and
+  limitations under the License.
+
+ */
+
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <openssl/ssl.h>
+#include <fcntl.h>
+#include <netinet/tcp.h>
+#include <pthread.h>
+
+#define NUM_THREADS 10
+
+char req_buf[10000];
+char post_buf[1000];
+
+pthread_mutex_t *mutex_buf = NULL;
+
+struct thread_info 
+{
+  struct addrinfo *result, *rp;
+  SSL_SESSION *session;
+}; 
+
+void
+SSL_locking_callback(int mode, int type, const char *file, int line)
+{
+  if (mode & CRYPTO_LOCK) {
+     pthread_mutex_lock(&mutex_buf[type]);
+  } else if (mode & CRYPTO_UNLOCK) {
+     pthread_mutex_unlock(&mutex_buf[type]);
+  } else {
+     printf("invalid SSL locking mode 0x%x\n", mode);
+  }
+}
+
+void
+SSL_pthreads_thread_id(CRYPTO_THREADID *id)
+{
+  CRYPTO_THREADID_set_numeric(id, (unsigned long)pthread_self());
+}
+
+void *spawn_same_session_send(void *arg) 
+{
+  struct thread_info *tinfo = (struct thread_info *)arg;
+
+  // Start again, but with the session set this time
+  int sfd = socket(tinfo->rp->ai_family, tinfo->rp->ai_socktype,
+                   tinfo->rp->ai_protocol);
+  if (sfd == -1) 
+  {
+    printf("Failed to get socket");
+    perror("Failed");
+    pthread_exit((void *)1);
+  }
+  if (connect(sfd, tinfo->rp->ai_addr, tinfo->rp->ai_addrlen) < 0)
+  {
+    printf("Failed to connect %d\n", sfd);
+    perror("Failed");
+    pthread_exit((void *)1);
+  }
+
+  fcntl(sfd, F_SETFL, O_NONBLOCK);
+  // Make sure we are nagling
+  int one = 0;
+  setsockopt(sfd, SOL_TCP, TCP_NODELAY, &one, sizeof(one));
+  
+  SSL_CTX *client_ctx = SSL_CTX_new(SSLv23_client_method());
+  SSL *ssl = SSL_new(client_ctx);
+  SSL_set_session(ssl, tinfo->session);
+
+  SSL_set_fd(ssl, sfd);
+  int ret = SSL_connect(ssl);
+  int read_count = 0;
+  int write_count = 1;
+  int write_ret = -1;
+  int post_write_ret = -1;
+
+  while (ret < 0) {
+    int error = SSL_get_error(ssl, ret);
+    fd_set reads;
+    fd_set writes;
+    FD_ZERO(&reads);
+    FD_ZERO(&writes);
+    switch (error) {
+    case SSL_ERROR_WANT_READ:
+    case SSL_ERROR_WANT_ACCEPT:
+      FD_SET(sfd, &reads);
+      read_count++;
+      break;
+    case SSL_ERROR_WANT_CONNECT:
+    case SSL_ERROR_WANT_WRITE:
+      FD_SET(sfd, &writes);
+      write_count++;
+      break;
+    case SSL_ERROR_SYSCALL:
+    case SSL_ERROR_SSL:
+    case SSL_ERROR_ZERO_RETURN:
+      printf("Error %d\n", error);
+      pthread_exit((void *)1);
+      break;
+    default:
+      //printf("Unknown error is %d", error);
+      FD_SET(sfd, &reads);
+      FD_SET(sfd, &writes);
+      break;
+    }
+    ret = select(sfd+1, &reads, &writes, NULL, NULL);
+    if (FD_ISSET(sfd, &reads) || FD_ISSET(sfd, &writes)) {
+      ret = write_ret = SSL_write(ssl, req_buf, strlen(req_buf));
+      if (write_ret >= 0) 
+        post_write_ret = SSL_write(ssl, post_buf, sizeof(post_buf));
+    }
+  } 
+
+  while (write_ret < 0) {
+     write_ret = SSL_write(ssl, req_buf, strlen(req_buf));
+  }
+  while (post_write_ret < 0) {
+    post_write_ret = SSL_write(ssl, post_buf, sizeof(post_buf));
+  }
+
+  // Have to do the shutdown so the data packet is sent out fast enough
+  // so it might be read with the last handshake packet
+  shutdown(sfd, SHUT_WR);
+
+  char input_buf[1024];
+  int read_bytes = SSL_read(ssl, input_buf, sizeof(input_buf));
+  int total_read = 0;
+  while (read_bytes != 0) {
+    fd_set reads;
+    fd_set writes;
+    FD_ZERO(&reads);
+    FD_ZERO(&writes);
+    if (read_bytes > 0) {
+      total_read += read_bytes;
+      FD_SET(sfd, &reads);
+    }
+    else {
+      int error = SSL_get_error(ssl, read_bytes);
+      switch (error) {
+      case SSL_ERROR_WANT_READ:
+      case SSL_ERROR_WANT_ACCEPT:
+        FD_SET(sfd, &reads);
+        break;
+      case SSL_ERROR_WANT_CONNECT:
+      case SSL_ERROR_WANT_WRITE:
+        printf("Unexpected write\n");
+        pthread_exit((void *)1);
+        break;
+      case SSL_ERROR_SYSCALL:
+      case SSL_ERROR_SSL:
+      case SSL_ERROR_ZERO_RETURN:
+        printf("Error Read\n");
+        pthread_exit((void *)1);
+        break;
+      default:
+        FD_SET(sfd, &reads);
+        FD_SET(sfd, &writes);
+        break;
+      }
+    }
+    select(sfd+1, &reads, &writes, NULL, NULL);
+    if (FD_ISSET(sfd, &reads)) {
+      read_bytes = SSL_read(ssl, input_buf, sizeof(input_buf));
+    }
+  }
+  if (read_bytes > 0 && read_bytes < 1024) input_buf[read_bytes] = '\0';
+  else input_buf[1023] = '\0';
+  //printf("total_bytes=%d Received bytes=%d handshake writes=%d handshake reads=%d\n", total_read,
read_bytes, write_count, read_count);
+  
+  //  Leaking the socket, so that the EOS does not wake up a potentially
+  //  stalled ATS connection.  Want to wait for the inactivity timeout
+  //  to make it clear that there was a stalling problem
+  //close(sfd);
+  pthread_exit(NULL);
+}
+
+/** 
+ * Connect to a server.
+ * Handshake
+ * Exit immediatesly
+ */
+int
+main(int argc, char *argv[])
+{
+    struct addrinfo hints;
+    struct addrinfo *result, *rp;
+    int sfd, s, j;
+    size_t len;
+    ssize_t nread;
+
+   if (argc < 4) {
+        fprintf(stderr, "Usage: %s host thread-count header-count [port]\n", argv[0]);
+        exit(EXIT_FAILURE);
+    }
+   char *host = argv[1];
+   int header_count = atoi(argv[3]);
+   snprintf(req_buf, sizeof(req_buf), "POST /post HTTP/1.1\r\nHost: %s\r\nConnection: close\r\nContent-length:%d\r\n",
host, sizeof(post_buf));
+   int i;
+   for (i = 0; i < header_count; i++) {
+     sprintf(req_buf + strlen(req_buf), "header%d:%d\r\n", i, i);
+   }
+   strcat(req_buf, "\r\n");
+   memset(post_buf, '0', sizeof(post_buf));
+
+   int thread_count = atoi(argv[2]);
+
+   char *port = argc == 5 ? argv[4] : "443";
+
+   /* Obtain address(es) matching host/port */
+
+   memset(&hints, 0, sizeof(struct addrinfo));
+   hints.ai_family = AF_UNSPEC;    /* Allow IPv4 or IPv6 */
+   hints.ai_socktype = SOCK_STREAM; /* Datagram socket */
+   hints.ai_flags = 0;
+   hints.ai_protocol = 0;          /* Any protocol */
+
+   s = getaddrinfo(host, port, &hints, &result);
+   if (s != 0) {
+       fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(s));
+       exit(EXIT_FAILURE);
+   }
+
+   /* getaddrinfo() returns a list of address structures.
+    * Try each address until we successfully connect(2).
+    * socket(2) (or connect(2)) fails, we (close the socket
+      and) try the next address. */
+
+   for (rp = result; rp != NULL; rp = rp->ai_next) {
+     sfd = socket(rp->ai_family, rp->ai_socktype,
+                  rp->ai_protocol);
+     if (sfd == -1)
+       continue;
+     if (connect(sfd, rp->ai_addr, rp->ai_addrlen) != -1)
+        break;                  /* Success */
+
+     close(sfd);
+   }
+
+   if (rp == NULL) {               /* No address succeeded */
+        fprintf(stderr, "Could not connect\n");
+        exit(EXIT_FAILURE);
+    }
+
+
+  //fcntl(sfd, F_SETFL, O_NONBLOCK);
+
+  SSL_load_error_strings();
+  SSL_library_init();
+
+  mutex_buf = (pthread_mutex_t *)OPENSSL_malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t));
+  for (i = 0; i < CRYPTO_num_locks(); i++) {
+    pthread_mutex_init(&mutex_buf[i], NULL);
+  }
+
+  CRYPTO_set_locking_callback(SSL_locking_callback);
+  CRYPTO_THREADID_set_callback(SSL_pthreads_thread_id);
+
+
+   SSL_CTX *client_ctx = SSL_CTX_new(SSLv23_client_method());
+   SSL *ssl = SSL_new(client_ctx);
+
+   SSL_set_fd(ssl, sfd);
+   int ret = SSL_connect(ssl);
+   int read_count = 0;
+   int write_count = 1;
+ 
+   printf("Sent request\n");
+   if ((ret = SSL_write(ssl, req_buf, strlen(req_buf))) <= 0) {
+      int error = SSL_get_error(ssl, ret);
+      printf("SSL_write failed %d", error);
+      exit(1);
+   }
+   SSL_write(ssl, post_buf, sizeof(post_buf));
+
+  char input_buf[1024];
+  int read_bytes = SSL_read(ssl, input_buf, sizeof(input_buf));
+  if (read_bytes > 0 && read_bytes < 1024) input_buf[read_bytes] = '\0';
+  else input_buf[1023] = '\0';
+  //printf("Received %d bytes %s\n", read_bytes, input_buf);
+  SSL_SESSION *session = SSL_get_session(ssl);
+  close(sfd);
+  struct thread_info tinfo;
+  tinfo.rp =rp;
+  tinfo.session = session;
+  pthread_t * threads = malloc(thread_count *sizeof(pthread_t));
+  for (i= 0; i < thread_count; i++) {
+    pthread_create(threads + i, NULL, spawn_same_session_send, &tinfo);
+  }
+
+  void *retval;
+  for (i = 0; i < thread_count; i++) {
+    retval = NULL;
+    pthread_join(threads[i], &retval);
+    if (retval != NULL) {
+      printf("Thread %d failed 0x%x\n", i, retval);
+    }
+  }
+
+  printf("All threads finished\n");
+ 
+  exit(0);
+}
+
diff --git a/tests/gold_tests/tls/ssl/server.key b/tests/gold_tests/tls/ssl/server.key
new file mode 100644
index 0000000..4c7a661
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/server.key
@@ -0,0 +1,15 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDWMHOiUF+ORmZjAxI8MWE9dblb7gQSJ36WCXlPFiFx6ynF+S1E
+kXAYpIip5X0pzDUaIbLukxJUAAnOtMEO0PCgxJQUrEtRWh8wiJdbdQJF0Zs/9R+u
+SUgb61f+mdTQvhqefBGx+xrpfAcgtcWiZuSA9Q3fvpDj5WOWSPWXBUuxywIDAQAB
+AoGBAJPxRX2gjFAGWmQbU/YVmXfNH6navh8X/nx9sLeqrpE0AFeJI/ZPiqDKzMal
+B43eSfNxwVi+ZxN0L1ICUbL9KKZvHs/QBxWLA1fGVAXrz7sRplEVvakPpTfHoEnv
+sKaMWVKaK/S5WGbDhElb6zb/Lwo19DsIAPjGYqFvzFJBmobJAkEA9iSeTGkR9X26
+GywZoYrIMlRh34htOIRx1UUq88rFzdrCF21kQ4lhBIkX5OZMMy652i2gyak4OZTe
+YewIv8jw9QJBAN7EQNHG8jPwXfVp91/fqxVQEfumuP2i6uiWWYQgZCmla2+0xcLZ
+pMQ6sQEe10hhTrVnzHgAUVp50Ntn2jwBX78CQF09veGAI9d1Cxzj9cmmAvRd1r2Q
+tp8kPOLnUsALXib+6WtqewLCdcf8DtsdClyRJMIraq85tRzK8fryKNZNzkkCQEgA
+yS7FDj5JgCU15hZgFk1iPx3HCt44jZM2HaL+UUHAzRQjKxTLAl3G1rWVAWLMyQML
+lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ
+vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z
+-----END RSA PRIVATE KEY-----
diff --git a/tests/gold_tests/tls/ssl/server.pem b/tests/gold_tests/tls/ssl/server.pem
new file mode 100644
index 0000000..a1de94f
--- /dev/null
+++ b/tests/gold_tests/tls/ssl/server.pem
@@ -0,0 +1,32 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIICXQIBAAKBgQDWMHOiUF+ORmZjAxI8MWE9dblb7gQSJ36WCXlPFiFx6ynF+S1E
+kXAYpIip5X0pzDUaIbLukxJUAAnOtMEO0PCgxJQUrEtRWh8wiJdbdQJF0Zs/9R+u
+SUgb61f+mdTQvhqefBGx+xrpfAcgtcWiZuSA9Q3fvpDj5WOWSPWXBUuxywIDAQAB
+AoGBAJPxRX2gjFAGWmQbU/YVmXfNH6navh8X/nx9sLeqrpE0AFeJI/ZPiqDKzMal
+B43eSfNxwVi+ZxN0L1ICUbL9KKZvHs/QBxWLA1fGVAXrz7sRplEVvakPpTfHoEnv
+sKaMWVKaK/S5WGbDhElb6zb/Lwo19DsIAPjGYqFvzFJBmobJAkEA9iSeTGkR9X26
+GywZoYrIMlRh34htOIRx1UUq88rFzdrCF21kQ4lhBIkX5OZMMy652i2gyak4OZTe
+YewIv8jw9QJBAN7EQNHG8jPwXfVp91/fqxVQEfumuP2i6uiWWYQgZCmla2+0xcLZ
+pMQ6sQEe10hhTrVnzHgAUVp50Ntn2jwBX78CQF09veGAI9d1Cxzj9cmmAvRd1r2Q
+tp8kPOLnUsALXib+6WtqewLCdcf8DtsdClyRJMIraq85tRzK8fryKNZNzkkCQEgA
+yS7FDj5JgCU15hZgFk1iPx3HCt44jZM2HaL+UUHAzRQjKxTLAl3G1rWVAWLMyQML
+lORoveLvotl4HOruSsMCQQCAx9dV9JUSFoyc1CWILp/FgUH/se4cjQCThGO0DoQQ
+vGTYmntY7j9WRJ9esQrjdD6Clw8zM/45GIBNwnXzqo7Z
+-----END RSA PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIICszCCAhwCCQCRJsJJ+mTsdDANBgkqhkiG9w0BAQsFADCBnTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh
+aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u
+ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j
+b20wHhcNMTYwODI1MjI1NzIxWhcNMTcwODI1MjI1NzIxWjCBnTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgMAklMMRIwEAYDVQQHDAlDaGFtcGFpZ24xDjAMBgNVBAoMBVlh
+aG9vMQ0wCwYDVQQLDARFZGdlMSgwJgYDVQQDDB9qdWljZXByb2R1Y2UuY29ycC5u
+ZTEueWFob28uY29tMSQwIgYJKoZIhvcNAQkBFhVwZXJzaWEuYXppekB5YWhvby5j
+b20wgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBANYwc6JQX45GZmMDEjwxYT11
+uVvuBBInfpYJeU8WIXHrKcX5LUSRcBikiKnlfSnMNRohsu6TElQACc60wQ7Q8KDE
+lBSsS1FaHzCIl1t1AkXRmz/1H65JSBvrV/6Z1NC+Gp58EbH7Gul8ByC1xaJm5ID1
+Dd++kOPlY5ZI9ZcFS7HLAgMBAAEwDQYJKoZIhvcNAQELBQADgYEAXSVfZ5p1TkhW
+QiYq9nfQlBnX2NVaf8ymA8edQR0qH/QBv4/52bNNXC7V/V+ev9LCho2iRMeYYyXB
+yo1wBAGR83lS9cF/tOABcYrxjdP54Sfkyh5fomcg8SV7zap6C8mhbV8r3EujbKCx
+igH3fMX5F/eRwNCzaMMyQsXaxTJ3trk=
+-----END CERTIFICATE-----
diff --git a/tests/gold_tests/tls/tls.test.py b/tests/gold_tests/tls/tls.test.py
new file mode 100644
index 0000000..04588fa
--- /dev/null
+++ b/tests/gold_tests/tls/tls.test.py
@@ -0,0 +1,101 @@
+'''
+'''
+#  Licensed to the Apache Software Foundation (ASF) under one
+#  or more contributor license agreements.  See the NOTICE file
+#  distributed with this work for additional information
+#  regarding copyright ownership.  The ASF licenses this file
+#  to you under the Apache License, Version 2.0 (the
+#  "License"); you may not use this file except in compliance
+#  with the License.  You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+#  Unless required by applicable law or agreed to in writing, software
+#  distributed under the License is distributed on an "AS IS" BASIS,
+#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+#  See the License for the specific language governing permissions and
+#  limitations under the License.
+
+import os
+Test.Summary = '''
+Test tls
+'''
+
+def Build(Test, filename, host):
+	tr = Test.AddTestRun("Build", "Build test file: {0}".format(filename))
+	tr.Command = 'gcc -o ssl-post -O2 -g {0} -lssl -lpthread -lcrypto'.format(filename)
+	tr.ReturnCode = 0
+	tr = Test.addTestRun("Run-Test")
+	tr.Command = './ssl-post {0} 40 378'.format(host)
+
+# ExtendTest(Build)
+
+
+# need Curl
+Test.SkipUnless(
+    Condition.HasProgram("curl","Curl need to be installed on system for this test to work")
+    )
+Test.ContinueOnFail=True
+# Define default ATS
+ts=Test.MakeATSProcess("ts",select_ports=False)
+server=Test.MakeOriginServer("server")
+
+
+tr=Test.AddTestRun("Build-Test","build test file: ssl-post.c")
+tr.Command = 'gcc -o ssl-post -O2 -g {0}/ssl-post.c -lssl -lpthread -lcrypto'.format(Test.RunDirectory)
+tr.ReturnCode=0
+tr.Setup.CopyAs('ssl-post.c',Test.RunDirectory)
+
+requestLocation = "test2"
+reHost = "www.example.com"
+
+testName = ""
+
+header_count = 378
+
+header_string = "POST /post HTTP/1.1\r\nHost: www.example.com\r\nContent-Length:1000\r\n"
+
+for i in range (0, 378):
+	header_string = "{1}header{0}:{0}\r\n".format(i,header_string)
+header_string = "{0}\r\n".format(header_string)
+
+post_body = ""
+for i in range (0, 1000):
+	post_body = "{0}0".format(post_body)
+
+# Add info the origin server responses
+server.addResponse("sessionlog.json",
+    {"headers": header_string, "timestamp": "1469733493.993", "body": post_body},
+    {"headers": "HTTP/1.1 200 OK\r\nServer: microserver\r\nConnection: close\r\nCache-Control:
max-age=3600\r\nContent-Length: 2\r\n\r\n", "timestamp": "1469733493.993", "body": "ok" })
+
+#add ssl materials like key, certificates for the server
+ts.addSSLfile("ssl/server.pem")
+ts.addSSLfile("ssl/server.key")
+
+ts.Variables.ssl_port = 4443
+ts.Disk.remap_config.AddLine(
+    'map / http://127.0.0.1:{0}'.format(server.Variables.Port)
+)
+
+ts.Disk.ssl_multicert_config.AddLine(
+    'dest_ip=* ssl_cert_name=server.pem ssl_key_name=server.key'
+)
+ts.Disk.records_config.update({
+        'proxy.config.ssl.server.cert.path': '{0}'.format(ts.Variables.SSLDir), 
+        'proxy.config.ssl.server.private_key.path': '{0}'.format(ts.Variables.SSLDir),
+        'proxy.config.http.server_ports': '{0} {1}:proto=http2;http:ssl'.format(ts.Variables.port,ts.Variables.ssl_port),
 # enable ssl port
+        'proxy.config.ssl.client.verify.server':  0,
+        'proxy.config.ssl.server.cipher_suite' : 'ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384:AES128-GCM-SHA256:AES256-GCM-SHA384:ECDHE-RSA-RC4-SHA:ECDHE-RSA-AES128-SHA:ECDHE-RSA-AES256-SHA:RC4-SHA:RC4-MD5:AES128-SHA:AES256-SHA:DES-CBC3-SHA!SRP:!DSS:!PSK:!aNULL:!eNULL:!SSLv2',
+    })
+
+tr=Test.AddTestRun("Run-Test")
+tr.Command = './ssl-post 127.0.0.1 40 378 4443'
+tr.ReturnCode=0
+# time delay as proxy.config.http.wait_for_cache could be broken
+tr.Processes.Default.StartBefore(server)
+tr.Processes.Default.StartBefore(Test.Processes.ts, ready=When.PortOpen(ts.Variables.ssl_port))
+tr.Processes.Default.Streams.stdout="gold/ssl-post.gold"
+tr.StillRunningAfter=server
+tr.Processes.Default.TimeOut = 5
+tr.TimeOut = 5
+

-- 
To stop receiving notification emails like this one, please contact
['"commits@trafficserver.apache.org" <commits@trafficserver.apache.org>'].

Mime
View raw message