12c01beb4SShuo Chen#include <muduo/net/Buffer.h>
22c01beb4SShuo Chen
32c01beb4SShuo Chen#include <stdio.h>
42c01beb4SShuo Chen
52c01beb4SShuo Chen#include <tls.h>
62c01beb4SShuo Chen
72c01beb4SShuo Chen#include "timer.h"
82c01beb4SShuo Chen
92c01beb4SShuo Chenmuduo::net::Buffer clientOut, serverOut;
10d9e55939SShuo Chenint64_t clientWrite, serverWrite;
112c01beb4SShuo Chen
122c01beb4SShuo Chenssize_t net_read(struct tls *ctx, void *buf, size_t len, void *arg)
132c01beb4SShuo Chen{
142c01beb4SShuo Chen  muduo::net::Buffer* in = ((arg == &clientOut) ? &serverOut : &clientOut);
152c01beb4SShuo Chen  if (in->readableBytes() > 0)
162c01beb4SShuo Chen  {
172c01beb4SShuo Chen    size_t n = std::min(in->readableBytes(), len);
182c01beb4SShuo Chen    memcpy(buf, in->peek(), n);
192c01beb4SShuo Chen    in->retrieve(n);
202c01beb4SShuo Chen    return n;
212c01beb4SShuo Chen  }
222c01beb4SShuo Chen  else
232c01beb4SShuo Chen  {
242c01beb4SShuo Chen    return TLS_WANT_POLLIN;
252c01beb4SShuo Chen  }
262c01beb4SShuo Chen}
272c01beb4SShuo Chen
282c01beb4SShuo Chenssize_t net_write(struct tls *ctx, const void *buf, size_t len, void *arg)
292c01beb4SShuo Chen{
302c01beb4SShuo Chen  muduo::net::Buffer* out = static_cast<muduo::net::Buffer*>(arg);
31d9e55939SShuo Chen  int64_t& wr = (out == &clientOut ? clientWrite : serverWrite);
32d9e55939SShuo Chen  wr += len;
332c01beb4SShuo Chen  out->append(buf, len);
342c01beb4SShuo Chen  return len;
352c01beb4SShuo Chen}
362c01beb4SShuo Chen
372c01beb4SShuo Chenstruct tls* client()
382c01beb4SShuo Chen{
392c01beb4SShuo Chen  struct tls_config* cfg = tls_config_new();
402c01beb4SShuo Chen  assert(cfg != NULL);
412c01beb4SShuo Chen
42cc4062ffSShuo Chen  // symlink to libressl/tests/ca.pem
432c01beb4SShuo Chen  tls_config_set_ca_file(cfg, "ca.pem");
442c01beb4SShuo Chen  // tls_config_insecure_noverifycert(cfg);
452c01beb4SShuo Chen  // tls_config_insecure_noverifyname(cfg);
462c01beb4SShuo Chen
472c01beb4SShuo Chen  struct tls* ctx = tls_client();
482c01beb4SShuo Chen  assert(ctx != NULL);
492c01beb4SShuo Chen
502c01beb4SShuo Chen  int ret = tls_configure(ctx, cfg);
512c01beb4SShuo Chen  assert(ret == 0);
522c01beb4SShuo Chen
532c01beb4SShuo Chen  tls_connect_cbs(ctx, net_read, net_write, &clientOut, "Test Server Cert");
542c01beb4SShuo Chen
552c01beb4SShuo Chen  return ctx;
562c01beb4SShuo Chen}
572c01beb4SShuo Chen
582c01beb4SShuo Chenstruct tls* server()
592c01beb4SShuo Chen{
602c01beb4SShuo Chen  struct tls_config* cfg = tls_config_new();
612c01beb4SShuo Chen  assert(cfg != NULL);
622c01beb4SShuo Chen
632c01beb4SShuo Chen  int ret = tls_config_set_cert_file(cfg, "server.pem");
642c01beb4SShuo Chen  assert(ret == 0);
652c01beb4SShuo Chen
662c01beb4SShuo Chen  ret = tls_config_set_key_file(cfg, "server.pem");
672c01beb4SShuo Chen  assert(ret == 0);
682c01beb4SShuo Chen
69b140ba61SShuo Chen  ret = tls_config_set_ecdhecurve(cfg, "prime256v1");
70b140ba61SShuo Chen  assert(ret == 0);
71b140ba61SShuo Chen
722c01beb4SShuo Chen  // tls_config_verify_client_optional(cfg);
732c01beb4SShuo Chen  struct tls* ctx = tls_server();
742c01beb4SShuo Chen  assert(ctx != NULL);
752c01beb4SShuo Chen
762c01beb4SShuo Chen  ret = tls_configure(ctx, cfg);
772c01beb4SShuo Chen  assert(ret == 0);
782c01beb4SShuo Chen
792c01beb4SShuo Chen  struct tls* conn_ctx = NULL;
802c01beb4SShuo Chen  tls_accept_cbs(ctx, &conn_ctx, net_read, net_write, &serverOut);
812c01beb4SShuo Chen  return conn_ctx;
822c01beb4SShuo Chen}
832c01beb4SShuo Chen
842c01beb4SShuo ChenTimer tclient, tserver;
852c01beb4SShuo Chen
86cc4062ffSShuo Chenbool handshake(struct tls* cctx, struct tls* sctx)
872c01beb4SShuo Chen{
882c01beb4SShuo Chen  int client_done = false, server_done = false;
892c01beb4SShuo Chen  while (!(client_done && server_done))
902c01beb4SShuo Chen  {
912c01beb4SShuo Chen    if (!client_done)
922c01beb4SShuo Chen    {
932c01beb4SShuo Chen      tclient.start();
942c01beb4SShuo Chen      int ret = tls_handshake(cctx);
952c01beb4SShuo Chen      tclient.stop();
962c01beb4SShuo Chen      // printf("c %d\n", ret);
972c01beb4SShuo Chen      if (ret == 0)
982c01beb4SShuo Chen        client_done = true;
992c01beb4SShuo Chen      else if (ret == -1)
100cc4062ffSShuo Chen      {
101cc4062ffSShuo Chen        printf("client handshake failed: %s\n", tls_error(cctx));
1022c01beb4SShuo Chen        break;
103cc4062ffSShuo Chen      }
1042c01beb4SShuo Chen    }
1052c01beb4SShuo Chen
1062c01beb4SShuo Chen    if (!server_done)
1072c01beb4SShuo Chen    {
1082c01beb4SShuo Chen      tserver.start();
1092c01beb4SShuo Chen      int ret = tls_handshake(sctx);
1102c01beb4SShuo Chen      tserver.stop();
1112c01beb4SShuo Chen      // printf("s %d\n", ret);
1122c01beb4SShuo Chen      if (ret == 0)
1132c01beb4SShuo Chen        server_done = true;
1142c01beb4SShuo Chen      else if (ret == -1)
115cc4062ffSShuo Chen      {
116cc4062ffSShuo Chen        printf("server handshake failed: %s\n", tls_error(sctx));
1172c01beb4SShuo Chen        break;
118cc4062ffSShuo Chen      }
1192c01beb4SShuo Chen    }
1202c01beb4SShuo Chen  }
121cc4062ffSShuo Chen  return client_done && server_done;
1222c01beb4SShuo Chen}
1232c01beb4SShuo Chen
124d9e55939SShuo Chenvoid throughput(int block_size, struct tls* cctx, struct tls* sctx)
125d9e55939SShuo Chen{
126d9e55939SShuo Chen  double start = now();
127d9e55939SShuo Chen  int total = 0;
128d9e55939SShuo Chen  int batch = 1024;
129d9e55939SShuo Chen  char* message = new char[block_size];
130d9e55939SShuo Chen  bzero(message, block_size);
131d9e55939SShuo Chen  clientWrite = 0;
132d9e55939SShuo Chen  tclient.reset();
133d9e55939SShuo Chen  tserver.reset();
134d9e55939SShuo Chen  while (now() - start < 10)
135d9e55939SShuo Chen  {
136d9e55939SShuo Chen    for (int i = 0; i < batch; ++i)
137d9e55939SShuo Chen    {
138d9e55939SShuo Chen      tclient.start();
139d9e55939SShuo Chen      int nw = tls_write(cctx, message, block_size);
140d9e55939SShuo Chen      tclient.stop();
141d9e55939SShuo Chen      assert(nw == block_size);
142d9e55939SShuo Chen      tserver.start();
143d9e55939SShuo Chen      int nr = tls_read(sctx, message, block_size);
144d9e55939SShuo Chen      tserver.stop();
145d9e55939SShuo Chen      assert(nr == block_size);
146d9e55939SShuo Chen    }
147d9e55939SShuo Chen    total += batch;
148d9e55939SShuo Chen    batch *= 2;
149d9e55939SShuo Chen  }
150d9e55939SShuo Chen  double secs = now() - start;
151d9e55939SShuo Chen  // throughput is half of real value, because client and server share one core.
152d9e55939SShuo Chen  printf("bs %5d sec %.3f tot %d thr %.1fKB/s wr %.2fB client %.3f server %.3f\n", block_size, secs, total,
153d9e55939SShuo Chen         block_size / secs * total / 1024, clientWrite * 1.0 / total, tclient.seconds(), tserver.seconds());
154926c960eSShuo Chen  delete[] message;
155d9e55939SShuo Chen}
156d9e55939SShuo Chen
1572c01beb4SShuo Chenint main(int argc, char* argv[])
1582c01beb4SShuo Chen{
1592c01beb4SShuo Chen  int ret = tls_init();
1602c01beb4SShuo Chen  assert(ret == 0);
1612c01beb4SShuo Chen
1622c01beb4SShuo Chen  struct tls* cctx = client();
1632c01beb4SShuo Chen  struct tls* sctx = server();
1642c01beb4SShuo Chen
165cc4062ffSShuo Chen  const int N = 1000;
1662c01beb4SShuo Chen  Timer all, client, server;
1672c01beb4SShuo Chen  all.start();
1682c01beb4SShuo Chen  for (int i = 0; i < N; ++i)
1692c01beb4SShuo Chen  {
170cc4062ffSShuo Chen    if (!handshake(cctx, sctx))
171cc4062ffSShuo Chen      return -1;
1722c01beb4SShuo Chen
1732c01beb4SShuo Chen    if (i == 0)
1742c01beb4SShuo Chen      printf("cipher %s\n", tls_conn_cipher(cctx));
1752c01beb4SShuo Chen  }
1762c01beb4SShuo Chen  all.stop();
1772c01beb4SShuo Chen  printf("%f secs, %f handshakes/sec\n", all.seconds(), N / all.seconds());
1782c01beb4SShuo Chen  printf("client %f secs, server %f secs\n", tclient.seconds(), tserver.seconds());
179d9e55939SShuo Chen
180cc4062ffSShuo Chen  for (int i = 1024 * 16; i >= 1; i /= 4)
181d9e55939SShuo Chen  {
182d9e55939SShuo Chen    throughput(i, cctx, sctx);
183d9e55939SShuo Chen  }
1842c01beb4SShuo Chen}
1852c01beb4SShuo Chen
186