Skip to content

Commit cea1d08

Browse files
committed
Server and client dtls threaded examples.
1 parent 6a34cb5 commit cea1d08

4 files changed

Lines changed: 592 additions & 231 deletions

File tree

dtls/client-dtls-threaded.c

Lines changed: 269 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,269 @@
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, "vt:n::?")) != -1) {
69+
switch (opt) {
70+
case 't':
71+
n_threads = atoi(optarg);
72+
break;
73+
74+
case '?':
75+
default:
76+
return EXIT_FAILURE;
77+
}
78+
}
79+
80+
if (n_threads <= 0 || n_threads > DTLS_NUMTHREADS) {
81+
printf("error: invalid n_threads: %d\n", n_threads);
82+
return EXIT_FAILURE;
83+
}
84+
85+
/* Initialize wolfSSL before assigning ctx */
86+
wolfSSL_Init();
87+
88+
ctx = wolfSSL_CTX_new(wolfDTLSv1_2_client_method());
89+
if (ctx == NULL) {
90+
printf("error: wolfSSL_CTX_new failed\n");
91+
return EXIT_FAILURE;
92+
}
93+
94+
/* Load certificates into ctx variable */
95+
ret = wolfSSL_CTX_load_verify_locations(ctx, certs, 0);
96+
if (ret != SSL_SUCCESS) {
97+
printf("error: loading %s failed, please check the file\n", certs);
98+
return EXIT_FAILURE;
99+
}
100+
101+
for (size_t i = 0; i < n_threads; ++i) {
102+
args[i].ctx = ctx;
103+
ret = pthread_create(&threads[i], NULL, client_work, &args[i]);
104+
105+
if (ret == 0 ) {
106+
printf("info: spawned thread: %ld\n", threads[i]);
107+
}
108+
else {
109+
printf("error: pthread_create returned %d\n", ret);
110+
threads[i] = 0;
111+
}
112+
sleep(1);
113+
}
114+
115+
for (size_t i = 0; i < n_threads; ++i) {
116+
if (threads[i]) {
117+
pthread_join(threads[i], NULL);
118+
printf("info: joined thread: %ld\n", threads[i]);
119+
threads[i] = 0;
120+
}
121+
}
122+
123+
wolfSSL_CTX_free(ctx);
124+
wolfSSL_Cleanup();
125+
126+
return EXIT_SUCCESS;
127+
}
128+
129+
static void *
130+
client_work(void * args)
131+
{
132+
thread_args_t * thread_args = (thread_args_t *) args;
133+
int n_bytes = 0;
134+
int err1;
135+
struct sockaddr_in servAddr;
136+
char send_msg[MSGLEN];
137+
char recv_msg[MSGLEN];
138+
int ret = 0;
139+
const char * localhost_ip = "127.0.0.1";
140+
141+
/* Assign ssl variable */
142+
thread_args->ssl = wolfSSL_new(thread_args->ctx);
143+
if (thread_args->ssl == NULL) {
144+
printf("error: wolfSSL_new failed\n");
145+
return NULL;
146+
}
147+
148+
/* servAddr setup */
149+
memset(&servAddr, 0, sizeof(servAddr));
150+
servAddr.sin_family = AF_INET;
151+
servAddr.sin_port = htons(SERV_PORT);
152+
153+
ret = inet_pton(AF_INET, localhost_ip, &servAddr.sin_addr);
154+
if (ret != 1) {
155+
printf("error: inet_pton %s returned %d\n", localhost_ip, ret);
156+
return NULL;
157+
}
158+
159+
ret = wolfSSL_dtls_set_peer(thread_args->ssl, &servAddr, sizeof(servAddr));
160+
if (ret != SSL_SUCCESS) {
161+
printf("error: wolfSSL_dtls_set_peer returned %d\n", ret);
162+
return NULL;
163+
}
164+
165+
thread_args->activefd = socket(AF_INET, SOCK_DGRAM, 0);
166+
if (thread_args->activefd <= 0) {
167+
printf("error: socket returned %d\n", thread_args->activefd);
168+
return NULL;
169+
}
170+
171+
/* Set the file descriptor for ssl and connect with ssl variable */
172+
wolfSSL_set_fd(thread_args->ssl, thread_args->activefd);
173+
if (wolfSSL_connect(thread_args->ssl) != SSL_SUCCESS) {
174+
err1 = wolfSSL_get_error(thread_args->ssl, 0);
175+
printf("error: thread %ld: wolfSSL_connect returned = %d, %s\n",
176+
pthread_self(), err1,
177+
wolfSSL_ERR_reason_error_string(err1));
178+
return NULL;
179+
}
180+
181+
/* Simulate a simple protocol over DTLS that exchanges a
182+
* sequence of records, and checks we get correct records
183+
* from correct server threads. */
184+
long int server_tid = 0;
185+
const char * tid_str = NULL; /* Str to thread id in response. */
186+
187+
for (size_t i = 0; i < 4; ++i) {
188+
char seq = '0' + (int) i;
189+
sprintf(send_msg, "msg %zu from client thread %ld\n", i,
190+
pthread_self());
191+
192+
n_bytes = wolfSSL_write(thread_args->ssl, send_msg, strlen(send_msg));
193+
194+
if (n_bytes != strlen(send_msg)) {
195+
printf("error: wolfSSL_write returned %d", n_bytes);
196+
break;
197+
}
198+
199+
/* n is the # of bytes received */
200+
n_bytes = wolfSSL_read(thread_args->ssl, recv_msg, sizeof(recv_msg)-1);
201+
202+
if (n_bytes < 0) {
203+
printf("error: wolfSSL_read returned %d", n_bytes);
204+
break;
205+
}
206+
207+
recv_msg[n_bytes] = '\0';
208+
fputs(recv_msg, stdout);
209+
210+
/* Check the server replied with the correct sequence record, e.g.:
211+
* "msg 2 from server thread 140146322425536" */
212+
if (recv_msg[4] != seq) {
213+
printf("error: got msg %c, expected %c\n", recv_msg[5], seq);
214+
break;
215+
}
216+
217+
tid_str = &recv_msg[25];
218+
if (server_tid == 0) {
219+
/* Save the server thread id on message 0. */
220+
server_tid = atol(tid_str);
221+
}
222+
else {
223+
/* Compare saved thread id. */
224+
if (server_tid != atol(tid_str)) {
225+
printf("error: got rsp from server thread %ld, expected %ld\n",
226+
server_tid, atol(tid_str));
227+
break;
228+
}
229+
else {
230+
printf("info: got response from server thread %ld\n",
231+
server_tid);
232+
}
233+
}
234+
235+
sleep(1);
236+
}
237+
238+
safer_shutdown(thread_args);
239+
240+
return NULL;
241+
}
242+
243+
/* Small shutdown wrapper to safely clean up a thread's
244+
* connection. */
245+
static void
246+
safer_shutdown(thread_args_t * args)
247+
{
248+
if (args == NULL) {
249+
printf("error: safer_shutdown with null args\n");
250+
return;
251+
}
252+
253+
if (args->ssl != NULL) {
254+
printf("info: closed tls session: %p\n", (void*) args->ssl);
255+
wolfSSL_shutdown(args->ssl);
256+
wolfSSL_free(args->ssl);
257+
args->ssl = NULL;
258+
}
259+
260+
if (args->activefd > 0) {
261+
printf("info: closed socket: %d\n", args->activefd);
262+
close(args->activefd);
263+
args->activefd = 0;
264+
}
265+
266+
return;
267+
}
268+
269+

0 commit comments

Comments
 (0)