1 /* This example, or test, is a moron test where the library is being hammered in all the possible ways randomly over time */
2
3 #include <libusockets.h>
4 const int SSL = 1;
5
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <time.h>
10 #include <stdbool.h>
11
12 int port;
13 int opened_connections, closed_connections, operations_done;
14 struct us_socket_context_t *server_context, *client_context;
15 struct us_listen_socket_t *listen_socket;
16
17 char client_msg[] = "Hello from client";
18 char server_msg[] = "Hello from server";
19
20 // also make sure to have socket ext data
21 // and context ext data
22 // and loop ext data
23
24 bool client_received_data;
25 bool server_received_data;
26
27 struct socket_context {
28 char *backpressure;
29 int length;
30 };
31
on_wakeup(struct us_loop_t * loop)32 void on_wakeup(struct us_loop_t *loop) {
33 // note: we expose internal functions to trigger a timeout sweep to find bugs
34 extern void us_internal_timer_sweep(struct us_loop_t * loop);
35 us_internal_timer_sweep(loop);
36 }
37
38 // maybe use thse to count spurious wakeups?
39 // that is, if we get tons of pre/post over and over without any events
40 // that would point towards 100% cpu usage kind of bugs
on_pre(struct us_loop_t * loop)41 void on_pre(struct us_loop_t *loop) {
42 // printf("PRE\n");
43 }
44
on_post(struct us_loop_t * loop)45 void on_post(struct us_loop_t *loop) {
46 // check if we did perform_random_operation
47 }
48
write_buffered(int SSL,struct us_socket_t * s,const char * data,int length)49 int write_buffered(int SSL, struct us_socket_t *s, const char *data, int length) {
50
51 struct socket_context *ctx = (struct socket_context *)us_socket_ext(SSL, s);
52
53 int written = us_socket_write(SSL, s, data, length, 0);
54 if (written != length) {
55 char *new_buffer = (char *)malloc(ctx->length + length - written);
56 memcpy(new_buffer, ctx->backpressure, ctx->length);
57 memcpy(new_buffer + ctx->length, data + written, length - written);
58 free(ctx->backpressure);
59 ctx->backpressure = new_buffer;
60 ctx->length += length - written;
61 }
62 return written;
63 }
64
write_backpressure(int SSL,struct us_socket_t * s)65 void write_backpressure(int SSL, struct us_socket_t *s) {
66
67 struct socket_context *ctx = (struct socket_context *)us_socket_ext(SSL, s);
68
69 /* Continue writing out our backpressure */
70 int written = us_socket_write(SSL, s, ctx->backpressure, ctx->length, 0);
71 if (written != ctx->length) {
72 char *new_buffer = (char *)malloc(ctx->length - written);
73 memcpy(new_buffer, ctx->backpressure, ctx->length - written);
74 free(ctx->backpressure);
75 ctx->backpressure = new_buffer;
76 ctx->length -= written;
77 } else {
78 free(ctx->backpressure);
79 ctx->length = 0;
80 }
81 }
82
on_server_socket_writable(struct us_socket_t * s)83 struct us_socket_t *on_server_socket_writable(struct us_socket_t *s) {
84 printf("on_server_socket_writable\n");
85
86 write_backpressure(SSL, s);
87
88 /* Peer is not boring */
89 us_socket_timeout(SSL, s, 30);
90
91 return s;
92 }
93
on_client_socket_writable(struct us_socket_t * s)94 struct us_socket_t *on_client_socket_writable(struct us_socket_t *s) {
95 printf("on_client_socket_writable\n");
96
97 write_backpressure(SSL, s);
98
99 /* Peer is not boring */
100 us_socket_timeout(SSL, s, 30);
101
102 return s;
103 }
104
on_server_socket_close(struct us_socket_t * s,int code,void * reason)105 struct us_socket_t *on_server_socket_close(struct us_socket_t *s, int code, void *reason) {
106 printf("on_server_socket_close\n");
107
108 us_listen_socket_close(SSL, listen_socket);
109
110 return s;
111 }
112
on_client_socket_close(struct us_socket_t * s,int code,void * reason)113 struct us_socket_t *on_client_socket_close(struct us_socket_t *s, int code, void *reason) {
114
115 printf("on_client_socket_close\n");
116
117 return s;
118 }
119
on_server_socket_end(struct us_socket_t * s)120 struct us_socket_t *on_server_socket_end(struct us_socket_t *s) {
121
122 return us_socket_close(SSL, s, 0, NULL);
123 }
124
on_client_socket_end(struct us_socket_t * s)125 struct us_socket_t *on_client_socket_end(struct us_socket_t *s) {
126
127 return us_socket_close(SSL, s, 0, NULL);
128 }
129
on_server_socket_data(struct us_socket_t * s,char * data,int length)130 struct us_socket_t *on_server_socket_data(struct us_socket_t *s, char *data, int length) {
131
132 if (length == 0) {
133 printf("ERROR: Got data event with no data\n");
134 exit(-1);
135 }
136 /* Print the data we received */
137 printf("on_server_socket_data: received '%.*s'\n", length, data);
138
139 server_received_data = true;
140
141 write_buffered(SSL, s, server_msg, sizeof(server_msg));
142
143 return s;
144 }
145
on_client_socket_data(struct us_socket_t * s,char * data,int length)146 struct us_socket_t *on_client_socket_data(struct us_socket_t *s, char *data, int length) {
147
148 if (length == 0) {
149 printf("ERROR: Got data event with no data\n");
150 exit(-1);
151 }
152 /* Print the data we received */
153 printf("on_client_socket_data: received '%.*s'\n", length, data);
154
155 client_received_data = true;
156
157 return us_socket_close(SSL, s, 0, NULL);
158 }
159
on_server_socket_open(struct us_socket_t * s,int is_client,char * ip,int ip_length)160 struct us_socket_t *on_server_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {
161
162 printf("on_server_socket_open\n");
163 struct socket_context *ctx = (struct socket_context *)us_socket_ext(SSL, s);
164
165 ctx->backpressure = 0;
166 ctx->length = 0;
167
168 /* Start a timeout to close the socket if boring */
169 us_socket_timeout(SSL, s, 30);
170
171 printf("Client connected\n");
172
173 return s;
174 }
175
on_client_socket_open(struct us_socket_t * s,int is_client,char * ip,int ip_length)176 struct us_socket_t *on_client_socket_open(struct us_socket_t *s, int is_client, char *ip, int ip_length) {
177
178 printf("on_client_socket_open\n");
179
180 struct socket_context *ctx = (struct socket_context *)us_socket_ext(SSL, s);
181
182 ctx->backpressure = 0;
183 ctx->length = 0;
184
185 write_buffered(SSL, s, client_msg, sizeof(client_msg));
186
187 return s;
188 }
189
on_client_socket_timeout(struct us_socket_t * s)190 struct us_socket_t *on_client_socket_timeout(struct us_socket_t *s) {
191 return s;
192 }
193
on_server_socket_timeout(struct us_socket_t * s)194 struct us_socket_t *on_server_socket_timeout(struct us_socket_t *s) {
195 return s;
196 }
197
expect_peer_verify(const char * test_name,bool expect_data_exchanged,struct us_socket_context_options_t server_options,struct us_socket_context_options_t client_options)198 int expect_peer_verify(const char *test_name, bool expect_data_exchanged,
199 struct us_socket_context_options_t server_options,
200 struct us_socket_context_options_t client_options) {
201
202
203 printf("----------------------------------------\n"
204 "[[ %s ]]\n"
205 " server_key: %s\n"
206 " server_crt: %s\n"
207 " server_ca: %s\n"
208 " client_crt: %s\n"
209 " client_key: %s\n"
210 " client_ca: %s\n\n",
211 test_name,
212 server_options.key_file_name,
213 server_options.cert_file_name,
214 server_options.ca_file_name,
215 client_options.key_file_name,
216 client_options.cert_file_name,
217 client_options.ca_file_name);
218
219 srand(time(0));
220 server_received_data = false;
221 client_received_data = false;
222
223 struct us_loop_t *loop = us_create_loop(0, on_wakeup, on_pre, on_post, 0);
224
225 server_context = us_create_socket_context(SSL, loop, sizeof(struct socket_context), server_options);
226
227 us_socket_context_on_open(SSL, server_context, on_server_socket_open);
228 us_socket_context_on_data(SSL, server_context, on_server_socket_data);
229 us_socket_context_on_writable(SSL, server_context, on_server_socket_writable);
230 us_socket_context_on_close(SSL, server_context, on_server_socket_close);
231 us_socket_context_on_timeout(SSL, server_context, on_server_socket_timeout);
232 us_socket_context_on_end(SSL, server_context, on_server_socket_end);
233
234 port = 3000;
235 listen_socket = us_socket_context_listen(SSL, server_context, "127.0.0.1", port, 0, sizeof(struct socket_context));
236 while (!listen_socket) {
237 listen_socket = us_socket_context_listen(SSL, server_context, "127.0.0.1", ++port, 0, sizeof(struct socket_context));
238 }
239 printf("Server listening on 127.0.0.1:%d\n", port);
240
241 client_context = us_create_socket_context(SSL, loop, sizeof(struct socket_context), client_options);
242 us_socket_context_on_open(SSL, client_context, on_client_socket_open);
243 us_socket_context_on_data(SSL, client_context, on_client_socket_data);
244 us_socket_context_on_writable(SSL, client_context, on_client_socket_writable);
245 us_socket_context_on_close(SSL, client_context, on_client_socket_close);
246 us_socket_context_on_timeout(SSL, client_context, on_client_socket_timeout);
247 us_socket_context_on_end(SSL, client_context, on_client_socket_end);
248
249 us_socket_context_connect(SSL, client_context, "127.0.0.1", port, NULL, 0, sizeof(struct socket_context));
250 us_loop_run(loop);
251
252 us_socket_context_free(SSL, server_context);
253 us_socket_context_free(SSL, client_context);
254 us_loop_free(loop);
255
256 bool data_exchanged = server_received_data && client_received_data;
257 if (!!expect_data_exchanged != !!data_exchanged) {
258
259 fprintf(stderr, "\n~ ERROR: expected data_echanged == %s, got %s\n\n",
260 (expect_data_exchanged ? "true" : "false"),
261 (data_exchanged ? "true" : "false"));
262 exit(1);
263 }
264
265 printf("[[ OK ]]\n\n");
266 return 0;
267 }
268
main()269 int main() {
270
271 expect_peer_verify("trusted client ca", true,
272 (struct us_socket_context_options_t){
273 .key_file_name = ".certs/valid_server_key.pem",
274 .cert_file_name = ".certs/valid_server_crt.pem",
275 .ca_file_name = ".certs/valid_ca_crt.pem"
276 },
277 (struct us_socket_context_options_t){
278 .key_file_name = ".certs/valid_client_key.pem",
279 .cert_file_name = ".certs/valid_client_crt.pem",
280 .ca_file_name = ".certs/valid_ca_crt.pem"
281 });
282
283
284 expect_peer_verify("untrusted client ca", false,
285 (struct us_socket_context_options_t){
286 .key_file_name = ".certs/valid_server_key.pem",
287 .cert_file_name = ".certs/valid_server_crt.pem",
288 .ca_file_name = ".certs/valid_ca_crt.pem"
289 },
290 (struct us_socket_context_options_t){
291 .key_file_name = ".certs/invalid_client_key.pem",
292 .cert_file_name = ".certs/invalid_client_crt.pem",
293 .ca_file_name = ".certs/valid_ca_crt.pem"
294 });
295
296 expect_peer_verify("trusted selfsigned client", true,
297 (struct us_socket_context_options_t){
298 .key_file_name = ".certs/valid_server_key.pem",
299 .cert_file_name = ".certs/valid_server_crt.pem",
300 .ca_file_name = ".certs/selfsigned_client_crt.pem"
301 },
302 (struct us_socket_context_options_t){
303 .key_file_name = ".certs/selfsigned_client_key.pem",
304 .cert_file_name = ".certs/selfsigned_client_crt.pem",
305 .ca_file_name = ".certs/valid_ca_crt.pem"
306 });
307
308 expect_peer_verify("untrusted selfsigned client", false,
309 (struct us_socket_context_options_t){
310 .key_file_name = ".certs/valid_server_key.pem",
311 .cert_file_name = ".certs/valid_server_crt.pem",
312 .ca_file_name = ".certs/valid_ca_crt.pem"
313 },
314 (struct us_socket_context_options_t){
315 .key_file_name = ".certs/selfsigned_client_key.pem",
316 .cert_file_name = ".certs/selfsigned_client_crt.pem",
317 .ca_file_name = ".certs/valid_ca_crt.pem"
318 });
319
320 expect_peer_verify("peer verify disabled", true,
321 (struct us_socket_context_options_t){
322 .key_file_name = ".certs/valid_server_key.pem",
323 .cert_file_name = ".certs/valid_server_crt.pem"
324 },
325 (struct us_socket_context_options_t){
326 .key_file_name = ".certs/valid_client_key.pem",
327 .cert_file_name = ".certs/valid_client_crt.pem"
328 });
329
330 }
331