Const variables in prototypes don't add much value, but make the code larger and redundant. Remove these const keywords. Note, this doesn't apply to pointers to const memory.
446 lines
13 KiB
C
446 lines
13 KiB
C
/* ctx.c
|
|
** strophe XMPP client library -- run-time context implementation
|
|
**
|
|
** Copyright (C) 2005-2009 Collecta, Inc.
|
|
**
|
|
** This software is provided AS-IS with no warranty, either express
|
|
** or implied.
|
|
**
|
|
** This program is dual licensed under the MIT and GPLv3 licenses.
|
|
*/
|
|
|
|
/** @file
|
|
* Runtime contexts, library initialization and shutdown, and versioning.
|
|
*/
|
|
|
|
/** @defgroup Context Context objects
|
|
* These functions create and manipulate Strophe context objects.
|
|
*
|
|
* In order to support usage in a variety of environments, the
|
|
* Strophe library uses a runtime context object. This object
|
|
* contains the information on how to do memory allocation and
|
|
* logging. This allows the user to control how memory is allocated
|
|
* and what do to with log messages.
|
|
*
|
|
* These issues do not affect programs in the common case, but many
|
|
* environments require special treatment. Abstracting these into a runtime
|
|
* context object makes it easy to use Strophe on embedded platforms.
|
|
*
|
|
* Objects in Strophe are reference counted to ease memory management issues,
|
|
* but the context objects are not.
|
|
*/
|
|
|
|
/** @defgroup Init Initialization, shutdown, and versioning
|
|
* These functions initialize and shutdown the library, and also allow
|
|
* for API version checking. Failure to properly call these functions may
|
|
* result in strange (and platform dependent) behavior.
|
|
*
|
|
* Specifically, the socket library on Win32 platforms must be initialized
|
|
* before use (although this is not the case on POSIX systems). The TLS
|
|
* subsystem must also seed the random number generator.
|
|
*/
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <stdarg.h>
|
|
#include <string.h>
|
|
|
|
#include "strophe.h"
|
|
#include "common.h"
|
|
#include "resolver.h"
|
|
#include "util.h"
|
|
|
|
/* Workaround for systems without va_copy support. */
|
|
#if defined(_MSC_VER) && _MSC_VER < 1800 || \
|
|
!defined(_MSC_VER) && !defined(HAVE_DECL_VA_COPY)
|
|
#define va_copy(d, s) (memcpy(&d, &s, sizeof(va_list)))
|
|
#endif
|
|
|
|
/** Initialize the Strophe library.
|
|
* This function initializes subcomponents of the Strophe library and must
|
|
* be called for Strophe to operate correctly.
|
|
*
|
|
* @ingroup Init
|
|
*/
|
|
void xmpp_initialize(void)
|
|
{
|
|
sock_initialize();
|
|
resolver_initialize();
|
|
tls_initialize();
|
|
}
|
|
|
|
/** Shutdown the Strophe library.
|
|
*
|
|
* @ingroup Init
|
|
*/
|
|
void xmpp_shutdown(void)
|
|
{
|
|
tls_shutdown();
|
|
resolver_shutdown();
|
|
sock_shutdown();
|
|
}
|
|
|
|
/* version information */
|
|
|
|
#ifndef LIBXMPP_VERSION_MAJOR
|
|
/** @def LIBXMPP_VERSION_MAJOR
|
|
* The major version number of Strophe.
|
|
*/
|
|
#define LIBXMPP_VERSION_MAJOR (0)
|
|
#endif
|
|
#ifndef LIBXMPP_VERSION_MINOR
|
|
/** @def LIBXMPP_VERSION_MINOR
|
|
* The minor version number of Strophe.
|
|
*/
|
|
#define LIBXMPP_VERSION_MINOR (0)
|
|
#endif
|
|
|
|
#ifndef EVENT_LOOP_DEFAULT_TIMEOUT
|
|
/** @def EVENT_LOOP_DEFAULT_TIMEOUT
|
|
* The default timeout in milliseconds for the event loop.
|
|
* This is set to 1 second.
|
|
*/
|
|
#define EVENT_LOOP_DEFAULT_TIMEOUT 1000
|
|
#endif
|
|
|
|
/** Check that Strophe supports a specific API version.
|
|
*
|
|
* @param major the major version number
|
|
* @param minor the minor version number
|
|
*
|
|
* @return TRUE if the version is supported and FALSE if unsupported
|
|
*
|
|
* @ingroup Init
|
|
*/
|
|
int xmpp_version_check(int major, int minor)
|
|
{
|
|
return (major == LIBXMPP_VERSION_MAJOR) && (minor >= LIBXMPP_VERSION_MINOR);
|
|
}
|
|
|
|
/* We define the global default allocator, logger, and context here. */
|
|
|
|
/* Wrap stdlib routines malloc, free, and realloc for default memory
|
|
* management.
|
|
*/
|
|
static void *_malloc(size_t size, void *userdata)
|
|
{
|
|
UNUSED(userdata);
|
|
return malloc(size);
|
|
}
|
|
|
|
static void _free(void *p, void *userdata)
|
|
{
|
|
UNUSED(userdata);
|
|
free(p);
|
|
}
|
|
|
|
static void *_realloc(void *p, size_t size, void *userdata)
|
|
{
|
|
UNUSED(userdata);
|
|
return realloc(p, size);
|
|
}
|
|
|
|
/* default memory function map */
|
|
static xmpp_mem_t xmpp_default_mem = {
|
|
_malloc, /* use the thinly wrapped stdlib routines by default */
|
|
_free, _realloc, NULL};
|
|
|
|
/* log levels and names */
|
|
static const char *_xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
|
|
static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
|
|
XMPP_LEVEL_DEBUG, XMPP_LEVEL_INFO, XMPP_LEVEL_WARN, XMPP_LEVEL_ERROR};
|
|
|
|
/** Log a message.
|
|
* The default logger writes to stderr.
|
|
*
|
|
* @param userdata the opaque data used by the default logger. This contains
|
|
* the filter level in the default logger.
|
|
* @param level the level to log at
|
|
* @param area the area the log message is for
|
|
* @param msg the log message
|
|
*/
|
|
static void xmpp_default_logger(void *userdata,
|
|
xmpp_log_level_t level,
|
|
const char *area,
|
|
const char *msg)
|
|
{
|
|
xmpp_log_level_t filter_level = *(xmpp_log_level_t *)userdata;
|
|
if (level >= filter_level)
|
|
fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
|
|
}
|
|
|
|
static const xmpp_log_t _xmpp_default_loggers[] = {
|
|
{&xmpp_default_logger,
|
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
|
|
{&xmpp_default_logger,
|
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
|
|
{&xmpp_default_logger,
|
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
|
|
{&xmpp_default_logger,
|
|
(void *)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}};
|
|
|
|
/** Get a default logger with filtering.
|
|
* The default logger provides a basic logging setup which writes log
|
|
* messages to stderr. Only messages where level is greater than or
|
|
* equal to the filter level will be logged.
|
|
*
|
|
* @param level the highest level the logger will log at
|
|
*
|
|
* @return the log structure for the given level
|
|
*
|
|
* @ingroup Context
|
|
*/
|
|
xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
|
|
{
|
|
/* clamp to the known range */
|
|
if (level > XMPP_LEVEL_ERROR)
|
|
level = XMPP_LEVEL_ERROR;
|
|
|
|
return (xmpp_log_t *)&_xmpp_default_loggers[level];
|
|
}
|
|
|
|
static xmpp_log_t xmpp_default_log = {NULL, NULL};
|
|
|
|
/* convenience functions for accessing the context */
|
|
|
|
/** Allocate memory in a Strophe context.
|
|
* All Strophe functions will use this to allocate memory.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param size the number of bytes to allocate
|
|
*
|
|
* @return a pointer to the allocated memory or NULL on an error
|
|
*/
|
|
void *xmpp_alloc(const xmpp_ctx_t *ctx, size_t size)
|
|
{
|
|
return ctx->mem->alloc(size, ctx->mem->userdata);
|
|
}
|
|
|
|
/** Free memory in a Strophe context.
|
|
* All Strophe functions will use this to free allocated memory.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param p a pointer referencing memory to be freed
|
|
*/
|
|
void xmpp_free(const xmpp_ctx_t *ctx, void *p)
|
|
{
|
|
ctx->mem->free(p, ctx->mem->userdata);
|
|
}
|
|
|
|
/** Reallocate memory in a Strophe context.
|
|
* All Strophe functions will use this to reallocate memory.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param p a pointer to previously allocated memory
|
|
* @param size the new size in bytes to allocate
|
|
*
|
|
* @return a pointer to the reallocated memory or NULL on an error
|
|
*/
|
|
void *xmpp_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
|
|
{
|
|
return ctx->mem->realloc(p, size, ctx->mem->userdata);
|
|
}
|
|
|
|
/** Write a log message to the logger.
|
|
* Write a log message to the logger for the context for the specified
|
|
* level and area. This function takes a printf-style format string and a
|
|
* variable argument list (in va_list) format. This function is not meant
|
|
* to be called directly, but is used via xmpp_error, xmpp_warn, xmpp_info,
|
|
* and xmpp_debug.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param level the level at which to log
|
|
* @param area the area to log for
|
|
* @param fmt a printf-style format string for the message
|
|
* @param ap variable argument list supplied for the format string
|
|
*/
|
|
void xmpp_log(const xmpp_ctx_t *ctx,
|
|
xmpp_log_level_t level,
|
|
const char *area,
|
|
const char *fmt,
|
|
va_list ap)
|
|
{
|
|
int oldret, ret;
|
|
char smbuf[1024];
|
|
char *buf;
|
|
va_list copy;
|
|
|
|
va_copy(copy, ap);
|
|
ret = xmpp_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
|
|
if (ret >= (int)sizeof(smbuf)) {
|
|
buf = (char *)xmpp_alloc(ctx, ret + 1);
|
|
if (!buf) {
|
|
buf = NULL;
|
|
xmpp_error(ctx, "log", "Failed allocating memory for log message.");
|
|
va_end(copy);
|
|
return;
|
|
}
|
|
oldret = ret;
|
|
ret = xmpp_vsnprintf(buf, ret + 1, fmt, copy);
|
|
if (ret > oldret) {
|
|
xmpp_error(ctx, "log", "Unexpected error");
|
|
xmpp_free(ctx, buf);
|
|
va_end(copy);
|
|
return;
|
|
}
|
|
} else {
|
|
buf = smbuf;
|
|
}
|
|
va_end(copy);
|
|
|
|
if (ctx->log->handler)
|
|
ctx->log->handler(ctx->log->userdata, level, area, buf);
|
|
|
|
if (buf != smbuf)
|
|
xmpp_free(ctx, buf);
|
|
}
|
|
|
|
/** Write to the log at the ERROR level.
|
|
* This is a convenience function for writing to the log at the
|
|
* ERROR level. It takes a printf-style format string followed by a
|
|
* variable list of arguments for formatting.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param area the area to log for
|
|
* @param fmt a printf-style format string followed by a variable list of
|
|
* arguments to format
|
|
*/
|
|
void xmpp_error(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
xmpp_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/** Write to the log at the WARN level.
|
|
* This is a convenience function for writing to the log at the WARN level.
|
|
* It takes a printf-style format string followed by a variable list of
|
|
* arguments for formatting.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param area the area to log for
|
|
* @param fmt a printf-style format string followed by a variable list of
|
|
* arguments to format
|
|
*/
|
|
void xmpp_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
xmpp_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/** Write to the log at the INFO level.
|
|
* This is a convenience function for writing to the log at the INFO level.
|
|
* It takes a printf-style format string followed by a variable list of
|
|
* arguments for formatting.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param area the area to log for
|
|
* @param fmt a printf-style format string followed by a variable list of
|
|
* arguments to format
|
|
*/
|
|
void xmpp_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
xmpp_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/** Write to the log at the DEBUG level.
|
|
* This is a convenience function for writing to the log at the DEBUG level.
|
|
* It takes a printf-style format string followed by a variable list of
|
|
* arguments for formatting.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param area the area to log for
|
|
* @param fmt a printf-style format string followed by a variable list of
|
|
* arguments to format
|
|
*/
|
|
void xmpp_debug(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
|
|
{
|
|
va_list ap;
|
|
|
|
va_start(ap, fmt);
|
|
xmpp_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
|
|
va_end(ap);
|
|
}
|
|
|
|
/** Create and initialize a Strophe context object.
|
|
* If mem is NULL, a default allocation setup will be used which
|
|
* wraps malloc(), free(), and realloc() from the standard library.
|
|
* If log is NULL, a default logger will be used which does no
|
|
* logging. Basic filtered logging to stderr can be done with the
|
|
* xmpp_get_default_logger() convenience function.
|
|
*
|
|
* @param mem a pointer to an xmpp_mem_t structure or NULL
|
|
* @param log a pointer to an xmpp_log_t structure or NULL
|
|
*
|
|
* @return the allocated Strophe context object or NULL on an error
|
|
*
|
|
* @ingroup Context
|
|
*/
|
|
xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
|
|
{
|
|
xmpp_ctx_t *ctx = NULL;
|
|
|
|
if (mem == NULL)
|
|
ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
|
|
else
|
|
ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
|
|
|
|
if (ctx != NULL) {
|
|
if (mem != NULL)
|
|
ctx->mem = mem;
|
|
else
|
|
ctx->mem = &xmpp_default_mem;
|
|
|
|
if (log == NULL)
|
|
ctx->log = &xmpp_default_log;
|
|
else
|
|
ctx->log = log;
|
|
|
|
ctx->connlist = NULL;
|
|
ctx->timed_handlers = NULL;
|
|
ctx->loop_status = XMPP_LOOP_NOTSTARTED;
|
|
ctx->rand = xmpp_rand_new(ctx);
|
|
ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
|
|
if (ctx->rand == NULL) {
|
|
xmpp_free(ctx, ctx);
|
|
ctx = NULL;
|
|
}
|
|
}
|
|
|
|
return ctx;
|
|
}
|
|
|
|
/** Free a Strophe context object that is no longer in use.
|
|
*
|
|
* @param ctx a Strophe context object
|
|
*
|
|
* @ingroup Context
|
|
*/
|
|
void xmpp_ctx_free(xmpp_ctx_t *ctx)
|
|
{
|
|
/* mem and log are owned by their suppliers */
|
|
xmpp_rand_free(ctx, ctx->rand);
|
|
xmpp_free(ctx, ctx); /* pull the hole in after us */
|
|
}
|
|
|
|
/** Set the timeout to use when calling xmpp_run().
|
|
*
|
|
* @param ctx a Strophe context object
|
|
* @param timeout the time to wait for events in milliseconds
|
|
*
|
|
* @ingroup Context
|
|
*/
|
|
void xmpp_ctx_set_timeout(xmpp_ctx_t *ctx, unsigned long timeout)
|
|
{
|
|
ctx->timeout = timeout;
|
|
}
|