text: /* test.c */
  /* $Id: test.c,v 1.1 2001/09/17 19:06:59 bodo Exp $ */
  
  #define L_PORT 9999
  #define C_PORT 443
  
  #include <arpa/inet.h>
  #include <assert.h>
  #include <errno.h>
  #include <fcntl.h>
  #include <netinet/in.h>
  #include <netinet/tcp.h>
  #include <stdlib.h>
  #include <stdio.h>
  #include <string.h>
  #include <sys/select.h>
  #include <sys/socket.h>
  #include <unistd.h>
  
  #include "test.h"
  #include "easy-tls.h"
  
  void test_process_init(int fd, int client_p, void *apparg)
  {
      fprintf(stderr,
              "test_process_init(fd = %d, client_p = %d, apparg = %p)\n", fd,
              client_p, apparg);
  }
  
  void test_errflush(int child_p, char *errbuf, size_t num, void *apparg)
  {
      fputs(errbuf, stderr);
  }
  
  int main(int argc, char *argv[])
  {
      int s, fd, r;
      FILE *conn_in;
      FILE *conn_out;
      char buf[256];
      SSL_CTX *ctx;
      int client_p = 0;
      int port;
      int tls = 0;
      char infobuf[TLS_INFO_SIZE + 1];
  
      if (argc > 1 && argv[1][0] == '-') {
          fputs("Usage: test [port]                   -- server\n"
                "       test num.num.num.num [port]   -- client\n", stderr);
          exit(1);
      }
  
      if (argc > 1) {
          if (strchr(argv[1], '.')) {
              client_p = 1;
          }
      }
  
      fputs(client_p ? "Client\n" : "Server\n", stderr);
  
      {
          struct tls_create_ctx_args a = tls_create_ctx_defaultargs();
          a.client_p = client_p;
          a.certificate_file = "cert.pem";
          a.key_file = "cert.pem";
          a.ca_file = "cacerts.pem";
  
          ctx = tls_create_ctx(a, NULL);
          if (ctx == NULL)
              exit(1);
      }
  
      s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
      if (s == -1) {
          perror("socket");
          exit(1);
      }
  
      if (client_p) {
          struct sockaddr_in addr;
          size_t addr_len = sizeof addr;
  
          addr.sin_family = AF_INET;
          assert(argc > 1);
          if (argc > 2)
              sscanf(argv[2], "%d", &port);
          else
              port = C_PORT;
          addr.sin_port = htons(port);
          addr.sin_addr.s_addr = inet_addr(argv[1]);
  
          r = connect(s, &addr, addr_len);
          if (r != 0) {
              perror("connect");
              exit(1);
          }
          fd = s;
          fprintf(stderr, "Connect (fd = %d).\n", fd);
      } else {
          /* server */
          {
              int i = 1;
  
              r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *)&i, sizeof i);
              if (r == -1) {
                  perror("setsockopt");
                  exit(1);
              }
          }
  
          {
              struct sockaddr_in addr;
              size_t addr_len = sizeof addr;
  
              if (argc > 1)
                  sscanf(argv[1], "%d", &port);
              else
                  port = L_PORT;
              addr.sin_family = AF_INET;
              addr.sin_port = htons(port);
              addr.sin_addr.s_addr = INADDR_ANY;
  
              r = bind(s, &addr, addr_len);
              if (r != 0) {
                  perror("bind");
                  exit(1);
              }
          }
  
          r = listen(s, 1);
          if (r == -1) {
              perror("listen");
              exit(1);
          }
  
          fprintf(stderr, "Listening at port %i.\n", port);
  
          fd = accept(s, NULL, 0);
          if (fd == -1) {
              perror("accept");
              exit(1);
          }
  
          fprintf(stderr, "Accept (fd = %d).\n", fd);
      }
  
      conn_in = fdopen(fd, "r");
      if (conn_in == NULL) {
          perror("fdopen");
          exit(1);
      }
      conn_out = fdopen(fd, "w");
      if (conn_out == NULL) {
          perror("fdopen");
          exit(1);
      }
  
      setvbuf(conn_in, NULL, _IOLBF, 256);
      setvbuf(conn_out, NULL, _IOLBF, 256);
  
      while (fgets(buf, sizeof buf, stdin) != NULL) {
          if (buf[0] == 'W') {
              fprintf(conn_out, "%.*s\r\n", (int)(strlen(buf + 1) - 1),
                      buf + 1);
              fprintf(stderr, ">>> %.*s\n", (int)(strlen(buf + 1) - 1),
                      buf + 1);
          } else if (buf[0] == 'C') {
              fprintf(stderr, "Closing.\n");
              fclose(conn_in);
              fclose(conn_out);
              exit(0);
          } else if (buf[0] == 'R') {
              int lines = 0;
  
              sscanf(buf + 1, "%d", &lines);
              do {
                  if (fgets(buf, sizeof buf, conn_in) == NULL) {
                      if (ferror(conn_in)) {
                          fprintf(stderr, "ERROR\n");
                          exit(1);
                      }
                      fprintf(stderr, "CLOSED\n");
                      return 0;
                  }
                  fprintf(stderr, "<<< %s", buf);
              } while (--lines > 0);
          } else if (buf[0] == 'T') {
              int infofd;
  
              tls++;
              {
                  struct tls_start_proxy_args a = tls_start_proxy_defaultargs();
                  a.fd = fd;
                  a.client_p = client_p;
                  a.ctx = ctx;
                  a.infofd = &infofd;
                  r = tls_start_proxy(a, NULL);
              }
              assert(r != 1);
              if (r != 0) {
                  fprintf(stderr, "tls_start_proxy failed: %d\n", r);
                  switch (r) {
                  case -1:
                      fputs("socketpair", stderr);
                      break;
                  case 2:
                      fputs("FD_SETSIZE exceeded", stderr);
                      break;
                  case -3:
                      fputs("pipe", stderr);
                      break;
                  case -4:
                      fputs("fork", stderr);
                      break;
                  case -5:
                      fputs("dup2", stderr);
                      break;
                  default:
                      fputs("?", stderr);
                  }
                  if (r < 0)
                      perror("");
                  else
                      fputc('\n', stderr);
                  exit(1);
              }
  
              r = read(infofd, infobuf, sizeof infobuf - 1);
              if (r > 0) {
                  const char *info = infobuf;
                  const char *eol;
  
                  infobuf[r] = '\0';
                  while ((eol = strchr(info, '\n')) != NULL) {
                      fprintf(stderr, "+++ `%.*s'\n", eol - info, info);
                      info = eol + 1;
                  }
                  close(infofd);
              }
          } else {
              fprintf(stderr, "W...  write line to network\n"
                      "R[n]  read line (n lines) from network\n"
                      "C     close\n"
                      "T     start %sTLS proxy\n", tls ? "another " : "");
          }
      }
      return 0;
  }
  