23 #include "syncml_internals.h"
25 #include "sml_support.h"
26 #include "sml_error_internals.h"
36 #include <libxml/parser.h>
38 GPrivate* current_tabs = NULL;
39 GPrivate* thread_id = NULL;
41 #define G_ERRORCHECK_MUTEXES
43 static const char* smlCheckDebugDirectory(
const char *env)
45 const char *dirname = g_getenv(env);
49 if (!g_file_test(dirname, G_FILE_TEST_EXISTS)) {
50 if (g_mkdir_with_parents(dirname, 0700) != 0) {
51 g_warning(
"The debug directory %s cannot be created.", dirname);
56 if (!g_file_test(dirname, G_FILE_TEST_IS_DIR)) {
57 g_warning(
"The debug directory %s is not a directory.", dirname);
73 void smlLog(
const char *logname,
const char *data,
unsigned int size)
75 #if defined ENABLE_TRACE
78 if (!(trace = smlCheckDebugDirectory(
"SYNCML_LOG")))
84 char *logfile_tmp = g_strdup_printf(
"%s/%s", trace, logname);
85 logfile = g_strdup_printf(logfile_tmp, i);
86 smlSafeCFree(&logfile_tmp);
87 if (!g_file_test(logfile, G_FILE_TEST_EXISTS))
89 smlSafeCFree(&logfile);
93 GIOChannel *chan = g_io_channel_new_file(logfile,
"w", &error);
95 printf(
"unable to open %s for writing: %s\n", logfile, error->message);
100 g_io_channel_set_encoding(chan, NULL, NULL);
101 if (g_io_channel_write_chars(chan, data, size, &writen, NULL) != G_IO_STATUS_NORMAL) {
102 printf(
"unable to write trace to %s\n", logfile);
104 g_io_channel_flush(chan, NULL);
106 g_io_channel_shutdown(chan, TRUE, NULL);
107 g_io_channel_unref(chan);
120 void smlTrace(SmlTraceType type,
const char *message, ...)
122 #if defined ENABLE_TRACE
125 if (!(trace = smlCheckDebugDirectory(
"SYNCML_TRACE")))
128 if (!g_thread_supported ()) g_thread_init (NULL);
131 current_tabs = g_private_new (NULL);
133 tabs = GPOINTER_TO_INT(g_private_get(current_tabs));
135 unsigned long int id;
140 id = (
unsigned long int)pthread_self().p;
143 thread_id = g_private_new (NULL);
144 id = GPOINTER_TO_INT(thread_id);
149 id = (
unsigned long int)pthread_self();
153 char *logfile = g_strdup_printf(
"%s/Thread%lu-%d.log", trace,
id, pid);
158 va_start(arglist, message);
159 buffer = g_strdup_vprintf(message, arglist);
163 const char *filter = g_getenv(
"SYNCML_TRACE_FILTER");
166 gchar** filters = g_strsplit(filter,
",", 0);
168 SmlBool matched = FALSE;
169 for (i=0; filters[i] != NULL && !matched ; i++)
171 if (strstr(buffer, filters[i]))
177 smlSafeCFree(&buffer);
182 GString *tabstr = g_string_new(
"");
184 for (i = 0; i < tabs; i++) {
185 tabstr = g_string_append(tabstr,
"\t");
189 g_get_current_time(&curtime);
190 char *logmessage = NULL;
193 logmessage = g_strdup_printf(
"[%li.%06li]\t%s>>>>>>> %s%s", curtime.tv_sec, curtime.tv_usec, tabstr->str, buffer, endline);
197 logmessage = g_strdup_printf(
"[%li.%06li]\t%s%s%s", curtime.tv_sec, curtime.tv_usec, tabstr->str, buffer, endline);
200 logmessage = g_strdup_printf(
"[%li.%06li]\t%sERROR: %s%s", curtime.tv_sec, curtime.tv_usec, tabstr->str, buffer, endline);
203 logmessage = g_strdup_printf(
"[%li.%06li]%s<<<<<<< %s%s", curtime.tv_sec, curtime.tv_usec, tabstr->str, buffer, endline);
208 case TRACE_EXIT_ERROR:
209 logmessage = g_strdup_printf(
"[%li.%06li]%s<--- ERROR --- %s%s", curtime.tv_sec, curtime.tv_usec, tabstr->str, buffer, endline);
215 smlSafeCFree(&buffer);
217 g_private_set(current_tabs, GINT_TO_POINTER(tabs));
219 g_string_free(tabstr, TRUE);
221 GError *error = NULL;
222 GIOChannel *chan = g_io_channel_new_file(logfile,
"a", &error);
224 printf(
"unable to open %s for writing: %s%s", logfile, error->message, endline);
225 smlSafeCFree(&logfile);
226 smlSafeCFree(&logmessage);
231 g_io_channel_set_encoding(chan, NULL, NULL);
232 if (g_io_channel_write_chars(chan, logmessage, strlen(logmessage), &writen, NULL) != G_IO_STATUS_NORMAL) {
233 printf(
"unable to write trace to %s%s", logfile, endline);
235 g_io_channel_flush(chan, NULL);
237 g_io_channel_shutdown(chan, TRUE, NULL);
238 g_io_channel_unref(chan);
239 smlSafeCFree(&logmessage);
240 smlSafeCFree(&logfile);
255 GString *str = g_string_new(
"");
256 for (t = 0; t < len; t++) {
257 if (data[t] >=
' ' && data[t] <=
'z')
258 g_string_append_c(str, data[t]);
260 g_string_append_printf(str,
" %02x ", (
unsigned char) data[t]);
262 return g_string_free(str, FALSE);
274 GString *str = g_string_new(
"");
275 for (t = 0; t < len; t++) {
276 g_string_append_printf(str,
" %02x", (
unsigned char) data[t]);
277 if (data[t] >=
' ' && data[t] <=
'z')
278 g_string_append_printf(str,
"(%c)", data[t]);
279 g_string_append_c(str,
' ');
281 return g_string_free(str, FALSE);
304 const char *randchars =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIKLMNOPQRSTUVWXYZ1234567890";
313 length = g_random_int_range(1, maxlength + 1);
315 retchar = malloc(length *
sizeof(
char) + 1);
318 for (i = 0; i < length; i++) {
319 retchar[i] = randchars[g_random_int_range(0, strlen(randchars))];
339 void *result = g_try_malloc(n_bytes);
344 msg = g_strdup_printf(
"No memory left (needed %ld).", n_bytes);
346 msg = g_strdup_printf(
"Malloc of zero bytes requested.");
352 smlErrorSet(error, SML_ERROR_INTERNAL_NO_MEMORY,
"%s", msg);
355 memset(result, 0, n_bytes);
374 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, context, error);
391 if (!g_thread_supported ()) g_thread_init (NULL);
392 if (!g_thread_supported ())
394 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
395 "Threads are not supported.");
399 thread->started = FALSE;
400 thread->started_mutex = g_mutex_new();
401 thread->started_cond = g_cond_new();
402 thread->context = context;
403 g_main_context_ref(thread->context);
404 thread->loop = g_main_loop_new(thread->context, FALSE);
406 smlTrace(TRACE_EXIT,
"%s: %p", __func__, thread);
416 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, thread);
419 if (thread->started_mutex)
420 g_mutex_free(thread->started_mutex);
422 if (thread->started_cond)
423 g_cond_free(thread->started_cond);
426 g_main_loop_unref(thread->loop);
429 g_main_context_unref(thread->context);
431 smlSafeFree((gpointer *)&thread);
432 smlTrace(TRACE_EXIT,
"%s", __func__);
435 static gpointer smlThreadStartCallback(gpointer data)
437 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
439 smlTrace(TRACE_INTERNAL,
"%s: +++++++++ This is the worker thread of thread %p for context %p +++++++++", __func__, thread, thread->context);
441 smlTrace(TRACE_INTERNAL,
"%s: locking", __func__);
442 g_mutex_lock(thread->started_mutex);
443 thread->started = TRUE;
444 smlTrace(TRACE_INTERNAL,
"%s: sending condition", __func__);
445 g_cond_signal(thread->started_cond);
446 smlTrace(TRACE_INTERNAL,
"%s: unlocking", __func__);
447 g_mutex_unlock(thread->started_mutex);
450 if (!g_main_context_acquire(thread->context)) {
451 smlAssertMsg(FALSE,
"This thread is not the owner of the GMainContext.");
453 smlTrace(TRACE_INTERNAL,
"%s: Thread is owner of the GMainContext.", __func__);
456 g_main_loop_run(thread->loop);
459 g_main_context_release(thread->context);
461 smlTrace(TRACE_EXIT,
"%s", __func__);
465 static gboolean smlThreadStopCallback(gpointer data)
467 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
469 smlTrace(TRACE_INTERNAL,
"%s: +++++++++ Quitting worker thread +++++++++", __func__);
471 g_main_loop_quit(thread->loop);
473 smlTrace(TRACE_EXIT,
"%s", __func__);
479 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, thread);
483 smlTrace(TRACE_INTERNAL,
"%s: locking", __func__);
484 g_mutex_lock(thread->started_mutex);
485 smlTrace(TRACE_INTERNAL,
"%s: creating thread", __func__);
486 thread->thread = g_thread_create (smlThreadStartCallback, thread, TRUE, NULL);
487 smlAssert(thread->thread);
488 smlTrace(TRACE_INTERNAL,
"%s: waiting for start", __func__);
489 while(!thread->started) {
490 smlTrace(TRACE_INTERNAL,
"%s: checking condition", __func__);
491 g_cond_wait(thread->started_cond, thread->started_mutex);
493 smlTrace(TRACE_INTERNAL,
"%s: condition received", __func__);
494 g_mutex_unlock(thread->started_mutex);
496 smlTrace(TRACE_EXIT,
"%s", __func__);
501 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, thread);
504 GSource *source = g_idle_source_new();
505 g_source_set_callback(source, smlThreadStopCallback, thread, NULL);
506 g_source_attach(source, thread->context);
508 g_thread_join(thread->thread);
509 thread->thread = NULL;
511 g_source_unref(source);
513 smlTrace(TRACE_EXIT,
"%s", __func__);
524 SmlThreadCallFunctionType func;
536 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, data);
540 ctx->result = ctx->func(ctx->data, ctx->error);
541 g_mutex_lock(ctx->mutex);
542 g_cond_signal(ctx->cond);
543 g_mutex_unlock(ctx->mutex);
546 smlTrace(TRACE_EXIT,
"%s", __func__);
563 SmlThreadCallFunctionType func,
567 smlTrace(TRACE_ENTRY,
"%s(%p => %p, %p, %p, %p)", __func__, thread, thread?thread->context:NULL, func, data, error);
572 smlTrace(TRACE_INTERNAL,
"%s: preparing context", __func__);
577 ctx->mutex = g_mutex_new();
579 smlErrorSet(error, SML_ERROR_GENERIC,
"Cannot create new mutex.");
582 ctx->cond = g_cond_new();
584 smlErrorSet(error, SML_ERROR_GENERIC,
"Cannot create new condition.");
592 smlTrace(TRACE_INTERNAL,
"%s: preparing source", __func__);
593 GSource *source = g_idle_source_new();
597 g_mutex_lock(ctx->mutex);
598 smlTrace(TRACE_INTERNAL,
"%s: attach source", __func__);
599 g_source_attach(source, thread->context);
600 smlTrace(TRACE_INTERNAL,
"%s: wait for condition", __func__);
601 g_cond_wait(ctx->cond, ctx->mutex);
602 smlTrace(TRACE_INTERNAL,
"%s: get condition", __func__);
603 g_mutex_unlock(ctx->mutex);
606 smlTrace(TRACE_INTERNAL,
"%s: cleanup", __func__);
607 SmlBool result = ctx->result;
608 g_source_unref(source);
609 g_mutex_free(ctx->mutex);
610 g_cond_free(ctx->cond);
611 smlSafeFree((gpointer *) &ctx);
614 smlTrace(TRACE_EXIT,
"%s - %i", __func__, result);
618 g_cond_free(ctx->cond);
620 g_mutex_free(ctx->mutex);
622 smlSafeFree((gpointer *) &ctx);
627 void smlSafeFree(gpointer *address)
635 void smlSafeCFree(
char **address)
637 smlSafeFree((gpointer *)address);
640 const char *smlGetLibraryVersion()
642 return PACKAGE_VERSION;
645 const char *smlGetLibrarySoName()
647 return PACKAGE_SONAME;
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
char * smlPrintHex(const char *data, int len)
Used for printing binary data in just hex.
SmlBool smlThreadCallFunction(SmlThread *thread, SmlThreadCallFunctionType func, gpointer data, SmlError **error)
char * smlRandStr(int maxlength, SmlBool exact)
Creates a random string.
char * smlPrintBinary(const char *data, int len)
Used for printing binary data.
const char * smlGetVersion(void)
Gets the version of libsyncml as string.
struct SmlThreadFunctionContext SmlThreadFunctionContext
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
gboolean smlThreadCallFunctionCallback(gpointer data)
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.