1926c960eSShuo Chen#include "timer.h"
2926c960eSShuo Chen#include "thread/Thread.h"
3926c960eSShuo Chen#include <boost/bind.hpp>
4926c960eSShuo Chen
542b85340SShuo Chen#include <assert.h>
6926c960eSShuo Chen#include <fcntl.h>
742b85340SShuo Chen#include <stdio.h>
842b85340SShuo Chen#include <sys/types.h>
942b85340SShuo Chen#include <sys/socket.h>
1042b85340SShuo Chen
1142b85340SShuo Chen#include <tls.h>
1242b85340SShuo Chen
1323a62999SShuo Chenstruct tls* client(int sockfd)
1442b85340SShuo Chen{
1542b85340SShuo Chen  struct tls_config* cfg = tls_config_new();
1642b85340SShuo Chen  assert(cfg != NULL);
1742b85340SShuo Chen
1842b85340SShuo Chen  tls_config_set_ca_file(cfg, "ca.pem");
1942b85340SShuo Chen  // tls_config_insecure_noverifycert(cfg);
2042b85340SShuo Chen  // tls_config_insecure_noverifyname(cfg);
2142b85340SShuo Chen
2242b85340SShuo Chen  struct tls* ctx = tls_client();
2342b85340SShuo Chen  assert(ctx != NULL);
2442b85340SShuo Chen
2542b85340SShuo Chen  int ret = tls_configure(ctx, cfg);
2642b85340SShuo Chen  assert(ret == 0);
2742b85340SShuo Chen
2823a62999SShuo Chen  ret = tls_connect_socket(ctx, sockfd, "Test Server Cert");
2923a62999SShuo Chen  assert(ret == 0);
3023a62999SShuo Chen
3142b85340SShuo Chen  return ctx;
3242b85340SShuo Chen}
3342b85340SShuo Chen
3423a62999SShuo Chenstruct tls* server(int sockfd)
3542b85340SShuo Chen{
3642b85340SShuo Chen  struct tls_config* cfg = tls_config_new();
3742b85340SShuo Chen  assert(cfg != NULL);
3842b85340SShuo Chen
3923a62999SShuo Chen  int ret = tls_config_set_cert_file(cfg, "server.pem");
4042b85340SShuo Chen  assert(ret == 0);
4142b85340SShuo Chen
4223a62999SShuo Chen  ret = tls_config_set_key_file(cfg, "server.pem");
4342b85340SShuo Chen  assert(ret == 0);
4442b85340SShuo Chen
45b140ba61SShuo Chen  ret = tls_config_set_ecdhecurve(cfg, "prime256v1");
46b140ba61SShuo Chen  assert(ret == 0);
47b140ba61SShuo Chen
48b140ba61SShuo Chen  // tls_config_verify_client_optional(cfg);
4942b85340SShuo Chen  struct tls* ctx = tls_server();
5042b85340SShuo Chen  assert(ctx != NULL);
5142b85340SShuo Chen
5242b85340SShuo Chen  ret = tls_configure(ctx, cfg);
5342b85340SShuo Chen  assert(ret == 0);
5442b85340SShuo Chen
5542b85340SShuo Chen  struct tls* sctx = NULL;
5623a62999SShuo Chen  ret = tls_accept_socket(ctx, &sctx, sockfd);
5723a62999SShuo Chen  assert(ret == 0 && sctx != NULL);
5842b85340SShuo Chen
5923a62999SShuo Chen  return sctx;
6023a62999SShuo Chen}
6123a62999SShuo Chen
62926c960eSShuo Chen// only works for non-blocking sockets
6323a62999SShuo Chenbool handshake(struct tls* cctx, struct tls* sctx)
6423a62999SShuo Chen{
6523a62999SShuo Chen  int client_done = false, server_done = false;
6623a62999SShuo Chen
6723a62999SShuo Chen  while (!(client_done && server_done))
6823a62999SShuo Chen  {
6923a62999SShuo Chen    if (!client_done)
7023a62999SShuo Chen    {
7123a62999SShuo Chen      int ret = tls_handshake(cctx);
72926c960eSShuo Chen      // printf("c %d\n", ret);
7323a62999SShuo Chen      if (ret == 0)
7423a62999SShuo Chen        client_done = true;
7523a62999SShuo Chen      else if (ret == -1)
7623a62999SShuo Chen      {
7723a62999SShuo Chen        printf("client handshake failed: %s\n", tls_error(cctx));
7823a62999SShuo Chen        break;
7923a62999SShuo Chen      }
8023a62999SShuo Chen    }
8123a62999SShuo Chen
8223a62999SShuo Chen    if (!server_done)
8323a62999SShuo Chen    {
8423a62999SShuo Chen      int ret = tls_handshake(sctx);
85926c960eSShuo Chen      // printf("s %d\n", ret);
8623a62999SShuo Chen      if (ret == 0)
8723a62999SShuo Chen        server_done = true;
8823a62999SShuo Chen      else if (ret == -1)
8923a62999SShuo Chen      {
90cc4062ffSShuo Chen        printf("server handshake failed: %s\n", tls_error(sctx));
9123a62999SShuo Chen        break;
9223a62999SShuo Chen      }
9323a62999SShuo Chen    }
9423a62999SShuo Chen  }
9523a62999SShuo Chen
9623a62999SShuo Chen  return client_done && server_done;
9723a62999SShuo Chen}
9823a62999SShuo Chen
99926c960eSShuo Chenvoid setBlockingIO(int fd)
100926c960eSShuo Chen{
101926c960eSShuo Chen  int flags = fcntl(fd, F_GETFL, 0);
102926c960eSShuo Chen  if (flags > 0)
103926c960eSShuo Chen  {
104926c960eSShuo Chen    printf("set blocking IO for %d\n", fd);
105926c960eSShuo Chen    fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
106926c960eSShuo Chen  }
107926c960eSShuo Chen}
108926c960eSShuo Chen
109926c960eSShuo Chenconst int N = 500;
110926c960eSShuo Chen
111926c960eSShuo Chenstruct Trial
112926c960eSShuo Chen{
113926c960eSShuo Chen  int blocks, block_size;
114926c960eSShuo Chen};
115926c960eSShuo Chen
116926c960eSShuo Chenvoid client_thread(struct tls* ctx)
117926c960eSShuo Chen{
118926c960eSShuo Chen  Timer t;
119926c960eSShuo Chen  t.start();
120926c960eSShuo Chen  for (int i = 0; i < N; ++i)
121926c960eSShuo Chen  {
122926c960eSShuo Chen    int ret = tls_handshake(ctx);
123926c960eSShuo Chen    if (ret != 0)
124926c960eSShuo Chen      printf("client err = %d\n", ret);
125926c960eSShuo Chen  }
126926c960eSShuo Chen  t.stop();
127926c960eSShuo Chen  printf("client %f secs, %f handshakes/sec\n", t.seconds(), N / t.seconds());
128926c960eSShuo Chen  while (true)
129926c960eSShuo Chen  {
130926c960eSShuo Chen    Trial trial = { 0, 0 };
131926c960eSShuo Chen
132926c960eSShuo Chen    int nr = tls_read(ctx, &trial, sizeof trial);
133926c960eSShuo Chen    if (nr == 0)
134926c960eSShuo Chen      break;
135926c960eSShuo Chen    assert(nr == sizeof trial);
136926c960eSShuo Chen    // printf("client read bs %d nb %d\n", trial.block_size, trial.blocks);
137926c960eSShuo Chen    if (trial.block_size == 0)
138926c960eSShuo Chen      break;
139926c960eSShuo Chen    char* buf = new char[trial.block_size];
140926c960eSShuo Chen    for (int i = 0; i < trial.blocks; ++i)
141926c960eSShuo Chen    {
142926c960eSShuo Chen      nr = tls_read(ctx, buf, trial.block_size);
143926c960eSShuo Chen      assert(nr == trial.block_size);
144926c960eSShuo Chen    }
145926c960eSShuo Chen    int64_t ack = static_cast<int64_t>(trial.blocks) * trial.block_size;
146926c960eSShuo Chen    int nw = tls_write(ctx, &ack, sizeof ack);
147926c960eSShuo Chen    assert(nw == sizeof ack);
148926c960eSShuo Chen    delete[] buf;
149926c960eSShuo Chen  }
150926c960eSShuo Chen  printf("client done\n");
151926c960eSShuo Chen  tls_close(ctx);
152926c960eSShuo Chen  tls_free(ctx);
153926c960eSShuo Chen}
154926c960eSShuo Chen
155926c960eSShuo Chenvoid send(int block_size, struct tls* ctx)
156926c960eSShuo Chen{
157926c960eSShuo Chen  double start = now();
158926c960eSShuo Chen  int total = 0;
159926c960eSShuo Chen  int blocks = 1024;
160926c960eSShuo Chen  char* message = new char[block_size];
161926c960eSShuo Chen  bzero(message, block_size);
162926c960eSShuo Chen  Timer t;
163926c960eSShuo Chen  while (now() - start < 10)
164926c960eSShuo Chen  {
165926c960eSShuo Chen    Trial trial = { blocks, block_size };
166926c960eSShuo Chen    int nw = tls_write(ctx, &trial, sizeof trial);
167926c960eSShuo Chen    assert(nw == sizeof trial);
168926c960eSShuo Chen    t.start();
169926c960eSShuo Chen    for (int i = 0; i < blocks; ++i)
170926c960eSShuo Chen    {
171926c960eSShuo Chen      nw = tls_write(ctx, message, block_size);
172926c960eSShuo Chen      if (nw != block_size)
173926c960eSShuo Chen        printf("bs %d nw %d\n", block_size, nw);
174926c960eSShuo Chen      assert(nw == block_size);
175926c960eSShuo Chen    }
176926c960eSShuo Chen    t.stop();
177926c960eSShuo Chen    int64_t ack = 0;
178926c960eSShuo Chen    int nr = tls_read(ctx, &ack, sizeof ack);
179926c960eSShuo Chen    assert(nr == sizeof ack);
180926c960eSShuo Chen    assert(ack == static_cast<int64_t>(blocks) * block_size);
181926c960eSShuo Chen    total += blocks;
182926c960eSShuo Chen    blocks *= 2;
183926c960eSShuo Chen  }
184926c960eSShuo Chen  double secs = now() - start;
185926c960eSShuo Chen  printf("bs %5d sec %.3f tot %d thr %.1fKB/s wr cpu %.3f\n", block_size, secs, total,
186926c960eSShuo Chen         block_size / secs * total / 1024, t.seconds());
187926c960eSShuo Chen  delete[] message;
188926c960eSShuo Chen}
189926c960eSShuo Chen
19023a62999SShuo Chenint main(int argc, char* argv[])
19123a62999SShuo Chen{
19223a62999SShuo Chen  int ret = tls_init();
19342b85340SShuo Chen  assert(ret == 0);
19442b85340SShuo Chen
19523a62999SShuo Chen  int fds[2];
19623a62999SShuo Chen  socketpair(AF_UNIX, SOCK_STREAM | SOCK_NONBLOCK, 0, fds);
19723a62999SShuo Chen
19823a62999SShuo Chen  struct tls* cctx = client(fds[0]);
19923a62999SShuo Chen  struct tls* sctx = server(fds[1]);
20042b85340SShuo Chen
20123a62999SShuo Chen  if (handshake(cctx, sctx))
20223a62999SShuo Chen    printf("cipher %s\n", tls_conn_cipher(cctx));
203cc4062ffSShuo Chen  else
204cc4062ffSShuo Chen    return -1;
205926c960eSShuo Chen
206926c960eSShuo Chen  setBlockingIO(fds[0]);
207926c960eSShuo Chen  setBlockingIO(fds[1]);
208926c960eSShuo Chen  muduo::Thread thr(boost::bind(client_thread, cctx), "clientThread");
209926c960eSShuo Chen  thr.start();
210926c960eSShuo Chen
211926c960eSShuo Chen  {
212926c960eSShuo Chen  Timer t;
213926c960eSShuo Chen  t.start();
214926c960eSShuo Chen  for (int i = 0; i < N; ++i)
215926c960eSShuo Chen  {
216926c960eSShuo Chen    int ret = tls_handshake(sctx);
217926c960eSShuo Chen    if (ret != 0)
218926c960eSShuo Chen      printf("server err = %d\n", ret);
219926c960eSShuo Chen  }
220926c960eSShuo Chen  t.stop();
221926c960eSShuo Chen  printf("server %f secs, %f handshakes/sec\n", t.seconds(), N / t.seconds());
222926c960eSShuo Chen  }
223926c960eSShuo Chen
224cc4062ffSShuo Chen  for (int i = 1024 * 16; i >= 1; i /= 4)
225926c960eSShuo Chen  {
226926c960eSShuo Chen    send(i, sctx);
227926c960eSShuo Chen  }
228926c960eSShuo Chen  tls_close(sctx);
229926c960eSShuo Chen  shutdown(fds[1], SHUT_RDWR);
230926c960eSShuo Chen  tls_free(sctx);
231926c960eSShuo Chen
232926c960eSShuo Chen  thr.join();
23342b85340SShuo Chen}
234