void comm_base_dispatch(struct comm_base* b) { struct replay_runtime* runtime = (struct replay_runtime*)b; run_scenario(runtime); if(runtime->sig_cb) (*runtime->sig_cb)(SIGTERM, runtime->sig_cb_arg); else exit(0); /* OK exit when LIBEVENT_SIGNAL_PROBLEM exists */ }
int main(int argc, char *argv[]) { int ret, exitcode; mbedtls_net_context server_fd; uint32_t flags; char scenario[10000] = ""; char server_host[100] = ""; char server_port[6] = ""; char server_ssl_hostname[100] = ""; const char *pers = "dtls_client"; int opt; struct timeval t0, t1; mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_ssl_context ssl; mbedtls_ssl_config conf; mbedtls_x509_crt cacert; mbedtls_timing_delay_context timer; /* Parse command line */ while ((opt = getopt(argc, argv, "h:n:p:s:")) != -1) { switch (opt) { case 'h': strncpy(server_host, optarg, sizeof(server_host)); break; case 'n': strncpy(server_ssl_hostname, optarg, sizeof(server_ssl_hostname)); break; case 'p': strncpy(server_port, optarg, sizeof(server_port)); break; case 's': strncpy(scenario, optarg, sizeof(scenario)); break; default: /* '?' */ print_usage(argv[0]); } } if (!(scenario[0] && server_port[0] && server_host[0])) { print_usage(argv[0]); } if (!server_ssl_hostname[0]) { strncpy(server_ssl_hostname, server_host, sizeof(server_ssl_hostname)); } #if defined(MBEDTLS_DEBUG_C) mbedtls_debug_set_threshold(DEBUG_LEVEL); #endif /* * 0. Initialize the RNG and the session data */ mbedtls_net_init(&server_fd); mbedtls_ssl_init(&ssl); mbedtls_ssl_config_init(&conf); mbedtls_x509_crt_init(&cacert); mbedtls_ctr_drbg_init(&ctr_drbg); plog("Seeding the random number generator..."); mbedtls_entropy_init(&entropy); if ((ret = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers))) != 0) { plog("ERROR: failed! mbedtls_ctr_drbg_seed returned %d", ret); goto exit; } /* * 0. Load certificates */ plog("Loading the CA root certificate ..."); ret = mbedtls_x509_crt_parse(&cacert, (const unsigned char *)mbedtls_test_cas_pem, mbedtls_test_cas_pem_len); if (ret < 0) { plog("ERROR: failed! mbedtls_x509_crt_parse returned -0x%x", -ret); goto exit; } plog("Connecting to udp %s:%s (SSL hostname: %s)...", server_host, server_port, server_ssl_hostname); if ((ret = mbedtls_net_connect(&server_fd, server_host, server_port, MBEDTLS_NET_PROTO_UDP)) != 0) { plog("ERROR: failed! mbedtls_net_connect returned %d", ret); goto exit; } plog("The local client UDP source port is %d", get_source_port(server_fd.fd)); plog("Setting up the DTLS structure..."); if ((ret = mbedtls_ssl_config_defaults(&conf, MBEDTLS_SSL_IS_CLIENT, MBEDTLS_SSL_TRANSPORT_DATAGRAM, MBEDTLS_SSL_PRESET_DEFAULT)) != 0) { plog("ERROR: failed! mbedtls_ssl_config_defaults returned %d", ret); goto exit; } /* OPTIONAL is usually a bad choice for security, but makes interop easier * in this simplified example, in which the ca chain is hardcoded. * Production code should set a proper ca chain and use REQUIRED. */ mbedtls_ssl_conf_authmode(&conf, MBEDTLS_SSL_VERIFY_OPTIONAL); mbedtls_ssl_conf_ca_chain(&conf, &cacert, NULL); mbedtls_ssl_conf_rng(&conf, mbedtls_ctr_drbg_random, &ctr_drbg); mbedtls_ssl_conf_dbg(&conf, log_mbedtls_debug_callback, NULL); /* TODO timeouts */ if ((ret = mbedtls_ssl_setup(&ssl, &conf)) != 0) { plog("ERROR: failed! mbedtls_ssl_setup returned %d", ret); goto exit; } if ((ret = mbedtls_ssl_set_hostname(&ssl, server_ssl_hostname)) != 0) { plog("ERROR: failed! mbedtls_ssl_set_hostname returned %d", ret); goto exit; } mbedtls_ssl_set_bio(&ssl, &server_fd, mbedtls_net_send, mbedtls_net_recv, mbedtls_net_recv_timeout); mbedtls_ssl_set_timer_cb(&ssl, &timer, mbedtls_timing_set_delay, mbedtls_timing_get_delay); plog("Performing the SSL/TLS handshake..."); gettimeofday(&t0, NULL); do { ret = mbedtls_ssl_handshake(&ssl); plog(" ... during SSL handshake, ret=%d (WANT_READ=%d, WANT_WRITE=%d, RECV_FAILED=%d", ret, MBEDTLS_ERR_SSL_WANT_READ, MBEDTLS_ERR_SSL_WANT_WRITE, MBEDTLS_ERR_NET_RECV_FAILED); gettimeofday(&t1, NULL); } while ((duration_ms(&t1, &t0) <= SSL_HANDSHAKE_TIMEOUT_MILLISECS) && (ret == MBEDTLS_ERR_SSL_WANT_READ || ret == MBEDTLS_ERR_SSL_WANT_WRITE)); plog("handshake duration: %d milliseconds", duration_ms(&t1, &t0)); if (duration_ms(&t1, &t0) > SSL_HANDSHAKE_TIMEOUT_MILLISECS) { plog("ERROR: long time to perform handshake: %d milliseconds", duration_ms(&t1, &t0)); ret = MBEDTLS_ERR_SSL_TIMEOUT; goto exit; } if (ret != 0) { plog("ERROR: failed! mbedtls_ssl_handshake returned -0x%x", -ret); goto exit; } plog("Verifying peer X.509 certificate..."); /* In real life, we would have used MBEDTLS_SSL_VERIFY_REQUIRED so that the * handshake would not succeed if the peer's cert is bad. Even if we used * MBEDTLS_SSL_VERIFY_OPTIONAL, we would bail out here if ret != 0 */ if ((flags = mbedtls_ssl_get_verify_result(&ssl)) != 0) { char vrfy_buf[512]; mbedtls_x509_crt_verify_info(vrfy_buf, sizeof(vrfy_buf), "! ", flags); plog("Verification failed: %s", vrfy_buf); } else { plog("Certificates ok"); } ret = run_scenario(scenario, &ssl); if (ret != 0) { goto exit; } plog("Closing the connection..."); /* No error checking, the connection might be closed already */ do { ret = mbedtls_ssl_close_notify(&ssl); } while (ret == MBEDTLS_ERR_SSL_WANT_WRITE); ret = 0; exit: #ifdef MBEDTLS_ERROR_C if (ret != 0) { char error_buf[100]; mbedtls_strerror(ret, error_buf, 100); plog("ERROR: Last error was: %d - %s", ret, error_buf); } #endif mbedtls_net_free(&server_fd); mbedtls_x509_crt_free(&cacert); mbedtls_ssl_free(&ssl); mbedtls_ssl_config_free(&conf); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); exitcode = ret == 0 ? 0 : 1; plog("Done, exitcode=%d", exitcode); return exitcode; }