Skip to content

Commit 2cf6e9f

Browse files
authored
Merge pull request #419 from philljj/fix_dtls_threaded
Server and client dtls threaded examples.
2 parents 6a34cb5 + 11509fd commit 2cf6e9f

4 files changed

Lines changed: 634 additions & 231 deletions

File tree

dtls/client-dtls-threaded.c

Lines changed: 279 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,279 @@
1+
/*
2+
* client-dtls-threaded.c
3+
*
4+
* Copyright (C) 2006-2024 wolfSSL Inc.
5+
*
6+
* This file is part of wolfSSL. (formerly known as CyaSSL)
7+
*
8+
* wolfSSL is free software; you can redistribute it and/or modify
9+
* it under the terms of the GNU General Public License as published by
10+
* the Free Software Foundation; either version 2 of the License, or
11+
* (at your option) any later version.
12+
*
13+
* wolfSSL is distributed in the hope that it will be useful,
14+
* but WITHOUT ANY WARRANTY; without even the implied warranty of
15+
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16+
* GNU General Public License for more details.
17+
*
18+
* You should have received a copy of the GNU General Public License
19+
* along with this program; if not, write to the Free Software
20+
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
21+
*
22+
*=============================================================================
23+
*
24+
* A simple dtls client with configurable threadpool, for
25+
* instructional/learning purposes. Utilizes DTLS 1.2.
26+
*/
27+
28+
#include <wolfssl/options.h>
29+
#include <unistd.h>
30+
#include <wolfssl/ssl.h>
31+
#include <netdb.h>
32+
#include <signal.h>
33+
#include <sys/socket.h>
34+
#include <arpa/inet.h>
35+
#include <netinet/in.h>
36+
#include <stdio.h>
37+
#include <stdlib.h>
38+
#include <string.h>
39+
40+
#define MSGLEN 4096
41+
#define SERV_PORT 11111
42+
#define DTLS_NUMTHREADS 16
43+
44+
typedef struct {
45+
WOLFSSL * ssl;
46+
int activefd;
47+
WOLFSSL_CTX * ctx;
48+
} thread_args_t;
49+
50+
static void safer_shutdown(thread_args_t * args);
51+
static void * client_work(void * arg);
52+
53+
int
54+
main(int argc,
55+
char * argv[])
56+
{
57+
WOLFSSL_CTX * ctx = NULL; /* ctx shared by threads */
58+
const char * certs = "../certs/ca-cert.pem";
59+
int ret = 0;
60+
int n_threads = 2;
61+
pthread_t threads[DTLS_NUMTHREADS];
62+
thread_args_t args[DTLS_NUMTHREADS];
63+
int opt = 0;
64+
65+
memset(threads, 0, sizeof(threads));
66+
memset(args, 0, sizeof(args));
67+
68+
while ((opt = getopt(argc, argv, "t:?")) != -1) {
69+
switch (opt) {
70+
case 't':
71+
n_threads = atoi(optarg);
72+
break;
73+
74+
case '?':
75+
printf("usage:\n");
76+
printf(" ./client-dtls-threaded [-t n]\n");
77+
printf("\n");
78+
printf("description:\n");
79+
printf(" A simple dtls client with configurable threadpool.\n");
80+
printf(" Num allowed threads is: 1 <= n <= %d\n",
81+
DTLS_NUMTHREADS);
82+
default:
83+
return EXIT_FAILURE;
84+
}
85+
}
86+
87+
if (n_threads <= 0 || n_threads > DTLS_NUMTHREADS) {
88+
printf("error: invalid n_threads: %d\n", n_threads);
89+
return EXIT_FAILURE;
90+
}
91+
92+
/* Initialize wolfSSL before assigning ctx */
93+
wolfSSL_Init();
94+
95+
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
96+
if (ctx == NULL) {
97+
printf("error: wolfSSL_CTX_new failed\n");
98+
return EXIT_FAILURE;
99+
}
100+
101+
/* Load certificates into ctx variable */
102+
ret = wolfSSL_CTX_load_verify_locations(ctx, certs, 0);
103+
if (ret != SSL_SUCCESS) {
104+
printf("error: loading %s failed, please check the file\n", certs);
105+
return EXIT_FAILURE;
106+
}
107+
108+
for (size_t i = 0; i < n_threads; ++i) {
109+
args[i].ctx = ctx;
110+
ret = pthread_create(&threads[i], NULL, client_work, &args[i]);
111+
112+
if (ret == 0 ) {
113+
printf("info: spawned thread: %ld\n", (long)threads[i]);
114+
}
115+
else {
116+
printf("error: pthread_create returned %d\n", ret);
117+
threads[i] = 0;
118+
}
119+
sleep(1);
120+
}
121+
122+
for (size_t i = 0; i < n_threads; ++i) {
123+
if (threads[i]) {
124+
pthread_join(threads[i], NULL);
125+
printf("info: joined thread: %ld\n", (long)threads[i]);
126+
threads[i] = 0;
127+
}
128+
}
129+
130+
wolfSSL_CTX_free(ctx);
131+
wolfSSL_Cleanup();
132+
133+
return EXIT_SUCCESS;
134+
}
135+
136+
static void *
137+
client_work(void * args)
138+
{
139+
thread_args_t * thread_args = (thread_args_t *) args;
140+
int n_bytes = 0;
141+
int err1;
142+
struct sockaddr_in servAddr;
143+
char send_msg[MSGLEN];
144+
char recv_msg[MSGLEN];
145+
int ret = 0;
146+
const char * localhost_ip = "127.0.0.1";
147+
148+
/* Assign ssl variable */
149+
thread_args->ssl = wolfSSL_new(thread_args->ctx);
150+
if (thread_args->ssl == NULL) {
151+
printf("error: wolfSSL_new failed\n");
152+
return NULL;
153+
}
154+
155+
/* servAddr setup */
156+
memset(&servAddr, 0, sizeof(servAddr));
157+
servAddr.sin_family = AF_INET;
158+
servAddr.sin_port = htons(SERV_PORT);
159+
160+
ret = inet_pton(AF_INET, localhost_ip, &servAddr.sin_addr);
161+
if (ret != 1) {
162+
printf("error: inet_pton %s returned %d\n", localhost_ip, ret);
163+
return NULL;
164+
}
165+
166+
ret = wolfSSL_dtls_set_peer(thread_args->ssl, &servAddr, sizeof(servAddr));
167+
if (ret != SSL_SUCCESS) {
168+
printf("error: wolfSSL_dtls_set_peer returned %d\n", ret);
169+
return NULL;
170+
}
171+
172+
thread_args->activefd = socket(AF_INET, SOCK_DGRAM, 0);
173+
if (thread_args->activefd <= 0) {
174+
printf("error: socket returned %d\n", thread_args->activefd);
175+
return NULL;
176+
}
177+
178+
printf("info: opened socket: %d\n", thread_args->activefd);
179+
180+
/* Set the file descriptor for ssl and connect with ssl variable */
181+
wolfSSL_set_fd(thread_args->ssl, thread_args->activefd);
182+
if (wolfSSL_connect(thread_args->ssl) != SSL_SUCCESS) {
183+
err1 = wolfSSL_get_error(thread_args->ssl, 0);
184+
printf("error: thread %ld: wolfSSL_connect returned = %d, %s\n",
185+
(long)pthread_self(), err1,
186+
wolfSSL_ERR_reason_error_string(err1));
187+
return NULL;
188+
}
189+
190+
/* Simulate a simple protocol over DTLS that exchanges a
191+
* sequence of records, and checks we get correct records
192+
* from correct server threads. */
193+
long int server_tid = 0;
194+
const char * tid_str = NULL; /* Str to thread id in response. */
195+
196+
for (size_t i = 0; i < 4; ++i) {
197+
memset(send_msg, '\0', sizeof(send_msg));
198+
memset(recv_msg, '\0', sizeof(recv_msg));
199+
200+
char seq = '0' + (int) i;
201+
sprintf(send_msg, "msg %zu from client thread %ld\n", i,
202+
(long)pthread_self());
203+
204+
n_bytes = wolfSSL_write(thread_args->ssl, send_msg, strlen(send_msg));
205+
206+
if (n_bytes != strlen(send_msg)) {
207+
printf("error: wolfSSL_write returned %d", n_bytes);
208+
break;
209+
}
210+
211+
/* n is the # of bytes received */
212+
n_bytes = wolfSSL_read(thread_args->ssl, recv_msg, sizeof(recv_msg)-1);
213+
214+
if (n_bytes < 0) {
215+
printf("error: wolfSSL_read returned %d", n_bytes);
216+
break;
217+
}
218+
219+
recv_msg[n_bytes] = '\0';
220+
fputs(recv_msg, stdout);
221+
222+
/* Check the server replied with the correct sequence record, e.g.:
223+
* "msg 2 from server thread 140146322425536" */
224+
if (recv_msg[4] != seq) {
225+
printf("error: got msg %c, expected %c\n", recv_msg[4], seq);
226+
break;
227+
}
228+
229+
tid_str = &recv_msg[25];
230+
if (server_tid == 0) {
231+
/* Save the server thread id on message 0. */
232+
server_tid = atol(tid_str);
233+
}
234+
else {
235+
/* Compare saved thread id. */
236+
if (server_tid != atol(tid_str)) {
237+
printf("error: got rsp from server thread %ld, expected %ld\n",
238+
server_tid, atol(tid_str));
239+
break;
240+
}
241+
else {
242+
printf("info: got response from server thread %ld\n",
243+
server_tid);
244+
}
245+
}
246+
247+
sleep(1);
248+
}
249+
250+
safer_shutdown(thread_args);
251+
252+
return NULL;
253+
}
254+
255+
/* Small shutdown wrapper to safely clean up a thread's
256+
* connection. */
257+
static void
258+
safer_shutdown(thread_args_t * args)
259+
{
260+
if (args == NULL) {
261+
printf("error: safer_shutdown with null args\n");
262+
return;
263+
}
264+
265+
if (args->ssl != NULL) {
266+
printf("info: closed tls session: %p\n", (void*) args->ssl);
267+
wolfSSL_shutdown(args->ssl);
268+
wolfSSL_free(args->ssl);
269+
args->ssl = NULL;
270+
}
271+
272+
if (args->activefd > 0) {
273+
printf("info: closed socket: %d\n", args->activefd);
274+
close(args->activefd);
275+
args->activefd = 0;
276+
}
277+
278+
return;
279+
}

0 commit comments

Comments
 (0)