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

            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 2.0-1