LCOV - code coverage report
Current view: top level - src - ctx.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 83 130 63.8 %
Date: 2024-02-24 00:00:00 Functions: 15 22 68.2 %

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