2 /* This is needed for apple */
3 #define __APPLE_USE_RFC_3542
10 #include <netinet/in.h>
11 #include <sys/types.h>
12 #include <sys/socket.h>
22 #define DTLS_PRIVATE_KEY_SIZE (32)
23 #define DTLS_PUBLIC_KEY_SIZE (64)
26 #define DEFAULT_PORT 20220
31 * General purpose byte array structure.
33 * Contains pointer to array of bytes and it's length.
38 uint8_t *data; /**< Pointer to the byte array */
39 size_t len; /**< Data size */
43 /**@def BYTE_ARRAY_INITIALIZER
45 * Initializes of existing byte array pointer to \a NULL.
47 #undef BYTE_ARRAY_INITIALIZER
48 #define BYTE_ARRAY_INITIALIZER {NULL, 0}
51 #define X509_OPTIONS "x:r:u:"
52 #define SERVER_CRT_LEN 295
53 static const unsigned char g_server_certificate[SERVER_CRT_LEN] = {
55 0x30, 0x82, 0x01, 0x20, 0x30, 0x81, 0xc4, 0xa0,
56 0x03, 0x02, 0x01, 0x01, 0x02, 0x02, 0x02, 0x37,
57 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0xce,
58 0x3d, 0x04, 0x03, 0x02, 0x05, 0x00, 0x30, 0x17,
59 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55, 0x04,
60 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61, 0x6c,
61 0x20, 0x49, 0x53, 0x53, 0x55, 0x45, 0x52, 0x30,
62 0x1e, 0x17, 0x0d, 0x31, 0x33, 0x30, 0x31, 0x30,
63 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
64 0x17, 0x0d, 0x34, 0x39, 0x30, 0x31, 0x30, 0x31,
65 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30,
66 0x17, 0x31, 0x15, 0x30, 0x13, 0x06, 0x03, 0x55,
67 0x04, 0x03, 0x0c, 0x0c, 0x4c, 0x6f, 0x63, 0x61,
68 0x6c, 0x20, 0x53, 0x45, 0x52, 0x56, 0x45, 0x52,
69 0x30, 0x59, 0x30, 0x13, 0x06, 0x07, 0x2a, 0x86,
70 0x48, 0xce, 0x3d, 0x02, 0x01, 0x06, 0x08, 0x2a,
71 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07, 0x03,
72 0x42, 0x00, 0x04, 0x07, 0x88, 0x10, 0xdc, 0x62,
73 0xd7, 0xe6, 0x9b, 0x7c, 0xad, 0x6e, 0x78, 0xb0,
74 0x5f, 0x9a, 0x00, 0x11, 0x74, 0x2c, 0x8b, 0xaf,
75 0x09, 0x65, 0x7c, 0x86, 0x8e, 0x55, 0xcb, 0x39,
76 0x55, 0x72, 0xc6, 0x65, 0x71, 0xcd, 0x03, 0xdc,
77 0x2a, 0x4f, 0x46, 0x5b, 0x14, 0xc8, 0x27, 0x74,
78 0xab, 0xf4, 0x1f, 0xc1, 0x35, 0x0d, 0x42, 0xbc,
79 0xc2, 0x9f, 0xb5, 0xc1, 0x79, 0xb6, 0x8b, 0xca,
80 0xdb, 0xff, 0x82, 0x30, 0x0c, 0x06, 0x08, 0x2a,
81 0x86, 0x48, 0xce, 0x3d, 0x04, 0x03, 0x02, 0x05,
82 0x00, 0x03, 0x49, 0x00, 0x30, 0x46, 0x02, 0x21,
83 0x00, 0xb1, 0x81, 0x81, 0x92, 0x0e, 0x76, 0x7c,
84 0xeb, 0xf5, 0x37, 0xde, 0x27, 0xc4, 0x01, 0xc8,
85 0x96, 0xc3, 0xe5, 0x9f, 0x47, 0x7e, 0x25, 0x92,
86 0xa4, 0xba, 0x22, 0x25, 0xa3, 0x81, 0x19, 0xcf,
87 0x0d, 0x02, 0x21, 0x00, 0xca, 0x92, 0xbe, 0x79,
88 0xc7, 0x82, 0x84, 0x64, 0xc4, 0xc4, 0xf4, 0x3d,
89 0x69, 0x79, 0x68, 0xc0, 0xf1, 0xba, 0xaf, 0x6c,
90 0xbb, 0xdd, 0x54, 0x7d, 0x07, 0xe7, 0x53, 0x3b,
91 0xc3, 0x1b, 0x87, 0x04};
93 //default server's key pair
94 static const unsigned char x509_priv_key[] = {
95 0xaa, 0xa3, 0x46, 0xf1, 0x3c, 0x56, 0x5d, 0x08,
96 0x5e, 0x59, 0xba, 0x7f, 0xd2, 0x21, 0x62, 0xc6,
97 0xcc, 0x5d, 0xfa, 0x3f, 0xb5, 0x25, 0xa9, 0x89,
98 0x4f, 0x32, 0xe8, 0x2a, 0xe0, 0xee, 0x9b, 0x4c};
100 static const unsigned char x509_pub_key_x[] = {
101 0x07, 0x88, 0x10, 0xdc, 0x62, 0xd7, 0xe6, 0x9b,
102 0x7c, 0xad, 0x6e, 0x78, 0xb0, 0x5f, 0x9a, 0x00,
103 0x11, 0x74, 0x2c, 0x8b, 0xaf, 0x09, 0x65, 0x7c,
104 0x86, 0x8e, 0x55, 0xcb, 0x39, 0x55, 0x72, 0xc6};
106 static const unsigned char x509_pub_key_y[] = {
107 0x65, 0x71, 0xcd, 0x03, 0xdc, 0x2a, 0x4f, 0x46,
108 0x5b, 0x14, 0xc8, 0x27, 0x74, 0xab, 0xf4, 0x1f,
109 0xc1, 0x35, 0x0d, 0x42, 0xbc, 0xc2, 0x9f, 0xb5,
110 0xc1, 0x79, 0xb6, 0x8b, 0xca, 0xdb, 0xff, 0x82};
113 static const unsigned char x509_ca_pub_x[] = {
114 0x57, 0x94, 0x7f, 0x98, 0x7a, 0x02, 0x67, 0x09,
115 0x25, 0xc1, 0xcb, 0x5a, 0xf5, 0x46, 0xfb, 0xad,
116 0xf7, 0x68, 0x94, 0x8c, 0xa7, 0xe3, 0xf0, 0x5b,
117 0xc3, 0x6b, 0x5c, 0x9b, 0xd3, 0x7d, 0x74, 0x12
120 static const unsigned char x509_ca_pub_y[] = {
121 0xce, 0x68, 0xbc, 0x55, 0xf5, 0xf8, 0x1b, 0x3d,
122 0xef, 0xed, 0x1f, 0x2b, 0xd2, 0x69, 0x5d, 0xcf,
123 0x79, 0x16, 0xa6, 0xbd, 0x97, 0x96, 0x27, 0x60,
124 0x5d, 0xd1, 0xb7, 0x93, 0xa2, 0x4a, 0x62, 0x4d
127 static const unsigned char client_pub_key_x[] = {
128 0xe3, 0xd1, 0x67, 0x1e, 0xdc, 0x46, 0xf4, 0x19,
129 0x50, 0x15, 0x2e, 0x3a, 0x2f, 0xd8, 0x68, 0x6b,
130 0x37, 0x32, 0x84, 0x9e, 0x83, 0x81, 0xbf, 0x25,
131 0x5d, 0xbb, 0x18, 0x07, 0x3c, 0xbd, 0xf3, 0xab};
133 static const unsigned char client_pub_key_y[] = {
134 0xd3, 0xbf, 0x53, 0x59, 0xc9, 0x1e, 0xce, 0x5b,
135 0x39, 0x6a, 0xe5, 0x60, 0xf3, 0x70, 0xdb, 0x66,
136 0xb6, 0x80, 0xcb, 0x65, 0x0b, 0x35, 0x2a, 0x62,
137 0x44, 0x89, 0x63, 0x64, 0x6f, 0x6f, 0xbd, 0xf0};
139 static unsigned char x509_server_cert[DTLS_MAX_CERT_SIZE];
140 static size_t x509_server_cert_len = 0;
141 static unsigned char x509_server_priv[DTLS_PRIVATE_KEY_SIZE+1];
142 static size_t x509_server_priv_is_set = 0;
143 static unsigned char x509_ca_pub[DTLS_PUBLIC_KEY_SIZE+1];
144 static size_t x509_ca_pub_is_set = 0;
146 static int x509_info_from_file = 0;
149 static const unsigned char ecdsa_priv_key[] = {
150 0xD9, 0xE2, 0x70, 0x7A, 0x72, 0xDA, 0x6A, 0x05,
151 0x04, 0x99, 0x5C, 0x86, 0xED, 0xDB, 0xE3, 0xEF,
152 0xC7, 0xF1, 0xCD, 0x74, 0x83, 0x8F, 0x75, 0x70,
153 0xC8, 0x07, 0x2D, 0x0A, 0x76, 0x26, 0x1B, 0xD4};
155 static const unsigned char ecdsa_pub_key_x[] = {
156 0xD0, 0x55, 0xEE, 0x14, 0x08, 0x4D, 0x6E, 0x06,
157 0x15, 0x59, 0x9D, 0xB5, 0x83, 0x91, 0x3E, 0x4A,
158 0x3E, 0x45, 0x26, 0xA2, 0x70, 0x4D, 0x61, 0xF2,
159 0x7A, 0x4C, 0xCF, 0xBA, 0x97, 0x58, 0xEF, 0x9A};
161 static const unsigned char ecdsa_pub_key_y[] = {
162 0xB4, 0x18, 0xB6, 0x4A, 0xFE, 0x80, 0x30, 0xDA,
163 0x1D, 0xDC, 0xF4, 0xF4, 0x2E, 0x2F, 0x26, 0x31,
164 0xD0, 0x43, 0xB1, 0xFB, 0x03, 0xE2, 0x2F, 0x4D,
165 0x17, 0xDE, 0x43, 0xF9, 0xF9, 0xAD, 0xEE, 0x70};
168 /* SIGINT handler: set quit to 1 for graceful termination */
170 handle_sigint(int signum) {
171 dsrv_stop(dsrv_get_context());
177 read_from_file(char *arg, unsigned char *buf, size_t max_buf_len) {
187 bytes_read = fread(buf, 1, max_buf_len, f);
194 result += bytes_read;
195 max_buf_len -= bytes_read;
205 #define PSK_SERVER_HINT "Server_identity"
207 /* This function is the "key store" for tinyDTLS. It is called to
208 * retrieve a key for the given identity within this particular
211 get_psk_info(struct dtls_context_t *ctx, const session_t *session,
212 dtls_credentials_type_t type,
213 const unsigned char *id, size_t id_len,
214 unsigned char *result, size_t result_length) {
224 { (unsigned char *)"Client_identity", 15,
225 (unsigned char *)"secretPSK", 9 },
226 { (unsigned char *)"default identity", 16,
227 (unsigned char *)"\x11\x22\x33", 3 },
228 { (unsigned char *)"\0", 2,
229 (unsigned char *)"", 1 }
234 if (result_length < strlen(PSK_SERVER_HINT)) {
235 dtls_warn("cannot set psk_hint -- buffer too small\n");
236 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
239 memcpy(result, PSK_SERVER_HINT, strlen(PSK_SERVER_HINT));
240 return strlen(PSK_SERVER_HINT);
245 for (i = 0; i < (int)(sizeof(psk)/sizeof(struct keymap_t)); i++) {
246 if (id_len == psk[i].id_length && memcmp(id, psk[i].id, id_len) == 0) {
247 if (result_length < psk[i].key_length) {
248 dtls_warn("buffer too small for PSK");
249 return dtls_alert_fatal_create(DTLS_ALERT_INTERNAL_ERROR);
252 memcpy(result, psk[i].key, psk[i].key_length);
253 return psk[i].key_length;
260 dtls_warn("unsupported request type: %d\n", type);
263 return dtls_alert_fatal_create(DTLS_ALERT_DECRYPT_ERROR);
266 #endif /* DTLS_PSK */
270 get_ecdsa_key(struct dtls_context_t *ctx,
271 const session_t *session,
272 const dtls_ecc_key_t **result) {
275 static const dtls_ecc_key_t ecdsa_key = {
276 .curve = DTLS_ECDH_CURVE_SECP256R1,
277 .priv_key = ecdsa_priv_key,
278 .pub_key_x = ecdsa_pub_key_x,
279 .pub_key_y = ecdsa_pub_key_y
282 *result = &ecdsa_key;
287 verify_ecdsa_key(struct dtls_context_t *ctx,
288 const session_t *session,
289 const unsigned char *other_pub_x,
290 const unsigned char *other_pub_y,
299 #endif /* DTLS_ECC */
303 get_x509_key(struct dtls_context_t *ctx,
304 const session_t *session,
305 const dtls_ecc_key_t **result) {
308 static dtls_ecc_key_t ecdsa_key = {
309 .curve = DTLS_ECDH_CURVE_SECP256R1,
310 .priv_key = x509_priv_key,
311 .pub_key_x = x509_pub_key_x,
312 .pub_key_y = x509_pub_key_y
314 if (x509_info_from_file)
315 ecdsa_key.priv_key = x509_server_priv;
317 *result = &ecdsa_key;
322 get_x509_cert(struct dtls_context_t *ctx,
323 const session_t *session,
324 const unsigned char **cert,
329 if (x509_info_from_file)
331 *cert = x509_server_cert;
332 *cert_size = x509_server_cert_len;
336 *cert = g_server_certificate;
337 *cert_size = SERVER_CRT_LEN;
343 static int check_certificate(byte_array cert_der_code, byte_array ca_public_key)
350 static int verify_x509_cert(struct dtls_context_t *ctx, const session_t *session,
351 const unsigned char *cert, size_t cert_size,
358 const unsigned char *ca_pub_x;
359 const unsigned char *ca_pub_y;
360 byte_array cert_der_code = BYTE_ARRAY_INITIALIZER;
361 byte_array ca_public_key = BYTE_ARRAY_INITIALIZER;
362 unsigned char ca_pub_key[DTLS_PUBLIC_KEY_SIZE];
366 if (x509_info_from_file)
368 ca_pub_x = x509_ca_pub;
369 ca_pub_y = x509_ca_pub + DTLS_PUBLIC_KEY_SIZE/2;
373 ca_pub_x = x509_ca_pub_x;
374 ca_pub_y = x509_ca_pub_y;
377 cert_der_code.data = (uint8_t *)cert;
378 cert_der_code.len = cert_size;
380 ca_public_key.len = DTLS_PUBLIC_KEY_SIZE;
381 ca_public_key.data = ca_pub_key;
382 memcpy(ca_public_key.data, ca_pub_x, DTLS_PUBLIC_KEY_SIZE/2);
383 memcpy(ca_public_key.data + DTLS_PUBLIC_KEY_SIZE/2, ca_pub_y, DTLS_PUBLIC_KEY_SIZE/2);
385 memcpy(x, client_pub_key_x, x_size);
386 memcpy(y, client_pub_key_y, y_size);
388 ret = (int) check_certificate(cert_der_code, ca_public_key);
393 static int is_x509_active(struct dtls_context_t *ctx)
398 #endif /* DTLS_X509 */
401 #define DTLS_SERVER_CMD_CLOSE "server:close"
402 #define DTLS_SERVER_CMD_RENEGOTIATE "server:renegotiate"
405 read_from_peer(struct dtls_context_t *ctx,
406 session_t *session, uint8 *data, size_t len) {
408 for (i = 0; i < len; i++)
409 printf("%c", data[i]);
410 if (len >= strlen(DTLS_SERVER_CMD_CLOSE) &&
411 !memcmp(data, DTLS_SERVER_CMD_CLOSE, strlen(DTLS_SERVER_CMD_CLOSE))) {
412 printf("server: closing connection\n");
413 dtls_close(ctx, session);
415 } else if (len >= strlen(DTLS_SERVER_CMD_RENEGOTIATE) &&
416 !memcmp(data, DTLS_SERVER_CMD_RENEGOTIATE, strlen(DTLS_SERVER_CMD_RENEGOTIATE))) {
417 printf("server: renegotiate connection\n");
418 dtls_renegotiate(ctx, session);
422 return dtls_write(ctx, session, data, len);
426 send_to_peer(struct dtls_context_t *ctx,
427 session_t *session, uint8 *data, size_t len) {
429 int fd = *(int *)dtls_get_app_data(ctx);
430 return sendto(fd, data, len, MSG_DONTWAIT,
431 &session->addr.sa, session->size);
435 dtls_handle_read(struct dtls_context_t *ctx) {
438 static uint8 buf[DTLS_MAX_BUF];
441 fd = dtls_get_app_data(ctx);
445 memset(&session, 0, sizeof(session_t));
446 session.size = sizeof(session.addr);
447 len = recvfrom(*fd, buf, sizeof(buf), MSG_TRUNC,
448 &session.addr.sa, &session.size);
454 dtls_debug("got %d bytes from port %d\n", len,
455 ntohs(session.addr.sin6.sin6_port));
456 if ((int)(sizeof(buf)) < len) {
457 dtls_warn("packet was truncated (%d bytes lost)\n", len - sizeof(buf));
461 return dtls_handle_message(ctx, &session, buf, len);
465 resolve_address(const char *server, struct sockaddr *dst) {
467 struct addrinfo *res, *ainfo;
468 struct addrinfo hints;
469 static char addrstr[256];
472 memset(addrstr, 0, sizeof(addrstr));
473 if (server && strlen(server) > 0)
474 memcpy(addrstr, server, strlen(server));
476 memcpy(addrstr, "localhost", 9);
478 memset ((char *)&hints, 0, sizeof(hints));
479 hints.ai_socktype = SOCK_DGRAM;
480 hints.ai_family = AF_UNSPEC;
482 error = getaddrinfo(addrstr, "", &hints, &res);
485 fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(error));
489 for (ainfo = res; ainfo != NULL; ainfo = ainfo->ai_next) {
491 switch (ainfo->ai_family) {
494 memcpy(dst, ainfo->ai_addr, ainfo->ai_addrlen);
495 return ainfo->ai_addrlen;
506 usage(const char *program, const char *version) {
509 p = strrchr( program, '/' );
513 fprintf(stderr, "%s v%s -- DTLS server implementation\n"
514 "(c) 2011-2014 Olaf Bergmann <bergmann@tzi.org>\n\n"
515 "usage: %s [-A address] [-p port] [-v num] [-a enable|disable]\n"
517 " [-x file] [-r file] [-u file]"
518 #endif /* DTLS_X509 */
519 "\t-A address\t\tlisten on specified address (default is ::)\n"
520 "\t-p port\t\tlisten on specified port (default is %d)\n"
521 "\t-v num\t\tverbosity level (default: 3)\n"
522 "\t-a enable|disable\t(default: disable)\n"
523 "\t\t\t\tenable:enable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n"
524 "\t\t\t\tdisable:disable TLS_ECDH_anon_with_AES_128_CBC_SHA_256\n"
526 "\t-x file\tread Server certificate from file\n"
527 "\t-r file\tread Server private key from file\n"
528 "\t-u file\tread CA public key from file\n"
529 #endif /* DTLS_X509 */
530 ,program, version, program, DEFAULT_PORT);
533 static dtls_handler_t cb = {
534 .write = send_to_peer,
535 .read = read_from_peer,
538 .get_psk_info = get_psk_info,
539 #endif /* DTLS_PSK */
541 .get_ecdsa_key = get_ecdsa_key,
542 .verify_ecdsa_key = verify_ecdsa_key,
543 #endif /* DTLS_ECC */
545 .get_x509_key = get_x509_key,
546 .verify_x509_cert = verify_x509_cert,
547 .get_x509_cert = get_x509_cert,
548 .is_x509_active = is_x509_active,
554 main(int argc, char **argv) {
555 dtls_context_t *the_context = NULL;
556 log_t log_level = DTLS_LOG_WARN;
558 struct timeval timeout;
561 dtls_cipher_enable_t ecdh_anon_enalbe = DTLS_CIPHER_DISABLE;
562 struct sockaddr_in6 listen_addr;
564 memset(&listen_addr, 0, sizeof(struct sockaddr_in6));
566 /* fill extra field for 4.4BSD-based systems (see RFC 3493, section 3.4) */
567 #if defined(SIN6_LEN) || defined(HAVE_SOCKADDR_IN6_SIN6_LEN)
568 listen_addr.sin6_len = sizeof(struct sockaddr_in6);
571 listen_addr.sin6_family = AF_INET6;
572 listen_addr.sin6_port = htons(DEFAULT_PORT);
573 listen_addr.sin6_addr = in6addr_any;
575 while ((opt = getopt(argc, argv, "A:p:v:a:")) != -1) {
578 if (resolve_address(optarg, (struct sockaddr *)&listen_addr) < 0) {
579 fprintf(stderr, "cannot resolve address\n");
584 listen_addr.sin6_port = htons(atoi(optarg));
587 log_level = strtol(optarg, NULL, 10);
590 if( strcmp(optarg, "enable") == 0)
591 ecdh_anon_enalbe = DTLS_CIPHER_ENABLE;
596 ssize_t result = read_from_file(optarg, x509_server_cert, DTLS_MAX_CERT_SIZE);
599 dtls_warn("Cannot read Server certificate. Using default\n");
603 x509_server_cert_len = result;
609 ssize_t result = read_from_file(optarg, x509_server_priv, DTLS_PRIVATE_KEY_SIZE+1);
612 dtls_warn("Cannot read Server private key. Using default\n");
616 x509_server_priv_is_set = result;
622 ssize_t result = read_from_file(optarg, x509_ca_pub, DTLS_PUBLIC_KEY_SIZE+1);
625 dtls_warn("Cannot read CA public key. Using default\n");
629 x509_ca_pub_is_set = result;
633 #endif /* DTLS_X509 */
635 usage(argv[0], dtls_package_version());
640 dtls_set_log_level(log_level);
643 if (x509_server_cert_len && x509_server_priv_is_set && x509_ca_pub_is_set)
645 x509_info_from_file = 1;
647 else if(!(x509_server_cert_len || x509_server_priv_is_set || x509_ca_pub_is_set))
649 x509_info_from_file = 0;
653 fprintf(stderr,"please set -x, -r, -u options simultaneously");
654 usage(argv[0], dtls_package_version());
657 #endif /* DTLS_X509 */
659 /* init socket and set it to non-blocking */
660 fd = socket(listen_addr.sin6_family, SOCK_DGRAM, 0);
663 dtls_alert("socket: %s\n", strerror(errno));
667 if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &on, sizeof(on) ) < 0) {
668 dtls_alert("setsockopt SO_REUSEADDR: %s\n", strerror(errno));
671 flags = fcntl(fd, F_GETFL, 0);
672 if (flags < 0 || fcntl(fd, F_SETFL, flags | O_NONBLOCK) < 0) {
673 dtls_alert("fcntl: %s\n", strerror(errno));
678 #ifdef IPV6_RECVPKTINFO
679 if (setsockopt(fd, IPPROTO_IPV6, IPV6_RECVPKTINFO, &on, sizeof(on) ) < 0) {
680 #else /* IPV6_RECVPKTINFO */
681 if (setsockopt(fd, IPPROTO_IPV6, IPV6_PKTINFO, &on, sizeof(on) ) < 0) {
682 #endif /* IPV6_RECVPKTINFO */
683 dtls_alert("setsockopt IPV6_PKTINFO: %s\n", strerror(errno));
686 if (bind(fd, (struct sockaddr *)&listen_addr, sizeof(listen_addr)) < 0) {
687 dtls_alert("bind: %s\n", strerror(errno));
693 the_context = dtls_new_context(&fd);
695 /* enable/disable tls_ecdh_anon_with_aes_128_cbc_sha_256 */
696 dtls_enables_anon_ecdh(the_context, ecdh_anon_enalbe);
698 dtls_set_handler(the_context, &cb);
705 /* FD_SET(fd, &wfds); */
710 result = select( fd+1, &rfds, &wfds, 0, &timeout);
712 if (result < 0) { /* error */
715 } else if (result == 0) { /* timeout */
717 if (FD_ISSET(fd, &wfds))
719 else if (FD_ISSET(fd, &rfds)) {
720 dtls_handle_read(the_context);
726 dtls_free_context(the_context);