+#if 0
+static void log_function_gnutls(int level, const char *string) {
+ (void)level;
+ fprintf(stderr, " => %s", string);
+}
+#endif
+
+static void initialize_gnutls(void) {
+ int result;
+/* Recent versions of GnuTLS automatically initialize the cryptography layer
+ * in gnutls_global_init(). */
+#if GNUTLS_VERSION_NUMBER <= 0x020b00
+ gcry_error_t error;
+
+ /* Thread safe setup. Must be called before gnutls_global_init(). */
+ error = gcry_control(GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread);
+ if (error != 0) {
+ fprintf(stderr, "gcry_control(): %s/%s\n", gcry_strsource(error),
+ gcry_strerror(error));
+ exit(EXIT_FAILURE);
+ }
+ /* Prevent usage of blocking /dev/random. */
+ error = gcry_control(GCRYCTL_ENABLE_QUICK_RANDOM, 0);
+ if (error != 0) {
+ fprintf(stderr, "gcry_control(): %s/%s\n", gcry_strsource(error),
+ gcry_strerror(error));
+ exit(EXIT_FAILURE);
+ }
+#endif
+
+ /* Initialize GnuTLS. */
+ result = gnutls_global_init();
+ GNUTLS_ERROR_EXIT(result, "gnutls_global_init()");
+
+#if 0
+ gnutls_global_set_log_level(10);
+ gnutls_global_set_log_function(log_function_gnutls);
+#endif
+
+ /* Setup GnuTLS cipher suites. */
+ result = gnutls_priority_init(&global_tls_priority_cache, "NORMAL", NULL);
+ GNUTLS_ERROR_EXIT(result, "gnutls_priority_init()");
+
+ /* Generate Diffie-Hellman parameters. */
+ result = gnutls_dh_params_init(&global_tls_dh_params);
+ GNUTLS_ERROR_EXIT(result, "gnutls_dh_params_init()");
+ result = gnutls_dh_params_generate2(global_tls_dh_params, DH_SIZE);
+ GNUTLS_ERROR_EXIT(result, "gnutls_dh_params_generate2()");
+}
+static void deinitialize_gnutls(void) {
+ gnutls_dh_params_deinit(global_tls_dh_params);
+ gnutls_priority_deinit(global_tls_priority_cache);
+
+ gnutls_global_deinit();
+}
+
+static void *worker_thread(void *unused) {