LCOV - code coverage report
Current view: top level - src - ctx.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 85 132 64.4 %
Date: 2023-08-10 00:00:00 Functions: 15 22 68.2 %

          Line data    Source code
       1             : /* ctx.c
       2             : ** strophe XMPP client library -- run-time context implementation
       3             : **
       4             : ** Copyright (C) 2005-2009 Collecta, Inc.
       5             : **
       6             : **  This software is provided AS-IS with no warranty, either express
       7             : **  or implied.
       8             : **
       9             : **  This program is dual licensed under the MIT and GPLv3 licenses.
      10             : */
      11             : 
      12             : /** @file
      13             :  *  Runtime contexts, library initialization and shutdown, and versioning.
      14             :  */
      15             : 
      16             : /** @defgroup Context Context objects
      17             :  *  These functions create and manipulate Strophe context objects.
      18             :  *
      19             :  *  In order to support usage in a variety of environments, the
      20             :  *  Strophe library uses a runtime context object.  This object
      21             :  *  contains the information on how to do memory allocation and
      22             :  *  logging.  This allows the user to control how memory is allocated
      23             :  *  and what do to with log messages.
      24             :  *
      25             :  *  These issues do not affect programs in the common case, but many
      26             :  *  environments require special treatment.  Abstracting these into a runtime
      27             :  *  context object makes it easy to use Strophe on embedded platforms.
      28             :  *
      29             :  *  Objects in Strophe are reference counted to ease memory management issues,
      30             :  *  but the context objects are not.
      31             :  */
      32             : 
      33             : /** @defgroup Init Initialization, shutdown, and versioning
      34             :  *  These functions initialize and shutdown the library, and also allow
      35             :  *  for API version checking.  Failure to properly call these functions may
      36             :  *  result in strange (and platform dependent) behavior.
      37             :  *
      38             :  *  Specifically, the socket library on Win32 platforms must be initialized
      39             :  *  before use (although this is not the case on POSIX systems).  The TLS
      40             :  *  subsystem must also seed the random number generator.
      41             :  */
      42             : 
      43             : #include <stdlib.h>
      44             : #include <stdio.h>
      45             : #include <stdarg.h>
      46             : #include <string.h>
      47             : 
      48             : #include "strophe.h"
      49             : #include "common.h"
      50             : #include "resolver.h"
      51             : #include "util.h"
      52             : 
      53             : #ifndef va_copy
      54             : #ifdef HAVE_VA_COPY
      55             : #define va_copy(dest, src) va_copy(dest, src)
      56             : #else
      57             : #ifdef HAVE___VA_COPY
      58             : #define va_copy(dest, src) __va_copy(dest, src)
      59             : #else
      60             : #ifndef VA_LIST_IS_ARRAY
      61             : #define va_copy(dest, src) (dest) = (src)
      62             : #else
      63             : #include <string.h>
      64             : #define va_copy(dest, src) \
      65             :     memcpy((char *)(dest), (char *)(src), sizeof(va_list))
      66             : #endif
      67             : #endif
      68             : #endif
      69             : #endif
      70             : 
      71             : /** Initialize the Strophe library.
      72             :  *  This function initializes subcomponents of the Strophe library and must
      73             :  *  be called for Strophe to operate correctly.
      74             :  *
      75             :  *  @ingroup Init
      76             :  */
      77           2 : void xmpp_initialize(void)
      78             : {
      79           2 :     sock_initialize();
      80           2 :     resolver_initialize();
      81           2 :     tls_initialize();
      82           2 : }
      83             : 
      84             : /** Shutdown the Strophe library.
      85             :  *
      86             :  *  @ingroup Init
      87             :  */
      88           2 : void xmpp_shutdown(void)
      89             : {
      90           2 :     tls_shutdown();
      91           2 :     resolver_shutdown();
      92           2 :     sock_shutdown();
      93           2 : }
      94             : 
      95             : /* version information */
      96             : 
      97             : #ifndef LIBXMPP_VERSION_MAJOR
      98             : /** @def LIBXMPP_VERSION_MAJOR
      99             :  *  The major version number of Strophe.
     100             :  */
     101             : #define LIBXMPP_VERSION_MAJOR (0)
     102             : #endif
     103             : #ifndef LIBXMPP_VERSION_MINOR
     104             : /** @def LIBXMPP_VERSION_MINOR
     105             :  *  The minor version number of Strophe.
     106             :  */
     107             : #define LIBXMPP_VERSION_MINOR (0)
     108             : #endif
     109             : 
     110             : #ifndef EVENT_LOOP_DEFAULT_TIMEOUT
     111             : /** @def EVENT_LOOP_DEFAULT_TIMEOUT
     112             :  *  The default timeout in milliseconds for the event loop.
     113             :  *  This is set to 1 second.
     114             :  */
     115             : #define EVENT_LOOP_DEFAULT_TIMEOUT 1000
     116             : #endif
     117             : 
     118             : /** Check that Strophe supports a specific API version.
     119             :  *
     120             :  *  @param major the major version number
     121             :  *  @param minor the minor version number
     122             :  *
     123             :  *  @return TRUE if the version is supported and FALSE if unsupported
     124             :  *
     125             :  *  @ingroup Init
     126             :  */
     127           0 : int xmpp_version_check(int major, int minor)
     128             : {
     129           0 :     return (major == LIBXMPP_VERSION_MAJOR) && (minor >= LIBXMPP_VERSION_MINOR);
     130             : }
     131             : 
     132             : /* We define the global default allocator, logger, and context here. */
     133             : 
     134             : /* Wrap stdlib routines malloc, free, and realloc for default memory
     135             :  * management.
     136             :  */
     137         150 : static void *_malloc(size_t size, void *userdata)
     138             : {
     139         150 :     UNUSED(userdata);
     140         150 :     return malloc(size);
     141             : }
     142             : 
     143         230 : static void _free(void *p, void *userdata)
     144             : {
     145         230 :     UNUSED(userdata);
     146         230 :     free(p);
     147         230 : }
     148             : 
     149           0 : static void *_realloc(void *p, size_t size, void *userdata)
     150             : {
     151           0 :     UNUSED(userdata);
     152           0 :     return realloc(p, size);
     153             : }
     154             : 
     155             : /* default memory function map */
     156             : static xmpp_mem_t xmpp_default_mem = {
     157             :     _malloc, /* use the thinly wrapped stdlib routines by default */
     158             :     _free, _realloc, NULL};
     159             : 
     160             : /* log levels and names */
     161             : static const char *_xmpp_log_level_name[4] = {"DEBUG", "INFO", "WARN", "ERROR"};
     162             : static const xmpp_log_level_t _xmpp_default_logger_levels[] = {
     163             :     XMPP_LEVEL_DEBUG, XMPP_LEVEL_INFO, XMPP_LEVEL_WARN, XMPP_LEVEL_ERROR};
     164             : 
     165             : /** Log a message.
     166             :  *  The default logger writes to stderr.
     167             :  *
     168             :  *  @param userdata the opaque data used by the default logger.  This contains
     169             :  *      the filter level in the default logger.
     170             :  *  @param level the level to log at
     171             :  *  @param area the area the log message is for
     172             :  *  @param msg the log message
     173             :  */
     174          27 : static void xmpp_default_logger(void *userdata,
     175             :                                 xmpp_log_level_t level,
     176             :                                 const char *area,
     177             :                                 const char *msg)
     178             : {
     179          27 :     xmpp_log_level_t filter_level = *(xmpp_log_level_t *)userdata;
     180          27 :     if (level >= filter_level)
     181          27 :         fprintf(stderr, "%s %s %s\n", area, _xmpp_log_level_name[level], msg);
     182          27 : }
     183             : 
     184             : static const xmpp_log_t _xmpp_default_loggers[] = {
     185             :     {&xmpp_default_logger,
     186             :      (void *)&_xmpp_default_logger_levels[XMPP_LEVEL_DEBUG]},
     187             :     {&xmpp_default_logger,
     188             :      (void *)&_xmpp_default_logger_levels[XMPP_LEVEL_INFO]},
     189             :     {&xmpp_default_logger,
     190             :      (void *)&_xmpp_default_logger_levels[XMPP_LEVEL_WARN]},
     191             :     {&xmpp_default_logger,
     192             :      (void *)&_xmpp_default_logger_levels[XMPP_LEVEL_ERROR]}};
     193             : 
     194             : /** Get a default logger with filtering.
     195             :  *  The default logger provides a basic logging setup which writes log
     196             :  *  messages to stderr.  Only messages where level is greater than or
     197             :  *  equal to the filter level will be logged.
     198             :  *
     199             :  *  @param level the highest level the logger will log at
     200             :  *
     201             :  *  @return the log structure for the given level
     202             :  *
     203             :  *  @ingroup Context
     204             :  */
     205           1 : xmpp_log_t *xmpp_get_default_logger(xmpp_log_level_t level)
     206             : {
     207             :     /* clamp to the known range */
     208           1 :     if (level > XMPP_LEVEL_ERROR)
     209             :         level = XMPP_LEVEL_ERROR;
     210             : 
     211           1 :     return (xmpp_log_t *)&_xmpp_default_loggers[level];
     212             : }
     213             : 
     214             : static xmpp_log_t xmpp_default_log = {NULL, NULL};
     215             : 
     216             : /* convenience functions for accessing the context */
     217             : 
     218             : /** Allocate memory in a Strophe context.
     219             :  *  All Strophe functions will use this to allocate memory.
     220             :  *
     221             :  *  @param ctx a Strophe context object
     222             :  *  @param size the number of bytes to allocate
     223             :  *
     224             :  *  @return a pointer to the allocated memory or NULL on an error
     225             :  */
     226         710 : void *strophe_alloc(const xmpp_ctx_t *ctx, size_t size)
     227             : {
     228         710 :     return ctx->mem->alloc(size, ctx->mem->userdata);
     229             : }
     230             : 
     231             : /** Free memory in a Strophe context.
     232             :  *  All Strophe functions will use this to free allocated memory.
     233             :  *
     234             :  *  @param ctx a Strophe context object
     235             :  *  @param p a pointer referencing memory to be freed
     236             :  */
     237        1687 : void strophe_free(const xmpp_ctx_t *ctx, void *p)
     238             : {
     239        1687 :     ctx->mem->free(p, ctx->mem->userdata);
     240        1687 : }
     241             : 
     242             : /** Trampoline to \ref strophe_free
     243             :  *
     244             :  *  @param ctx \ref strophe_free
     245             :  *  @param p \ref strophe_free
     246             :  */
     247          29 : void xmpp_free(const xmpp_ctx_t *ctx, void *p)
     248             : {
     249          29 :     strophe_free(ctx, p);
     250          29 : }
     251             : 
     252             : /** Reallocate memory in a Strophe context.
     253             :  *  All Strophe functions will use this to reallocate memory.
     254             :  *
     255             :  *  @param ctx a Strophe context object
     256             :  *  @param p a pointer to previously allocated memory
     257             :  *  @param size the new size in bytes to allocate
     258             :  *
     259             :  *  @return a pointer to the reallocated memory or NULL on an error
     260             :  */
     261           5 : void *strophe_realloc(const xmpp_ctx_t *ctx, void *p, size_t size)
     262             : {
     263           5 :     return ctx->mem->realloc(p, size, ctx->mem->userdata);
     264             : }
     265             : 
     266             : /** Write a log message to the logger.
     267             :  *  Write a log message to the logger for the context for the specified
     268             :  *  level and area.  This function takes a printf-style format string and a
     269             :  *  variable argument list (in va_list) format.  This function is not meant
     270             :  *  to be called directly, but is used via strophe_error, strophe_warn,
     271             :  * strophe_info, and strophe_debug.
     272             :  *
     273             :  *  @param ctx a Strophe context object
     274             :  *  @param level the level at which to log
     275             :  *  @param area the area to log for
     276             :  *  @param fmt a printf-style format string for the message
     277             :  *  @param ap variable argument list supplied for the format string
     278             :  */
     279          27 : static void _strophe_log(const xmpp_ctx_t *ctx,
     280             :                          xmpp_log_level_t level,
     281             :                          const char *area,
     282             :                          const char *fmt,
     283             :                          va_list ap)
     284             : {
     285          27 :     int oldret, ret;
     286          27 :     char smbuf[1024];
     287          27 :     char *buf;
     288          27 :     va_list copy;
     289             : 
     290          27 :     if (!ctx->log->handler)
     291           0 :         return;
     292             : 
     293          27 :     if (ctx->log->handler == xmpp_default_logger &&
     294          27 :         level < *(xmpp_log_level_t *)ctx->log->userdata)
     295             :         return;
     296             : 
     297          27 :     va_copy(copy, ap);
     298          27 :     ret = strophe_vsnprintf(smbuf, sizeof(smbuf), fmt, ap);
     299          27 :     if (ret >= (int)sizeof(smbuf)) {
     300           0 :         buf = (char *)strophe_alloc(ctx, ret + 1);
     301           0 :         if (!buf) {
     302           0 :             buf = NULL;
     303           0 :             strophe_error(ctx, "log",
     304             :                           "Failed allocating memory for log message.");
     305           0 :             va_end(copy);
     306           0 :             return;
     307             :         }
     308           0 :         oldret = ret;
     309           0 :         ret = strophe_vsnprintf(buf, ret + 1, fmt, copy);
     310           0 :         if (ret > oldret) {
     311           0 :             strophe_error(ctx, "log", "Unexpected error");
     312           0 :             strophe_free(ctx, buf);
     313           0 :             va_end(copy);
     314           0 :             return;
     315             :         }
     316             :     } else {
     317             :         buf = smbuf;
     318             :     }
     319          27 :     va_end(copy);
     320             : 
     321          27 :     ctx->log->handler(ctx->log->userdata, level, area, buf);
     322             : 
     323          27 :     if (buf != smbuf)
     324           0 :         strophe_free(ctx, buf);
     325             : }
     326             : 
     327             : /* Dummy trampoline, will be removed when deprecated.c is deleted */
     328           0 : void strophe_log_internal(const xmpp_ctx_t *ctx,
     329             :                           xmpp_log_level_t level,
     330             :                           const char *area,
     331             :                           const char *fmt,
     332             :                           va_list ap)
     333             : {
     334           0 :     _strophe_log(ctx, level, area, fmt, ap);
     335           0 : }
     336             : 
     337             : /** Write to the log at the ERROR level.
     338             :  *  This is a convenience function for writing to the log at the
     339             :  *  ERROR level.  It takes a printf-style format string followed by a
     340             :  *  variable list of arguments for formatting.
     341             :  *
     342             :  *  @param ctx a Strophe context object
     343             :  *  @param area the area to log for
     344             :  *  @param fmt a printf-style format string followed by a variable list of
     345             :  *      arguments to format
     346             :  */
     347           0 : void strophe_error(const xmpp_ctx_t *ctx,
     348             :                    const char *area,
     349             :                    const char *fmt,
     350             :                    ...)
     351             : {
     352           0 :     va_list ap;
     353             : 
     354           0 :     va_start(ap, fmt);
     355           0 :     _strophe_log(ctx, XMPP_LEVEL_ERROR, area, fmt, ap);
     356           0 :     va_end(ap);
     357           0 : }
     358             : 
     359             : /** Write to the log at the WARN level.
     360             :  *  This is a convenience function for writing to the log at the WARN level.
     361             :  *  It takes a printf-style format string followed by a variable list of
     362             :  *  arguments for formatting.
     363             :  *
     364             :  *  @param ctx a Strophe context object
     365             :  *  @param area the area to log for
     366             :  *  @param fmt a printf-style format string followed by a variable list of
     367             :  *      arguments to format
     368             :  */
     369           3 : void strophe_warn(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
     370             : {
     371           3 :     va_list ap;
     372             : 
     373           3 :     va_start(ap, fmt);
     374           3 :     _strophe_log(ctx, XMPP_LEVEL_WARN, area, fmt, ap);
     375           3 :     va_end(ap);
     376           3 : }
     377             : 
     378             : /** Write to the log at the INFO level.
     379             :  *  This is a convenience function for writing to the log at the INFO level.
     380             :  *  It takes a printf-style format string followed by a variable list of
     381             :  *  arguments for formatting.
     382             :  *
     383             :  *  @param ctx a Strophe context object
     384             :  *  @param area the area to log for
     385             :  *  @param fmt a printf-style format string followed by a variable list of
     386             :  *      arguments to format
     387             :  */
     388           0 : void strophe_info(const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
     389             : {
     390           0 :     va_list ap;
     391             : 
     392           0 :     va_start(ap, fmt);
     393           0 :     _strophe_log(ctx, XMPP_LEVEL_INFO, area, fmt, ap);
     394           0 :     va_end(ap);
     395           0 : }
     396             : 
     397             : /** Write to the log at the DEBUG level.
     398             :  *  This is a convenience function for writing to the log at the DEBUG level.
     399             :  *  It takes a printf-style format string followed by a variable list of
     400             :  *  arguments for formatting.
     401             :  *
     402             :  *  @param ctx a Strophe context object
     403             :  *  @param area the area to log for
     404             :  *  @param fmt a printf-style format string followed by a variable list of
     405             :  *      arguments to format
     406             :  */
     407          24 : void strophe_debug(const xmpp_ctx_t *ctx,
     408             :                    const char *area,
     409             :                    const char *fmt,
     410             :                    ...)
     411             : {
     412          24 :     va_list ap;
     413             : 
     414          24 :     va_start(ap, fmt);
     415          24 :     _strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
     416          24 :     va_end(ap);
     417          24 : }
     418             : 
     419             : /** Write to the log at the DEBUG level if verbosity is enabled.
     420             :  *  This is a convenience function for writing to the log at the DEBUG level.
     421             :  *  It takes a printf-style format string followed by a variable list of
     422             :  *  arguments for formatting.
     423             :  *
     424             :  *  @param level the verbosity level
     425             :  *  @param ctx a Strophe context object
     426             :  *  @param area the area to log for
     427             :  *  @param fmt a printf-style format string followed by a variable list of
     428             :  *      arguments to format
     429             :  */
     430           0 : void strophe_debug_verbose(
     431             :     int level, const xmpp_ctx_t *ctx, const char *area, const char *fmt, ...)
     432             : {
     433           0 :     va_list ap;
     434             : 
     435           0 :     if (ctx->verbosity < level)
     436           0 :         return;
     437             : 
     438           0 :     va_start(ap, fmt);
     439           0 :     _strophe_log(ctx, XMPP_LEVEL_DEBUG, area, fmt, ap);
     440           0 :     va_end(ap);
     441             : }
     442             : 
     443             : /** Create and initialize a Strophe context object.
     444             :  *  If mem is NULL, a default allocation setup will be used which
     445             :  *  wraps malloc(), free(), and realloc() from the standard library.
     446             :  *  If log is NULL, a default logger will be used which does no
     447             :  *  logging.  Basic filtered logging to stderr can be done with the
     448             :  *  xmpp_get_default_logger() convenience function.
     449             :  *
     450             :  *  @param mem a pointer to an xmpp_mem_t structure or NULL
     451             :  *  @param log a pointer to an xmpp_log_t structure or NULL
     452             :  *
     453             :  *  @return the allocated Strophe context object or NULL on an error
     454             :  *
     455             :  *  @ingroup Context
     456             :  */
     457           3 : xmpp_ctx_t *xmpp_ctx_new(const xmpp_mem_t *mem, const xmpp_log_t *log)
     458             : {
     459           3 :     xmpp_ctx_t *ctx = NULL;
     460             : 
     461           3 :     if (mem == NULL)
     462           2 :         ctx = xmpp_default_mem.alloc(sizeof(xmpp_ctx_t), NULL);
     463             :     else
     464           1 :         ctx = mem->alloc(sizeof(xmpp_ctx_t), mem->userdata);
     465             : 
     466           3 :     if (ctx != NULL) {
     467           3 :         if (mem != NULL)
     468           1 :             ctx->mem = mem;
     469             :         else
     470           2 :             ctx->mem = &xmpp_default_mem;
     471             : 
     472           3 :         if (log == NULL)
     473           2 :             ctx->log = &xmpp_default_log;
     474             :         else
     475           1 :             ctx->log = log;
     476             : 
     477           3 :         ctx->connlist = NULL;
     478           3 :         ctx->timed_handlers = NULL;
     479           3 :         ctx->loop_status = XMPP_LOOP_NOTSTARTED;
     480           3 :         ctx->rand = xmpp_rand_new(ctx);
     481           3 :         ctx->timeout = EVENT_LOOP_DEFAULT_TIMEOUT;
     482           3 :         ctx->verbosity = 0;
     483           3 :         if (ctx->rand == NULL) {
     484           0 :             strophe_free(ctx, ctx);
     485           0 :             ctx = NULL;
     486             :         }
     487             :     }
     488             : 
     489           3 :     return ctx;
     490             : }
     491             : 
     492             : /** Free a Strophe context object that is no longer in use.
     493             :  *
     494             :  *  @param ctx a Strophe context object
     495             :  *
     496             :  *  @ingroup Context
     497             :  */
     498           3 : void xmpp_ctx_free(xmpp_ctx_t *ctx)
     499             : {
     500             :     /* mem and log are owned by their suppliers */
     501           3 :     xmpp_rand_free(ctx, ctx->rand);
     502           3 :     strophe_free(ctx, ctx); /* pull the hole in after us */
     503           3 : }
     504             : 
     505             : /** Set the verbosity level of a Strophe context.
     506             :  *
     507             :  *  @param ctx a Strophe context object
     508             :  *  @param level the verbosity level
     509             :  *
     510             :  *  @ingroup Context
     511             :  */
     512           0 : void xmpp_ctx_set_verbosity(xmpp_ctx_t *ctx, int level)
     513             : {
     514           0 :     ctx->verbosity = level;
     515           0 : }

Generated by: LCOV version 1.14