1/* test.c */
2/* $Id: test.c,v 1.1 2001/09/17 19:06:59 bodo Exp $ */
3
4#define L_PORT 9999
5#define C_PORT 443
6
7#include <arpa/inet.h>
8#include <assert.h>
9#include <errno.h>
10#include <fcntl.h>
11#include <netinet/in.h>
12#include <netinet/tcp.h>
13#include <stdlib.h>
14#include <stdio.h>
15#include <string.h>
16#include <sys/select.h>
17#include <sys/socket.h>
18#include <unistd.h>
19
20#include "test.h"
21#include "easy-tls.h"
22
23void
24test_process_init(int fd, int client_p, void *apparg)
25{
26    fprintf(stderr, "test_process_init(fd = %d, client_p = %d, apparg = %p)\n", fd, client_p, apparg);
27}
28
29void
30test_errflush(int child_p, char *errbuf, size_t num, void *apparg)
31{
32    fputs(errbuf, stderr);
33}
34
35
36int
37main(int argc, char *argv[])
38{
39    int s, fd, r;
40    FILE *conn_in;
41    FILE *conn_out;
42    char buf[256];
43    SSL_CTX *ctx;
44    int client_p = 0;
45    int port;
46    int tls = 0;
47    char infobuf[TLS_INFO_SIZE + 1];
48
49    if (argc > 1 && argv[1][0] == '-') {
50	fputs("Usage: test [port]                   -- server\n"
51	      "       test num.num.num.num [port]   -- client\n",
52	      stderr);
53	exit(1);
54    }
55
56    if (argc > 1) {
57	if (strchr(argv[1], '.')) {
58	    client_p = 1;
59	}
60    }
61
62    fputs(client_p ? "Client\n" : "Server\n", stderr);
63
64    {
65	struct tls_create_ctx_args a = tls_create_ctx_defaultargs();
66	a.client_p = client_p;
67	a.certificate_file = "cert.pem";
68	a.key_file = "cert.pem";
69	a.ca_file = "cacerts.pem";
70
71	ctx = tls_create_ctx(a, NULL);
72	if (ctx == NULL)
73	    exit(1);
74    }
75
76    s = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
77    if (s == -1) {
78	perror("socket");
79	exit(1);
80    }
81
82    if (client_p) {
83	struct sockaddr_in addr;
84	size_t addr_len = sizeof addr;
85
86	addr.sin_family = AF_INET;
87	assert(argc > 1);
88	if (argc > 2)
89	    sscanf(argv[2], "%d", &port);
90	else
91	    port = C_PORT;
92	addr.sin_port = htons(port);
93	addr.sin_addr.s_addr = inet_addr(argv[1]);
94
95	r = connect(s, &addr, addr_len);
96	if (r != 0) {
97	    perror("connect");
98	    exit(1);
99	}
100	fd = s;
101	fprintf(stderr, "Connect (fd = %d).\n", fd);
102    } else {
103	/* server */
104	{
105	    int i = 1;
106
107	    r = setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (void *) &i, sizeof i);
108	    if (r == -1) {
109		perror("setsockopt");
110		exit(1);
111	    }
112	}
113
114	{
115	    struct sockaddr_in addr;
116	    size_t addr_len = sizeof addr;
117
118	    if (argc > 1)
119		sscanf(argv[1], "%d", &port);
120	    else
121		port = L_PORT;
122	    addr.sin_family = AF_INET;
123	    addr.sin_port = htons(port);
124	    addr.sin_addr.s_addr = INADDR_ANY;
125
126	    r = bind(s, &addr, addr_len);
127	    if (r != 0) {
128		perror("bind");
129		exit(1);
130	    }
131	}
132
133	r = listen(s, 1);
134	if (r == -1) {
135	    perror("listen");
136	    exit(1);
137	}
138
139	fprintf(stderr, "Listening at port %i.\n", port);
140
141	fd = accept(s, NULL, 0);
142	if (fd == -1) {
143	    perror("accept");
144	    exit(1);
145	}
146
147	fprintf(stderr, "Accept (fd = %d).\n", fd);
148    }
149
150    conn_in = fdopen(fd, "r");
151    if (conn_in == NULL) {
152	perror("fdopen");
153	exit(1);
154    }
155    conn_out = fdopen(fd, "w");
156    if (conn_out == NULL) {
157	perror("fdopen");
158	exit(1);
159    }
160
161    setvbuf(conn_in, NULL, _IOLBF, 256);
162    setvbuf(conn_out, NULL, _IOLBF, 256);
163
164    while (fgets(buf, sizeof buf, stdin) != NULL) {
165	if (buf[0] == 'W') {
166	    fprintf(conn_out, "%.*s\r\n", (int)(strlen(buf + 1) - 1), buf + 1);
167	    fprintf(stderr, ">>> %.*s\n", (int)(strlen(buf + 1) - 1), buf + 1);
168	} else if (buf[0] == 'C') {
169	    fprintf(stderr, "Closing.\n");
170	    fclose(conn_in);
171	    fclose(conn_out);
172	    exit(0);
173	} else if (buf[0] == 'R') {
174	    int lines = 0;
175
176	    sscanf(buf + 1, "%d", &lines);
177	    do {
178		if (fgets(buf, sizeof buf, conn_in) == NULL) {
179		    if (ferror(conn_in)) {
180			fprintf(stderr, "ERROR\n");
181			exit(1);
182		    }
183		    fprintf(stderr, "CLOSED\n");
184		    return 0;
185		}
186		fprintf(stderr, "<<< %s", buf);
187	    } while (--lines > 0);
188	} else if (buf[0] == 'T') {
189	    int infofd;
190
191	    tls++;
192	    {
193		struct tls_start_proxy_args a = tls_start_proxy_defaultargs();
194		a.fd = fd;
195		a.client_p = client_p;
196		a.ctx = ctx;
197		a.infofd = &infofd;
198		r = tls_start_proxy(a, NULL);
199	    }
200	    assert(r != 1);
201	    if (r != 0) {
202		fprintf(stderr, "tls_start_proxy failed: %d\n", r);
203		switch (r) {
204		case -1:
205		    fputs("socketpair", stderr); break;
206		case 2:
207		    fputs("FD_SETSIZE exceeded", stderr); break;
208		case -3:
209		    fputs("pipe", stderr); break;
210		case -4:
211		    fputs("fork", stderr); break;
212		case -5:
213		    fputs("dup2", stderr); break;
214		default:
215		    fputs("?", stderr);
216		}
217		if (r < 0)
218		    perror("");
219		else
220		    fputc('\n', stderr);
221		exit(1);
222	    }
223
224	    r = read(infofd, infobuf, sizeof infobuf - 1);
225	    if (r > 0) {
226		const char *info = infobuf;
227		const char *eol;
228
229		infobuf[r] = '\0';
230		while ((eol = strchr(info, '\n')) != NULL) {
231		    fprintf(stderr, "+++ `%.*s'\n", eol - info, info);
232		    info = eol+1;
233		}
234		close (infofd);
235	    }
236	} else {
237	    fprintf(stderr, "W...  write line to network\n"
238		    "R[n]  read line (n lines) from network\n"
239		    "C     close\n"
240		    "T     start %sTLS proxy\n", tls ? "another " : "");
241	}
242    }
243    return 0;
244}
245