1#include <muduo/net/Buffer.h>
2
3#include <stdio.h>
4
5#include <tls.h>
6
7#include "timer.h"
8
9muduo::net::Buffer clientOut, serverOut;
10int64_t clientWrite, serverWrite;
11
12ssize_t net_read(struct tls *ctx, void *buf, size_t len, void *arg)
13{
14  muduo::net::Buffer* in = ((arg == &clientOut) ? &serverOut : &clientOut);
15  if (in->readableBytes() > 0)
16  {
17    size_t n = std::min(in->readableBytes(), len);
18    memcpy(buf, in->peek(), n);
19    in->retrieve(n);
20    return n;
21  }
22  else
23  {
24    return TLS_WANT_POLLIN;
25  }
26}
27
28ssize_t net_write(struct tls *ctx, const void *buf, size_t len, void *arg)
29{
30  muduo::net::Buffer* out = static_cast<muduo::net::Buffer*>(arg);
31  int64_t& wr = (out == &clientOut ? clientWrite : serverWrite);
32  wr += len;
33  out->append(buf, len);
34  return len;
35}
36
37struct tls* client()
38{
39  struct tls_config* cfg = tls_config_new();
40  assert(cfg != NULL);
41
42  // symlink to libressl/tests/ca.pem
43  tls_config_set_ca_file(cfg, "ca.pem");
44  // tls_config_insecure_noverifycert(cfg);
45  // tls_config_insecure_noverifyname(cfg);
46
47  struct tls* ctx = tls_client();
48  assert(ctx != NULL);
49
50  int ret = tls_configure(ctx, cfg);
51  assert(ret == 0);
52
53  tls_connect_cbs(ctx, net_read, net_write, &clientOut, "Test Server Cert");
54
55  return ctx;
56}
57
58struct tls* server()
59{
60  struct tls_config* cfg = tls_config_new();
61  assert(cfg != NULL);
62
63  int ret = tls_config_set_cert_file(cfg, "server.pem");
64  assert(ret == 0);
65
66  ret = tls_config_set_key_file(cfg, "server.pem");
67  assert(ret == 0);
68
69  ret = tls_config_set_ecdhecurve(cfg, "prime256v1");
70  assert(ret == 0);
71
72  // tls_config_verify_client_optional(cfg);
73  struct tls* ctx = tls_server();
74  assert(ctx != NULL);
75
76  ret = tls_configure(ctx, cfg);
77  assert(ret == 0);
78
79  struct tls* conn_ctx = NULL;
80  tls_accept_cbs(ctx, &conn_ctx, net_read, net_write, &serverOut);
81  return conn_ctx;
82}
83
84Timer tclient, tserver;
85
86bool handshake(struct tls* cctx, struct tls* sctx)
87{
88  int client_done = false, server_done = false;
89  while (!(client_done && server_done))
90  {
91    if (!client_done)
92    {
93      tclient.start();
94      int ret = tls_handshake(cctx);
95      tclient.stop();
96      // printf("c %d\n", ret);
97      if (ret == 0)
98        client_done = true;
99      else if (ret == -1)
100      {
101        printf("client handshake failed: %s\n", tls_error(cctx));
102        break;
103      }
104    }
105
106    if (!server_done)
107    {
108      tserver.start();
109      int ret = tls_handshake(sctx);
110      tserver.stop();
111      // printf("s %d\n", ret);
112      if (ret == 0)
113        server_done = true;
114      else if (ret == -1)
115      {
116        printf("server handshake failed: %s\n", tls_error(sctx));
117        break;
118      }
119    }
120  }
121  return client_done && server_done;
122}
123
124void throughput(int block_size, struct tls* cctx, struct tls* sctx)
125{
126  double start = now();
127  int total = 0;
128  int batch = 1024;
129  char* message = new char[block_size];
130  bzero(message, block_size);
131  clientWrite = 0;
132  tclient.reset();
133  tserver.reset();
134  while (now() - start < 10)
135  {
136    for (int i = 0; i < batch; ++i)
137    {
138      tclient.start();
139      int nw = tls_write(cctx, message, block_size);
140      tclient.stop();
141      assert(nw == block_size);
142      tserver.start();
143      int nr = tls_read(sctx, message, block_size);
144      tserver.stop();
145      assert(nr == block_size);
146    }
147    total += batch;
148    batch *= 2;
149  }
150  double secs = now() - start;
151  // throughput is half of real value, because client and server share one core.
152  printf("bs %5d sec %.3f tot %d thr %.1fKB/s wr %.2fB client %.3f server %.3f\n", block_size, secs, total,
153         block_size / secs * total / 1024, clientWrite * 1.0 / total, tclient.seconds(), tserver.seconds());
154  delete[] message;
155}
156
157int main(int argc, char* argv[])
158{
159  int ret = tls_init();
160  assert(ret == 0);
161
162  struct tls* cctx = client();
163  struct tls* sctx = server();
164
165  const int N = 1000;
166  Timer all, client, server;
167  all.start();
168  for (int i = 0; i < N; ++i)
169  {
170    if (!handshake(cctx, sctx))
171      return -1;
172
173    if (i == 0)
174      printf("cipher %s\n", tls_conn_cipher(cctx));
175  }
176  all.stop();
177  printf("%f secs, %f handshakes/sec\n", all.seconds(), N / all.seconds());
178  printf("client %f secs, server %f secs\n", tclient.seconds(), tserver.seconds());
179
180  for (int i = 1024 * 16; i >= 1; i /= 4)
181  {
182    throughput(i, cctx, sctx);
183  }
184}
185
186