Deadlock in rr_workpool.c/process_item when calling g_thread_create

Sandro Poppi <[email protected]> Sat, 31 May 2003 15:41:57 +0200
Newsgroups gmane.network.beep.roadrunner.general
Message-ID <[email protected]>
Hi,

I'm still running into a deadlock situation in our snort plugin where I 
can't find an answer. I cut it down to the following line in 
rr_workpool.c, function process_item:

-------------------------------------------------------------------------
static void
process_item (RRWorkPool *pool)
{
         GError *error = NULL;
         WorkItem *item;

         g_return_if_fail (pool);
         if ((item = get_next_item (pool))) {
                 pool->num_threads++;

==>       if (g_thread_create (work_proxy, item, FALSE, &error) == NULL)
                  {
                         g_error ("g_thread_create failed: %s\n",
                                  error->message);
                  }
         }
}
-------------------------------------------------------------------------

I get no message, I also added an else statement to print something to 
stderr but it didn't show up either. g_thread_create is called and then 
the listening server (see below) hangs with 100% cpu.

What's even worse is that after some 5 - 10 minutes the first run is ok 
but the second and all further calls hang except waiting some more 
minutes. Very strange.

Here is a code snippet where the IDXP/TLS connection is established 
(removed all the ugly debugging statements ;):

-------------------------------------------------------------------------
static gchar *
keyfile_resolver (RRTLS *tls)
{
	return g_strdup (global_data->own_prv_key);
}

static gchar *
certfile_resolver (RRTLS *tls)
{
	return g_strdup (global_data->own_cert);
}

static gboolean
enableTls (RRConnection *connection)
{
	GError *error = NULL;
	RRTLSConfig *cfg;

	cfg = rr_tls_config_new ();

	rr_tls_config_set_key_resolver    (cfg, keyfile_resolver);
	rr_tls_config_set_cert_resolver   (cfg, certfile_resolver);
	rr_tls_config_set_trusted_ca_file (cfg, global_data->ca_cert);

	if (!rr_tls_privatize (connection, global_data->name, cfg, &error)) {
		g_print ("rr_tls_privatize failed: %s\n", error->message);
		return FALSE;
	}

	rr_tls_config_destroy (cfg);
	if (rr_tls_is_strong_enough (connection, 128)) {
	}
	else {
		g_print ("The encryption is not strong enough!\n");
		return FALSE;
	}

	if (rr_tls_is_trusted (connection, &error)) {
	}
	else {
		g_print ("Certificate verification failed: '%s'!\n",
			 error->message);
		return FALSE;
	}
	
	return TRUE;
}

static RRConnection *
initIdxpConnection (IDMEFOutputFacility * facility)
{
	RRProfileRegistry *profreg;
	RRManager *manager;
	RRConnection *conn;
	GError *error = NULL;
  	RRIDXPConfig *idxpconfig = NULL;

	/* FIXME: define prio/stream */
	idxpconfig = rr_idxp_config_new_with_vals (TM_URI, RR_IDXP_ROLE_CLIENT,
					       global_data->name,NULL,
					       RR_IDXP_CHANNEL_PRIORITY_UNDEFINED, TRUE,
					       RR_IDXP_STREAM_UNDEFINED, FALSE);

         /* save config for later use */
	facility->config->idxp_config.RRIdxpConfig = idxpconfig;
	
	/* Tell roadrunner which profiles we want to support */
	profreg = rr_profile_registry_new ();
	rr_profile_registry_add_profile (profreg, RR_TYPE_TLS, NULL);
      	rr_profile_registry_add_profile (profreg, RR_TYPE_IDXP, idxpconfig);
	/* Create a connection object */
	if ((conn = rr_tcp_connection_new (profreg, 
facility->config->idxp_config.age_host,
					   facility->config->idxp_config.port_num,
					   &error)) == NULL)
		FatalError ("IDMEF::initIdxpConnection: rr_tcp_connection_new failed: 
%s\n", error->message);

	/* Check if the remote peer supports the profiles we need */
	g_assert (rr_connection_peer_supports_profile (conn, RR_TYPE_IDXP));
	g_assert (rr_connection_peer_supports_profile (conn, 	/* require TLS or 
exit */
	if (!enableTls (conn))
	 {
	   g_print ("IDMEF::initIdxpConnection: TLS connection not 
established!\n");
	   return NULL;
	 }

	manager = rr_connection_get_manager (conn);

	return conn;
}

void OpenFacilityIdxp(IDMEFOutputFacility * facility)
{

... some snort specific stuff ...

   if (!(conn = initIdxpConnection (facility)))
    {
      FatalError ("IDMEF::OpenFacilityIdxp: initIdxpConnection failed. 
Exiting ...\n");
    }

   manager = rr_connection_get_manager (conn);

   /* save connection information */
   facility->state->idxp_state.rrconnection = conn;
}

-------------------------------------------------------------------------

And here is the listening server's code:

-------------------------------------------------------------------------
#include <librr/rr.h>
#include <librrtls/rr-tls.h>
#include <librridxp/rridxp.h>

static gchar *
tls_keyfile_resolver (RRTLS *tls)
{
         RRConnection *connection = RR_CHANNEL (tls)->connection;
         const gchar *server_name = rr_connection_get_server_name 
(connection);

         rr_debug1 ("resolver: server_name = '%s'\n", server_name);

         /* The server_name can be used to select different files for
          * different "virtual hosts". */

         return g_strdup ("./server.key");
}

static gchar *
tls_certfile_resolver (RRTLS *tls)
{
         return g_strdup ("./server.crt");
}

gboolean idxp_consumer (RRIDXP *idxp, RRIDXPMessageType msg_type, 
RRFrame *frame,
                       gpointer user_data, GError **error)
{
         g_print ("yay!\n");

         return TRUE;
}

int
main (gint argc, gchar **argv)
{
         GError *error = NULL;
         RRListener *listener;
         RRProfileRegistry *profreg;
         RRTLSConfig *tls_config;
         RRIDXPConfig *idxp_config = NULL;

         idxp_config = rr_idxp_config_new_with_vals 
("http://idxp.codefactory.se/idxp",
                                                RR_IDXP_ROLE_SERVER,
                                                "pluto", NULL,
 
RR_IDXP_CHANNEL_PRIORITY_UNDEFINED,
                                                TRUE,
 
RR_IDXP_STREAM_UNDEFINED, FALSE);

         rr_idxp_config_set_frame_handler (idxp_config, 
RR_IDXP_MESSAGE_TEXT,
                                           idxp_consumer, NULL, TRUE);
         rr_idxp_config_set_frame_handler (idxp_config, 
RR_IDXP_MESSAGE_IDMEF,
                                           idxp_consumer, NULL, TRUE);

         tls_config = rr_tls_config_new ();

         rr_tls_config_set_key_resolver (tls_config,
                                         tls_keyfile_resolver);
         rr_tls_config_set_cert_resolver (tls_config,
                                          tls_certfile_resolver);

         if (!rr_init (&argc, &argv, &error))
                 g_error ("rr_init failed: %s\n", error->message);

         profreg = rr_profile_registry_new ();
         rr_profile_registry_add_profile (profreg, RR_TYPE_TLS, tls_config);
         rr_profile_registry_add_profile (profreg, RR_TYPE_IDXP, 
idxp_config);

         if ((listener = rr_tcp_listener_new (profreg, "localhost", 10289,
                                              &error)) == NULL)
                 g_error ("listen failed: %s\n", error->message);

         if (!rr_wait_until_done (&error))
                 g_error ("rr_run failed: %s\n", error->message);

         if (!rr_listener_shutdown (listener, &error))
                 g_error ("rr_listener_shutdown failed: %s\n", 
error->message);

         if (!rr_exit (&error))
                 g_error ("rr_exit failed: %s\n", error->message);

         rr_tls_config_destroy (tls_config);
         rr_idxp_config_destroy (idxp_config);

         return 0;
}
-------------------------------------------------------------------------


Tested with glib-2.0.1 (shipped with RH) and 2.0.7 (created RPM myself) 
and kernel-2.4.18-27.7.x (shipped with RH) on Redhat 7.3.

Any hint is greatly appreciated!

TIA,
Sandro
-- 
"Linux is like a wigwam: no windows, no gates ... apache inside!"

http://spoppi.home.pages.de/
http://www.lug-burghausen.org/