diff options
Diffstat (limited to 'wsutil')
83 files changed, 1633 insertions, 642 deletions
diff --git a/wsutil/.clang-tidy b/wsutil/.clang-tidy new file mode 100644 index 00000000..84ea0537 --- /dev/null +++ b/wsutil/.clang-tidy @@ -0,0 +1,10 @@ +InheritParentConfig: true + +# We don't want to do any checks in this directory yet so hack around +# the fact that Clang-Tidy won't let us disable all checks. +# https://stackoverflow.com/a/58379342/82195 +Checks: + - '-*' + - 'misc-definitions-in-headers' +CheckOptions: + - { key: 'HeaderFileExtensions', value: 'DISABLED' } diff --git a/wsutil/.editorconfig b/wsutil/.editorconfig index 78cac438..03257de7 100644 --- a/wsutil/.editorconfig +++ b/wsutil/.editorconfig @@ -97,8 +97,9 @@ indent_size = tab [type_util.[ch]] indent_size = 2 -[u3.[ch]] -indent_size = 2 +[version_info.[ch]] +indent_style = tab +indent_size = tab [ws_getopt.[ch]] indent_style = tab diff --git a/wsutil/802_11-utils.c b/wsutil/802_11-utils.c index ee79f839..2ad5da81 100644 --- a/wsutil/802_11-utils.c +++ b/wsutil/802_11-utils.c @@ -10,6 +10,7 @@ #include "config.h" #include "802_11-utils.h" +#include <wsutil/array.h> typedef struct freq_cvt_s { unsigned fmin; /* Minimum frequency in MHz */ @@ -41,7 +42,7 @@ static freq_cvt_t freq_cvt[] = { { 4910, 4980, 182, false }, }; -#define NUM_FREQ_CVT (sizeof(freq_cvt) / sizeof(freq_cvt_t)) +#define NUM_FREQ_CVT array_length(freq_cvt) #define MAX_CHANNEL(fc) ( (int) ((fc.fmax - fc.fmin) / FREQ_STEP) + fc.cmin ) /* @@ -84,17 +85,44 @@ ieee80211_chan_to_mhz(int chan, bool is_bg) { } /* + * Get Frequency given a Channel number and band. + */ +unsigned +ieee80211_chan_band_to_mhz(int chan, bool is_bg, bool is_6ghz) { + unsigned i; + + int start_idx = 0; + if (is_6ghz) { + start_idx = 3; + } + for (i = start_idx; i < NUM_FREQ_CVT; i++) { + if (is_bg == freq_cvt[i].is_bg && + chan >= freq_cvt[i].cmin && chan <= MAX_CHANNEL(freq_cvt[i])) { + return ((chan - freq_cvt[i].cmin) * FREQ_STEP) + freq_cvt[i].fmin; + } + } + return 0; +} + +/* * Get channel representation string given a Frequency */ char* ieee80211_mhz_to_str(unsigned freq){ int chan = ieee80211_mhz_to_chan(freq); - bool is_bg = FREQ_IS_BG(freq); + const char* band; + if (FREQ_IS_BG(freq)) { + band = "2.4 GHz"; + } else if (FREQ_IS_6G(freq)) { + band = "6 GHz"; + } else { + band = "5 GHz"; + } if (chan < 0) { return ws_strdup_printf("%u", freq); } else { - return ws_strdup_printf("%u [%s %u]", freq, is_bg ? "BG" : "A", + return ws_strdup_printf("%u [%s %u]", freq, band, chan); } } diff --git a/wsutil/802_11-utils.h b/wsutil/802_11-utils.h index 887faddb..5c496da2 100644 --- a/wsutil/802_11-utils.h +++ b/wsutil/802_11-utils.h @@ -51,10 +51,19 @@ WS_DLL_PUBLIC char* ieee80211_mhz_to_str(unsigned freq); +/* + * Get Frequency given a Channel number and band. + */ +WS_DLL_PUBLIC +unsigned +ieee80211_chan_band_to_mhz(int chan, bool is_bg, bool is_6ghz); + /* Should this be "(freq < 4920)", or something else? */ #define FREQ_IS_BG(freq) ((freq) <= 2484) #define CHAN_IS_BG(chan) ((chan) <= 14) +#define FREQ_IS_6G(freq) (5950 <= (freq) && (freq) <= 7125) + /* * Test whether a data rate is an {HR}/DSSS (legacy DSSS/11b) data rate * and whether it's an OFDM (11a/11g OFDM mode) data rate. diff --git a/wsutil/CMakeLists.txt b/wsutil/CMakeLists.txt index ba8633e1..c4bf10bd 100644 --- a/wsutil/CMakeLists.txt +++ b/wsutil/CMakeLists.txt @@ -17,6 +17,8 @@ file(TO_NATIVE_PATH "${PLUGIN_INSTALL_LIBDIR}" PATH_PLUGIN_DIR) string(REPLACE "\\" "\\\\" PATH_PLUGIN_DIR "${PATH_PLUGIN_DIR}") file(TO_NATIVE_PATH "${EXTCAP_INSTALL_LIBDIR}" PATH_EXTCAP_DIR) string(REPLACE "\\" "\\\\" PATH_EXTCAP_DIR "${PATH_EXTCAP_DIR}") +file(TO_NATIVE_PATH "${LOG_EXTCAP_INSTALL_LIBDIR}" PATH_LOG_EXTCAP_DIR) +string(REPLACE "\\" "\\\\" PATH_LOG_EXTCAP_DIR "${PATH_LOG_EXTCAP_DIR}") configure_file(${CMAKE_CURRENT_SOURCE_DIR}/path_config.h.in ${CMAKE_CURRENT_BINARY_DIR}/path_config.h) @@ -74,6 +76,7 @@ set(WMEM_FILES set(WSUTIL_PUBLIC_HEADERS 802_11-utils.h adler32.h + array.h base32.h bits_count_ones.h bits_ctz.h @@ -102,8 +105,7 @@ set(WSUTIL_PUBLIC_HEADERS filesystem.h g711.h inet_addr.h - inet_ipv4.h - inet_ipv6.h + inet_cidr.h interface.h introspection.h jsmn.h @@ -113,6 +115,7 @@ set(WSUTIL_PUBLIC_HEADERS os_version_info.h pint.h please_report_bug.h + plugins.h pow2.h privileges.h processes.h @@ -173,6 +176,7 @@ set(WSUTIL_COMMON_FILES filter_files.c g711.c inet_addr.c + inet_cidr.c interface.c introspection.c jsmn.c @@ -354,7 +358,7 @@ target_compile_definitions(wsutil PRIVATE set_target_properties(wsutil PROPERTIES PREFIX "lib" LINK_FLAGS "${WS_LINK_FLAGS}" - VERSION "15.0.0" SOVERSION 15 + VERSION "16.0.0" SOVERSION 16 FOLDER "DLLs" INSTALL_RPATH "${LIBRARY_INSTALL_RPATH}" ) @@ -371,7 +375,9 @@ target_link_libraries(wsutil ${CMAKE_DL_LIBS} ${GCRYPT_LIBRARIES} ${GNUTLS_LIBRARIES} + ${M_LIBRARIES} ${ZLIB_LIBRARIES} + ${ZLIBNG_LIBRARIES} $<IF:$<CONFIG:Debug>,${PCRE2_DEBUG_LIBRARIES},${PCRE2_LIBRARIES}> ${WIN_IPHLPAPI_LIBRARY} ${WIN_WS2_32_LIBRARY} @@ -385,6 +391,7 @@ target_include_directories(wsutil SYSTEM PRIVATE ${GMODULE2_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} + ${ZLIBNG_INCLUDE_DIRS} ${PCRE2_INCLUDE_DIRS} ) @@ -426,6 +433,7 @@ target_link_libraries(wsutil_static ${GCRYPT_LIBRARIES} ${GNUTLS_LIBRARIES} ${ZLIB_LIBRARIES} + ${ZLIBNG_LIBRARIES} $<IF:$<CONFIG:Debug>,${PCRE2_DEBUG_LIBRARIES},${PCRE2_LIBRARIES}> ${WIN_IPHLPAPI_LIBRARY} ${WIN_WS2_32_LIBRARY} @@ -439,6 +447,7 @@ target_include_directories(wsutil_static SYSTEM PRIVATE ${GMODULE2_INCLUDE_DIRS} ${ZLIB_INCLUDE_DIRS} + ${ZLIBNG_INCLUDE_DIRS} ${PCRE2_INCLUDE_DIRS} ) diff --git a/wsutil/adler32.c b/wsutil/adler32.c index 2830eab4..bdd99395 100644 --- a/wsutil/adler32.c +++ b/wsutil/adler32.c @@ -12,6 +12,13 @@ #include <wsutil/adler32.h> +#ifdef HAVE_ZLIBNG +#include <zlib-ng.h> +#else +#ifdef HAVE_ZLIB +#include <zlib.h> +#endif /* HAVE_ZLIB */ +#endif #include <string.h> #define BASE 65521 /* largest prime smaller than 65536 */ @@ -19,6 +26,13 @@ /*--- update_adler32 --------------------------------------------------------*/ uint32_t update_adler32(uint32_t adler, const uint8_t *buf, size_t len) { +#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG) +#ifdef HAVE_ZLIBNG + return (uint32_t)zng_adler32(adler, buf, len); +#else + return (uint32_t)adler32(adler, buf, len); +#endif +#endif uint32_t s1 = adler & 0xffff; uint32_t s2 = (adler >> 16) & 0xffff; size_t n; @@ -28,6 +42,7 @@ uint32_t update_adler32(uint32_t adler, const uint8_t *buf, size_t len) s2 = (s2 + s1) % BASE; } return (s2 << 16) + s1; + } /*--- adler32 ---------------------------------------------------------------*/ diff --git a/wsutil/array.h b/wsutil/array.h new file mode 100644 index 00000000..1e23b5f6 --- /dev/null +++ b/wsutil/array.h @@ -0,0 +1,25 @@ +/** @file + * Utility functions/macros for handling arrays, C and/or glib. + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __WSUTIL_ARRAY_H__ +#define __WSUTIL_ARRAY_H__ + +#include <stdlib.h> +#include <glib.h> + +/** Useful when you have an array whose size is known at compile-time. */ +#define array_length(x) (sizeof (x) / sizeof (x)[0]) + +/** glib doesn't have g_ptr_array_len, of all things! */ +#ifndef g_ptr_array_len +#define g_ptr_array_len(a) ((a) ? (a)->len : 0) +#endif + +#endif /* __WSUTIL_ARRAY_H__ */ diff --git a/wsutil/bits_count_ones.h b/wsutil/bits_count_ones.h index 1b4f1d68..a77025d7 100644 --- a/wsutil/bits_count_ones.h +++ b/wsutil/bits_count_ones.h @@ -41,11 +41,11 @@ ws_count_ones(const uint64_t x) { uint64_t bits = x; - bits = bits - ((bits >> 1) & G_GUINT64_CONSTANT(0x5555555555555555)); - bits = (bits & G_GUINT64_CONSTANT(0x3333333333333333)) + ((bits >> 2) & G_GUINT64_CONSTANT(0x3333333333333333)); - bits = (bits + (bits >> 4)) & G_GUINT64_CONSTANT(0x0F0F0F0F0F0F0F0F); + bits = bits - ((bits >> 1) & UINT64_C(0x5555555555555555)); + bits = (bits & UINT64_C(0x3333333333333333)) + ((bits >> 2) & UINT64_C(0x3333333333333333)); + bits = (bits + (bits >> 4)) & UINT64_C(0x0F0F0F0F0F0F0F0F); - return (int)((bits * G_GUINT64_CONSTANT(0x0101010101010101)) >> 56); + return (int)((bits * UINT64_C(0x0101010101010101)) >> 56); } #endif /* __WSUTIL_BITS_COUNT_ONES_H__ */ diff --git a/wsutil/buffer.c b/wsutil/buffer.c index 95330086..cdb16a83 100644 --- a/wsutil/buffer.c +++ b/wsutil/buffer.c @@ -16,7 +16,7 @@ #include <wsutil/wslog.h> #define SMALL_BUFFER_SIZE (2 * 1024) /* Everyone still uses 1500 byte frames, right? */ -static GPtrArray *small_buffers = NULL; /* Guaranteed to be at least SMALL_BUFFER_SIZE */ +static GPtrArray *small_buffers; /* Guaranteed to be at least SMALL_BUFFER_SIZE */ /* XXX - Add medium and large buffers? */ /* Initializes a buffer with a certain amount of allocated space */ diff --git a/wsutil/clopts_common.c b/wsutil/clopts_common.c index fa17f8e3..f361b4ef 100644 --- a/wsutil/clopts_common.c +++ b/wsutil/clopts_common.c @@ -59,7 +59,7 @@ get_positive_int(const char *string, const char *name) } uint32_t -get_guint32(const char *string, const char *name) +get_uint32(const char *string, const char *name) { uint32_t number; @@ -76,11 +76,43 @@ get_guint32(const char *string, const char *name) } uint32_t -get_nonzero_guint32(const char *string, const char *name) +get_nonzero_uint32(const char *string, const char *name) { uint32_t number; - number = get_guint32(string, name); + number = get_uint32(string, name); + + if (number == 0) { + cmdarg_err("The specified %s is zero", name); + exit(1); + } + + return number; +} + +uint64_t +get_uint64(const char *string, const char *name) +{ + uint64_t number; + + if (!ws_strtou64(string, NULL, &number)) { + if (errno == EINVAL) { + cmdarg_err("The specified %s \"%s\" isn't a decimal number", name, string); + exit(1); + } + cmdarg_err("The specified %s \"%s\" is too large (greater than %" PRIu64 ")", + name, string, number); + exit(1); + } + return number; +} + +uint64_t +get_nonzero_uint64(const char *string, const char *name) +{ + uint64_t number; + + number = get_uint64(string, name); if (number == 0) { cmdarg_err("The specified %s is zero", name); diff --git a/wsutil/clopts_common.h b/wsutil/clopts_common.h index 3f8b7f71..b401ddeb 100644 --- a/wsutil/clopts_common.h +++ b/wsutil/clopts_common.h @@ -34,6 +34,12 @@ extern "C" { // Base value for GUI specific long options #define LONGOPT_BASE_GUI 4000 +#define LONGOPT_READ_CAPTURE_COMMON \ + {"read-file", ws_required_argument, NULL, 'r' }, \ + +#define OPTSTRING_READ_CAPTURE_COMMON \ + "r:" + WS_DLL_PUBLIC int get_natural_int(const char *string, const char *name); @@ -41,10 +47,24 @@ WS_DLL_PUBLIC int get_positive_int(const char *string, const char *name); WS_DLL_PUBLIC uint32_t -get_guint32(const char *string, const char *name); +get_uint32(const char *string, const char *name); + +WS_DEPRECATED_X("Use get_uint32 instead") +static inline uint32_t +get_guint32(const char *string, const char *name) { return get_uint32(string, name); } WS_DLL_PUBLIC uint32_t -get_nonzero_guint32(const char *string, const char *name); +get_nonzero_uint32(const char *string, const char *name); + +WS_DEPRECATED_X("Use get_nonzero_uint32 instead") +static inline uint32_t +get_nonzero_guint32(const char *string, const char *name) { return get_nonzero_uint32(string, name); } + +WS_DLL_PUBLIC uint64_t +get_uint64(const char *string, const char *name); + +WS_DLL_PUBLIC uint64_t +get_nonzero_uint64(const char *string, const char *name); WS_DLL_PUBLIC double get_positive_double(const char *string, const char *name); diff --git a/wsutil/codecs.c b/wsutil/codecs.c index 857cd33b..dfd5c0e0 100644 --- a/wsutil/codecs.c +++ b/wsutil/codecs.c @@ -18,10 +18,10 @@ #endif #ifdef HAVE_PLUGINS -static plugins_t *libwscodecs_plugins = NULL; +static plugins_t *libwscodecs_plugins; #endif -static GSList *codecs_plugins = NULL; +static GSList *codecs_plugins; #ifdef HAVE_PLUGINS void @@ -84,7 +84,7 @@ struct codec_handle { /* * List of registered codecs. */ -static GHashTable *registered_codecs = NULL; +static GHashTable *registered_codecs; /* Find a registered codec by name. */ diff --git a/wsutil/console_win32.c b/wsutil/console_win32.c index eed18c88..9548ff9b 100644 --- a/wsutil/console_win32.c +++ b/wsutil/console_win32.c @@ -15,7 +15,9 @@ #include <stdlib.h> #include <glib.h> + #include <wsutil/file_util.h> +#include <wsutil/filesystem.h> #include "console_win32.h" @@ -26,7 +28,7 @@ static bool has_console; /* true if app has console */ static bool console_wait; /* "Press any key..." */ -static bool stdin_capture = false; /* Don't grab stdin & stdout if true */ +static bool stdin_capture; /* Don't grab stdin & stdout if true */ /* * Check whether a given standard handle needs to be redirected. @@ -161,7 +163,11 @@ do a FreeConsole() first. */ if (AllocConsole()) { /* That succeeded. */ console_wait = true; - SetConsoleTitle(_T("Wireshark Debug Console")); + if (is_packet_configuration_namespace()) { + SetConsoleTitle(_T("Wireshark Debug Console")); + } else { + SetConsoleTitle(_T("Logray Debug Console")); + } } else { /* On Windows XP, this still fails; FreeConsole() apparently doesn't clear the state, as it does on Windows 7. */ diff --git a/wsutil/cpu_info.c b/wsutil/cpu_info.c index 8b06b070..7c31a3bd 100644 --- a/wsutil/cpu_info.c +++ b/wsutil/cpu_info.c @@ -36,7 +36,7 @@ * model strings. */ static int -compare_model_names(gconstpointer a, gconstpointer b, void * user_data _U_) +compare_model_names(const void *a, const void *b, void * user_data _U_) { return strcmp((const char *)a, (const char *)b); } diff --git a/wsutil/crc16.c b/wsutil/crc16.c index dfb2e2d6..547206b1 100644 --- a/wsutil/crc16.c +++ b/wsutil/crc16.c @@ -375,7 +375,7 @@ static const uint16_t crc16_usb_xorout = 0xFFFF; static uint16_t crc16_unreflected(const uint8_t *buf, unsigned len, uint16_t crc_in, const unsigned table[]) { - /* we use guints, rather than guint16s, as they are likely to be + /* we use uints, rather than uint16s, as they are likely to be faster. We just ignore the top 16 bits and let them do what they want. */ unsigned crc16 = (unsigned)crc_in; @@ -389,7 +389,7 @@ static uint16_t crc16_unreflected(const uint8_t *buf, unsigned len, static uint16_t crc16_reflected(const uint8_t *buf, unsigned len, uint16_t crc_in, const unsigned table[]) { - /* we use guints, rather than guint16s, as they are likely to be + /* we use uints, rather than uint16s, as they are likely to be faster. We just ignore the top 16 bits and let them do what they want. XXX - does any time saved not zero-extending uint16_t's to 32 bits into a register outweigh any increased cache footprint from the diff --git a/wsutil/crc32.c b/wsutil/crc32.c index 4be3d651..96ec9db0 100644 --- a/wsutil/crc32.c +++ b/wsutil/crc32.c @@ -17,6 +17,15 @@ #include <wsutil/crc32.h> +#ifdef HAVE_ZLIBNG +#include <zlib-ng.h> +#else +#ifdef HAVE_ZLIB +#define ZLIB_CONST +#include <zlib.h> +#endif /* HAVE_ZLIB */ +#endif + #define CRC32_ACCUMULATE(c,d,table) (c=(c>>8)^(table)[(c^(d))&0xFF]) /*****************************************************************/ @@ -395,6 +404,13 @@ crc32_ccitt(const uint8_t *buf, unsigned len) uint32_t crc32_ccitt_seed(const uint8_t *buf, unsigned len, uint32_t seed) { +#if defined (HAVE_ZLIB) || defined (HAVE_ZLIBNG) +#ifdef HAVE_ZLIBNG + return (unsigned)zng_crc32(~seed, buf, len); +#else + return (unsigned)crc32(~seed, buf, len); +#endif +#else unsigned i; uint32_t crc32 = seed; @@ -402,6 +418,7 @@ crc32_ccitt_seed(const uint8_t *buf, unsigned len, uint32_t seed) CRC32_ACCUMULATE(crc32, buf[i], crc32_ccitt_table); return ( ~crc32 ); +#endif } uint32_t diff --git a/wsutil/epochs.h b/wsutil/epochs.h index 17d62728..27a88473 100644 --- a/wsutil/epochs.h +++ b/wsutil/epochs.h @@ -62,6 +62,12 @@ * (as they lack a leap year), and one leftover year, 1969, that is * 365 days long. */ -#define EPOCH_DELTA_1601_01_01_00_00_00_UTC G_GUINT64_CONSTANT(11644473600) +#define EPOCH_DELTA_1601_01_01_00_00_00_UTC UINT64_C(11644473600) + +/* + * 2000-01-01 00:00:00 UTC. + * Used by the Zigbee Zigbee Cluster Library protocol. + */ +#define EPOCH_DELTA_2000_01_01_00_00_00_UTC ((unsigned)(((3*365 + 366)*7 + 2*365)*24*3600)) #endif /* __EPOCHS_H__ */ diff --git a/wsutil/exported_pdu_tlvs.h b/wsutil/exported_pdu_tlvs.h index 4850be8e..2799b8a7 100644 --- a/wsutil/exported_pdu_tlvs.h +++ b/wsutil/exported_pdu_tlvs.h @@ -175,11 +175,22 @@ #define EXP_PDU_TAG_P2P_DIRECTION 35 /**< The packet direction (P2P_DIR_SENT, P2P_DIR_RECV). */ -#define EXP_PDU_TAG_COL_INFO_TEXT 36 /**< UTF-8 text string to put in COL_INFO, useful when puting meta data into the packet list. +#define EXP_PDU_TAG_COL_INFO_TEXT 36 /**< UTF-8 text string to put in COL_INFO, useful when putting meta data into the packet list. */ #define EXP_PDU_TAG_USER_DATA_PDU 37 /**< Raw user data PDU which can be dissected as any protocol. */ +/* 3GPP identity types for EXP_PDU_TAG_3GPP_ID */ +#define EXP_PDU_3GPP_ID_CGI 0 /**< 56-bit 2G/3G Cell Global Identifier (MNC big-endian encoding) */ +#define EXP_PDU_3GPP_ID_ECGI 1 /**< 52-bit 4G E-UTRAN Cell Global Identifier (MNC big-endian encoding) */ +#define EXP_PDU_3GPP_ID_NCGI 2 /**< 60-bit NR Cell Global Identifier (MNC big-endian encoding) */ + +/**< Stores a 3GPP identifier. + The value begins with a 1-byte identity type (EXP_PDU_3GPP_ID_*), + followed by the identity itself. +*/ +#define EXP_PDU_TAG_3GPP_ID 38 + #define EXP_PDU_TAG_IPV4_LEN 4 #define EXP_PDU_TAG_IPV6_LEN 16 diff --git a/wsutil/feature_list.c b/wsutil/feature_list.c index f0c30d66..c06a453e 100644 --- a/wsutil/feature_list.c +++ b/wsutil/feature_list.c @@ -22,7 +22,7 @@ with_feature(feature_list l, const char *fmt, ...) va_start(arg, fmt); g_string_append_vprintf(msg, fmt, arg); va_end(arg); - *l = g_list_prepend(*l, g_string_free(msg, false)); + *l = g_list_prepend(*l, g_string_free(msg, FALSE)); } void @@ -33,11 +33,11 @@ without_feature(feature_list l, const char *fmt, ...) va_start(arg, fmt); g_string_append_vprintf(msg, fmt, arg); va_end(arg); - *l = g_list_prepend(*l, g_string_free(msg, false)); + *l = g_list_prepend(*l, g_string_free(msg, FALSE)); } static int -feature_sort_alpha(gconstpointer a, gconstpointer b) +feature_sort_alpha(const void *a, const void *b) { return g_ascii_strcasecmp((char *)a + 1, (char *)b + 1); } diff --git a/wsutil/file_util.c b/wsutil/file_util.c index 4fd55180..d36ae75f 100644 --- a/wsutil/file_util.c +++ b/wsutil/file_util.c @@ -60,9 +60,9 @@ #include "file_util.h" #include "ws_attributes.h" -static char *program_path = NULL; -static char *system_path = NULL; -static char *npcap_path = NULL; +static char *program_path; +static char *system_path; +static char *npcap_path; /** * g_open: @@ -630,8 +630,8 @@ load_wpcap_module(void) */ #define WIRESHARK_IS_RUNNING_UUID "9CA78EEA-EA4D-4490-9240-FC01FCEF464B" -static HANDLE local_running_mutex = NULL; -static HANDLE global_running_mutex = NULL; +static HANDLE local_running_mutex; +static HANDLE global_running_mutex; void create_app_running_mutex(void) { SECURITY_DESCRIPTOR sec_descriptor; diff --git a/wsutil/filesystem.c b/wsutil/filesystem.c index 065cdd3c..bec1cea2 100644 --- a/wsutil/filesystem.c +++ b/wsutil/filesystem.c @@ -9,10 +9,10 @@ */ #include "config.h" -#include "filesystem.h" - #define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL +#include "filesystem.h" + #include <stdio.h> #include <stdlib.h> #include <string.h> @@ -73,18 +73,19 @@ enum configuration_namespace_e configuration_namespace = CONFIGURATION_NAMESPACE #define CONFIGURATION_NAMESPACE_LOWER (configuration_namespace == CONFIGURATION_NAMESPACE_WIRESHARK ? "wireshark" : "logray") #define CONFIGURATION_ENVIRONMENT_VARIABLE(suffix) (configuration_namespace == CONFIGURATION_NAMESPACE_WIRESHARK ? "WIRESHARK_" suffix : "LOGRAY_" suffix) -char *persconffile_dir = NULL; -char *datafile_dir = NULL; -char *persdatafile_dir = NULL; -char *persconfprofile = NULL; -char *doc_dir = NULL; +char *persconffile_dir; +char *datafile_dir; +char *persdatafile_dir; +char *persconfprofile; +char *doc_dir; +char *current_working_dir; /* Directory from which the executable came. */ -static char *progfile_dir = NULL; -static char *install_prefix = NULL; +static char *progfile_dir; +static char *install_prefix; -static bool do_store_persconffiles = false; -static GHashTable *profile_files = NULL; +static bool do_store_persconffiles; +static GHashTable *profile_files; /* * Given a pathname, return a pointer to the last pathname separator @@ -219,6 +220,21 @@ test_for_fifo(const char *path) return 0; } +bool +test_for_regular_file(const char *path) +{ + ws_statb64 statb; + + if (!path) { + return false; + } + + if (ws_stat64(path, &statb) != 0) + return false; + + return S_ISREG(statb.st_mode); +} + #ifdef ENABLE_APPLICATION_BUNDLE /* * Directory of the application bundle in which we're contained, @@ -278,7 +294,7 @@ static char *appbundle_dir; * true if we're running from the build directory and we aren't running * with special privileges. */ -static bool running_in_build_directory_flag = false; +static bool running_in_build_directory_flag; /* * Set our configuration namespace. This will be used for top-level @@ -524,6 +540,13 @@ get_current_executable_path(void) static void trim_progfile_dir(void) { +#ifdef _WIN32 + char *namespace_last_dir = find_last_pathname_separator(progfile_dir); + if (namespace_last_dir && strncmp(namespace_last_dir + 1, CONFIGURATION_NAMESPACE_LOWER, sizeof(CONFIGURATION_NAMESPACE_LOWER)) == 0) { + *namespace_last_dir = '\0'; + } +#endif + char *progfile_last_dir = find_last_pathname_separator(progfile_dir); if (! (progfile_last_dir && strncmp(progfile_last_dir + 1, "extcap", sizeof("extcap")) == 0)) { @@ -581,7 +604,7 @@ get_executable_path(const char *program_name) * g_mallocated string containing an error on failure. */ #ifdef _WIN32 -char * +static char * configuration_init_w32(const char* arg0 _U_) { TCHAR prog_pathname_w[_MAX_PATH+2]; @@ -666,7 +689,7 @@ configuration_init_w32(const char* arg0 _U_) #else /* !_WIN32 */ -char * +static char * configuration_init_posix(const char* arg0) { const char *execname; @@ -943,6 +966,33 @@ get_progfile_dir(void) return progfile_dir; } +extern const char * +get_current_working_dir(void) +{ + if (current_working_dir != NULL) { + return current_working_dir; + } + + /* + * It's good to cache this because on Windows Microsoft cautions + * against using GetCurrentDirectory except early on, e.g. when + * parsing command line options. + */ + current_working_dir = g_get_current_dir(); + /* + * The above always returns something, with a fallback, e.g., on macOS + * if the program is run from Finder, of G_DIR_SEPARATOR_S. + * On Windows when run from a shortcut / taskbar it returns whatever + * the "run in" directory is on the shortcut, which is usually the + * directory where the program resides, which isn't that useful. + * Should we set it to the home directory on macOS or the + * "My Documents" folder on Windows in those cases, + * as we do in get_persdatafile_dir()? This isn't the default preference + * setting so perhaps caveat emptor is ok. + */ + return current_working_dir; +} + /* * Get the directory in which the global configuration and data files are * stored. @@ -1000,7 +1050,7 @@ get_datafile_dir(void) if (running_in_build_directory_flag) { datafile_dir = g_strdup(install_prefix); } else { - datafile_dir = g_build_filename(install_prefix, DATA_DIR, (char *)NULL); + datafile_dir = g_build_filename(install_prefix, DATA_DIR, CONFIGURATION_NAMESPACE_LOWER, (char *)NULL); } #elif defined(_WIN32) /* @@ -1057,7 +1107,7 @@ get_datafile_dir(void) */ datafile_dir = g_strdup(progfile_dir); } else { - datafile_dir = g_build_filename(install_prefix, DATA_DIR, (char *)NULL); + datafile_dir = g_build_filename(install_prefix, DATA_DIR, CONFIGURATION_NAMESPACE_LOWER, (char *)NULL); } #endif return datafile_dir; @@ -1099,8 +1149,7 @@ get_doc_dir(void) * it; we don't need to call started_with_special_privs().) */ else if (appbundle_dir != NULL) { - doc_dir = ws_strdup_printf("%s/Contents/Resources/%s", - appbundle_dir, DOC_DIR); + doc_dir = g_strdup(get_datafile_dir()); } #endif else if (running_in_build_directory_flag && progfile_dir != NULL) { @@ -1138,11 +1187,11 @@ get_doc_dir(void) * otherwise, we use the PLUGIN_DIR value supplied by the * configure script. */ -static char *plugin_dir = NULL; -static char *plugin_dir_with_version = NULL; -static char *plugin_pers_dir = NULL; -static char *plugin_pers_dir_with_version = NULL; -static char *extcap_pers_dir = NULL; +static char *plugin_dir; +static char *plugin_dir_with_version; +static char *plugin_pers_dir; +static char *plugin_pers_dir_with_version; +static char *extcap_pers_dir; static void init_plugin_dir(void) @@ -1155,47 +1204,22 @@ init_plugin_dir(void) * Let {WIRESHARK,LOGRAY}_PLUGIN_DIR take precedence. */ plugin_dir = g_strdup(g_getenv(plugin_dir_envar)); - return; } #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) #if defined(HAVE_MSYSTEM) - if (running_in_build_directory_flag) { + else if (running_in_build_directory_flag) { plugin_dir = g_build_filename(install_prefix, "plugins", (char *)NULL); } else { plugin_dir = g_build_filename(install_prefix, PLUGIN_DIR, (char *)NULL); } #elif defined(_WIN32) - /* - * On Windows, the data file directory is the installation - * directory; the plugins are stored under it. - * - * Assume we're running the installed version of Wireshark; - * on Windows, the data file directory is the directory - * in which the Wireshark binary resides. - */ - plugin_dir = g_build_filename(get_datafile_dir(), "plugins", (char *)NULL); - - /* - * Make sure that pathname refers to a directory. - */ - if (test_for_directory(plugin_dir) != EISDIR) { + else { /* - * Either it doesn't refer to a directory or it - * refers to something that doesn't exist. - * - * Assume that means we're running a version of - * Wireshark we've built in a build directory, - * in which case {datafile dir}\plugins is the - * top-level plugins source directory, and use - * that directory and set the "we're running in - * a build directory" flag, so the plugin - * scanner will check all subdirectories of that - * directory for plugins. + * On Windows, plugins are stored under the program file directory + * in both the build and the installation directories. */ - g_free(plugin_dir); - plugin_dir = g_build_filename(get_datafile_dir(), "plugins", (char *)NULL); - running_in_build_directory_flag = true; + plugin_dir = g_build_filename(get_progfile_dir(), "plugins", (char *)NULL); } #else #ifdef ENABLE_APPLICATION_BUNDLE @@ -1212,7 +1236,7 @@ init_plugin_dir(void) plugin_dir = g_build_filename(appbundle_dir, "Contents/PlugIns", CONFIGURATION_NAMESPACE_LOWER, (char *)NULL); } -#endif +#endif // ENABLE_APPLICATION_BUNDLE else if (running_in_build_directory_flag) { /* * We're (probably) being run from the build directory and @@ -1224,7 +1248,7 @@ init_plugin_dir(void) } else { plugin_dir = g_build_filename(install_prefix, PLUGIN_DIR, (char *)NULL); } -#endif +#endif // HAVE_MSYSTEM / _WIN32 #endif /* defined(HAVE_PLUGINS) || defined(HAVE_LUA) */ } @@ -1287,7 +1311,7 @@ get_plugins_pers_dir_with_version(void) * If the WIRESHARK_EXTCAP_DIR environment variable is set and we are not * running with special privileges, use that. Otherwise: * - * On Windows, we use the "extcap" subdirectory of the datafile directory. + * On Windows, we use the "extcap" subdirectory of the program directory. * * On UN*X: * @@ -1299,7 +1323,7 @@ get_plugins_pers_dir_with_version(void) * * otherwise, we use the EXTCAP_DIR value supplied by CMake. */ -static char *extcap_dir = NULL; +static char *extcap_dir; static void init_extcap_dir(void) @@ -1322,25 +1346,14 @@ init_extcap_dir(void) #elif defined(_WIN32) else { /* - * On Windows, the data file directory is the installation - * directory; the extcap hooks are stored under it. - * - * Assume we're running the installed version of Wireshark; - * on Windows, the data file directory is the directory - * in which the Wireshark binary resides. + * On Windows, extcap utilities are stored in "extcap/<program name>" + * in the program file directory in both the build and installation + * directories. */ - extcap_dir = g_build_filename(get_datafile_dir(), "extcap", (char *)NULL); + extcap_dir = g_build_filename(get_progfile_dir(), EXTCAP_DIR_NAME, + CONFIGURATION_NAMESPACE_LOWER, (char *)NULL); } #else - else if (running_in_build_directory_flag) { - /* - * We're (probably) being run from the build directory and - * weren't started with special privileges, so we'll use - * the "extcap hooks" subdirectory of the directory where the program - * we're running is (that's the build directory). - */ - extcap_dir = g_build_filename(get_progfile_dir(), "extcap", (char *)NULL); - } #ifdef ENABLE_APPLICATION_BUNDLE else if (appbundle_dir != NULL) { /* @@ -1354,11 +1367,22 @@ init_extcap_dir(void) */ extcap_dir = g_build_filename(appbundle_dir, "Contents/MacOS/extcap", (char *)NULL); } -#endif +#endif // ENABLE_APPLICATION_BUNDLE + else if (running_in_build_directory_flag) { + /* + * We're (probably) being run from the build directory and + * weren't started with special privileges, so we'll use + * the "extcap hooks" subdirectory of the directory where the program + * we're running is (that's the build directory). + */ + extcap_dir = g_build_filename(get_progfile_dir(), EXTCAP_DIR_NAME, + CONFIGURATION_NAMESPACE_LOWER, (char *)NULL); + } else { - extcap_dir = g_build_filename(install_prefix, EXTCAP_DIR, (char *)NULL); + extcap_dir = g_build_filename(install_prefix, + is_packet_configuration_namespace() ? EXTCAP_DIR : LOG_EXTCAP_DIR, (char *)NULL); } -#endif +#endif // HAVE_MSYSTEM / _WIN32 } static void @@ -2040,7 +2064,7 @@ copy_persconffile_profile(const char *toname, const char *fromname, bool from_gl from_file = ws_strdup_printf ("%s%s%s", from_dir, G_DIR_SEPARATOR_S, filename); to_file = ws_strdup_printf ("%s%s%s", to_dir, G_DIR_SEPARATOR_S, filename); - if (file_exists(from_file) && !copy_file_binary_mode(from_file, to_file)) { + if (test_for_regular_file(from_file) && !copy_file_binary_mode(from_file, to_file)) { *pf_filename_return = g_strdup(filename); g_free (from_file); g_free (to_file); @@ -2393,37 +2417,48 @@ bool config_file_exists_with_entries(const char *fname, char comment_char) bool files_identical(const char *fname1, const char *fname2) { - /* Two different implementations, because: - * - * - _fullpath is not available on UN*X, so we can't get full - * paths and compare them (which wouldn't work with hard links - * in any case); - * - * - st_ino isn't filled in with a meaningful value on Windows. + /* Two different implementations, because st_ino isn't filled in with + * a meaningful value on Windows. Use the Windows API and FILE_ID_INFO + * instead. */ #ifdef _WIN32 - char full1[MAX_PATH], full2[MAX_PATH]; + + FILE_ID_INFO filestat1, filestat2; /* - * Get the absolute full paths of the file and compare them. - * That won't work if you have hard links, but those aren't - * much used on Windows, even though NTFS supports them. - * - * XXX - will _fullpath work with UNC? + * Compare VolumeSerialNumber and FileId. */ - if( _fullpath( full1, fname1, MAX_PATH ) == NULL ) { + + HANDLE h1 = CreateFile(utf_8to16(fname1), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + + if (h1 == INVALID_HANDLE_VALUE) { return false; } - if( _fullpath( full2, fname2, MAX_PATH ) == NULL ) { + if (!GetFileInformationByHandleEx(h1, FileIdInfo, &filestat1, sizeof(FILE_ID_INFO))) { + CloseHandle(h1); return false; } + CloseHandle(h1); - if(strcmp(full1, full2) == 0) { - return true; - } else { + HANDLE h2 = CreateFile(utf_8to16(fname2), 0, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + NULL, OPEN_EXISTING, 0, NULL); + + if (h2 == INVALID_HANDLE_VALUE) { return false; } + + if (!GetFileInformationByHandleEx(h2, FileIdInfo, &filestat2, sizeof(FILE_ID_INFO))) { + CloseHandle(h2); + return false; + } + CloseHandle(h2); + + return ((memcmp(&filestat1.FileId, &filestat2.FileId, sizeof(FILE_ID_128)) == 0) && + filestat1.VolumeSerialNumber == filestat2.VolumeSerialNumber); #else ws_statb64 filestat1, filestat2; @@ -2692,6 +2727,8 @@ free_progdirs(void) doc_dir = NULL; g_free(install_prefix); install_prefix = NULL; + g_free(current_working_dir); + current_working_dir = NULL; #if defined(HAVE_PLUGINS) || defined(HAVE_LUA) g_free(plugin_dir); plugin_dir = NULL; diff --git a/wsutil/filesystem.h b/wsutil/filesystem.h index fd3e3ebc..e1e2aead 100644 --- a/wsutil/filesystem.h +++ b/wsutil/filesystem.h @@ -302,6 +302,11 @@ WS_DLL_PUBLIC const char *get_persdatafile_dir(void); WS_DLL_PUBLIC void set_persdatafile_dir(const char *p); /* + * Get the current working directory. + */ +WS_DLL_PUBLIC WS_RETNONNULL const char *get_current_working_dir(void); + +/* * Return an error message for UNIX-style errno indications on open or * create operations. */ @@ -359,7 +364,14 @@ WS_DLL_PUBLIC int test_for_directory(const char *); WS_DLL_PUBLIC int test_for_fifo(const char *); /* - * Check, if file is existing. + * Given a pathname, return true if the attempt to "stat()" the file + * succeeds, and it turns out to be a regular file. "stat()" follows + * links, so returns true if the pathname is a link to a regular file. + */ +WS_DLL_PUBLIC bool test_for_regular_file(const char *); + +/* + * Check if a file exists. */ WS_DLL_PUBLIC bool file_exists(const char *fname); diff --git a/wsutil/filter_files.c b/wsutil/filter_files.c index 48464892..1c3c013f 100644 --- a/wsutil/filter_files.c +++ b/wsutil/filter_files.c @@ -23,16 +23,6 @@ #include <wsutil/ws_assert.h> /* - * List of capture filters - saved. - */ -static GList *capture_filters = NULL; - -/* - * List of display filters - saved. - */ -static GList *display_filters = NULL; - -/* * Read in a list of filters. * * On error, report the error via the UI. @@ -60,16 +50,10 @@ free_filter_entry(void * data) g_free(filt); } -void free_filter_lists(void) +void ws_filter_list_free(filter_list_t *fl) { - if (capture_filters) { - g_list_free_full(capture_filters, free_filter_entry); - capture_filters = NULL; - } - if (display_filters) { - g_list_free_full(display_filters, free_filter_entry); - display_filters = NULL; - } + g_list_free_full(fl->list, free_filter_entry); + g_free(fl); } static GList * @@ -114,36 +98,42 @@ getc_crlf(FILE *ff) return c; } -void -read_filter_list(filter_list_type_t list_type) +filter_list_t * +ws_filter_list_read(filter_list_type_t list_type) { const char *ff_name, *ff_description; char *ff_path; FILE *ff; - GList **flpp; + GList *flp = NULL; int c; char *filt_name, *filt_expr; int filt_name_len, filt_expr_len; int filt_name_index, filt_expr_index; int line = 1; + filter_list_t *list = g_new(filter_list_t, 1); + list->type = list_type; + list->list = NULL; + switch (list_type) { case CFILTER_LIST: ff_name = CFILTER_FILE_NAME; ff_description = "capture"; - flpp = &capture_filters; break; case DFILTER_LIST: ff_name = DFILTER_FILE_NAME; ff_description = "display"; - flpp = &display_filters; + break; + + case DMACROS_LIST: + ff_name = DMACROS_FILE_NAME; + ff_description = "display filter macro"; break; default: ws_assert_not_reached(); - return; } /* try to open personal "cfilters"/"dfilters" file */ @@ -159,59 +149,28 @@ read_filter_list(filter_list_type_t list_type) report_warning("Could not open your %s filter file\n\"%s\": %s.", ff_description, ff_path, g_strerror(errno)); g_free(ff_path); - return; + return list; } /* - * Yes. See if there's an "old style" personal "filters" file; if so, read it. - * This means that a user will start out with their capture and - * display filter lists being identical; each list may contain - * filters that don't belong in that list. The user can edit - * the filter lists, and delete the ones that don't belong in - * a particular list. + * Yes. Try to open the global "cfilters/dfilters" file. */ g_free(ff_path); - ff_path = get_persconffile_path(FILTER_FILE_NAME, false); + ff_path = get_datafile_path(ff_name); if ((ff = ws_fopen(ff_path, "r")) == NULL) { /* - * Did that fail because the file didn't exist? + * Well, that didn't work, either. Just give up. + * Report an error if the file existed but we couldn't open it. */ if (errno != ENOENT) { - /* - * No. Just give up. - */ report_warning("Could not open your %s filter file\n\"%s\": %s.", ff_description, ff_path, g_strerror(errno)); - g_free(ff_path); - return; } - - /* - * Try to open the global "cfilters/dfilters" file. - */ g_free(ff_path); - ff_path = get_datafile_path(ff_name); - if ((ff = ws_fopen(ff_path, "r")) == NULL) { - /* - * Well, that didn't work, either. Just give up. - * Report an error if the file existed but we couldn't open it. - */ - if (errno != ENOENT) { - report_warning("Could not open your %s filter file\n\"%s\": %s.", - ff_description, ff_path, g_strerror(errno)); - } - g_free(ff_path); - return; - } + return list; } } - /* If we already have a list of filters, discard it. */ - /* this should never happen - this function is called only once for each list! */ - while(*flpp) { - *flpp = remove_filter_entry(*flpp, g_list_first(*flpp)); - } - /* Allocate the filter name buffer. */ filt_name_len = INIT_BUF_SIZE; filt_name = (char *)g_malloc(filt_name_len + 1); @@ -235,6 +194,12 @@ read_filter_list(filter_list_type_t list_type) break; /* Nothing more to read */ if (c == '\n') continue; /* Blank line. */ + if (c == '#') { + /* Comment. */ + while (c != '\n') + c = getc(ff); /* skip to the end of the line */ + continue; + } /* "c" is the first non-white-space character. If it's not a quote, it's an error. */ @@ -319,7 +284,7 @@ read_filter_list(filter_list_type_t list_type) for (;;) { /* Add this character to the filter expression string. */ if (filt_expr_index >= filt_expr_len) { - /* Filter expressioin buffer isn't long enough; double its length. */ + /* Filter expression buffer isn't long enough; double its length. */ filt_expr_len *= 2; filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1); } @@ -343,14 +308,14 @@ read_filter_list(filter_list_type_t list_type) /* We saw the ending newline; terminate the filter expression string */ if (filt_expr_index >= filt_expr_len) { - /* Filter expressioin buffer isn't long enough; double its length. */ + /* Filter expression buffer isn't long enough; double its length. */ filt_expr_len *= 2; filt_expr = (char *)g_realloc(filt_expr, filt_expr_len + 1); } filt_expr[filt_expr_index] = '\0'; /* Add the new filter to the list of filters */ - *flpp = add_filter_entry(*flpp, filt_name, filt_expr); + flp = add_filter_entry(flp, filt_name, filt_expr); } if (ferror(ff)) { report_warning("Error reading your %s filter file\n\"%s\": %s.", @@ -360,71 +325,44 @@ read_filter_list(filter_list_type_t list_type) fclose(ff); g_free(filt_name); g_free(filt_expr); + list->list = flp; + return list; } /* - * Get a pointer to a list of filters. + * Add a new filter to the end of a list. */ -static GList ** -get_filter_list(filter_list_type_t list_type) +void +ws_filter_list_add(filter_list_t *fl, const char *name, + const char *expression) { - GList **flpp; - - switch (list_type) { - - case CFILTER_LIST: - flpp = &capture_filters; - break; - - case DFILTER_LIST: - flpp = &display_filters; - break; - - default: - ws_assert_not_reached(); - flpp = NULL; - } - return flpp; + fl->list = add_filter_entry(fl->list, name, expression); } -/* - * Get a pointer to the first entry in a filter list. - */ -GList * -get_filter_list_first(filter_list_type_t list_type) +static int +compare_def(const void *def, const void *name) { - GList **flpp; - - flpp = get_filter_list(list_type); - return g_list_first(*flpp); + return g_strcmp0(((filter_def *)def)->name, name); } -/* - * Add a new filter to the end of a list. - * Returns a pointer to the newly-added entry. - */ -GList * -add_to_filter_list(filter_list_type_t list_type, const char *name, - const char *expression) +GList *ws_filter_list_find(filter_list_t *list, const char *name) { - GList **flpp; - - flpp = get_filter_list(list_type); - *flpp = add_filter_entry(*flpp, name, expression); - - return g_list_last(*flpp); + return g_list_find_custom(list->list, name, compare_def); } /* * Remove a filter from a list. */ -void -remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry) +bool +ws_filter_list_remove(filter_list_t *list, const char *name) { - GList **flpp; + GList *p; - flpp = get_filter_list(list_type); - *flpp = remove_filter_entry(*flpp, fl_entry); + p = g_list_find_custom(list->list, name, compare_def); + if (p == NULL) + return false; + list->list = remove_filter_entry(list->list, p); + return true; } /* @@ -433,7 +371,7 @@ remove_from_filter_list(filter_list_type_t list_type, GList *fl_entry) * On error, report the error via the UI. */ void -save_filter_list(filter_list_type_t list_type) +ws_filter_list_write(filter_list_t *list) { char *pf_dir_path; const char *ff_name, *ff_description; @@ -444,24 +382,28 @@ save_filter_list(filter_list_type_t list_type) FILE *ff; unsigned char *p, c; - switch (list_type) { + switch (list->type) { case CFILTER_LIST: ff_name = CFILTER_FILE_NAME; ff_description = "capture"; - fl = capture_filters; break; case DFILTER_LIST: ff_name = DFILTER_FILE_NAME; ff_description = "display"; - fl = display_filters; + break; + + case DMACROS_LIST: + ff_name = DMACROS_FILE_NAME; + ff_description = "display filter macros"; break; default: ws_assert_not_reached(); return; } + fl = list->list; /* Create the directory that holds personal configuration files, if necessary. */ diff --git a/wsutil/filter_files.h b/wsutil/filter_files.h index f3e67872..b493d68a 100644 --- a/wsutil/filter_files.h +++ b/wsutil/filter_files.h @@ -19,11 +19,6 @@ extern "C" { #endif /* __cplusplus */ /* - * Old filter file name. - */ -#define FILTER_FILE_NAME "filters" - -/* * Capture filter file name. */ #define CFILTER_FILE_NAME "cfilters" @@ -34,11 +29,17 @@ extern "C" { #define DFILTER_FILE_NAME "dfilters" /* + * Display filter file name. + */ +#define DMACROS_FILE_NAME "dmacros" + +/* * Filter lists. */ typedef enum { CFILTER_LIST, /* capture filter list - saved */ - DFILTER_LIST /* display filter list - saved */ + DFILTER_LIST, /* display filter list - saved */ + DMACROS_LIST, /* display filter macro list - saved */ } filter_list_type_t; /* @@ -49,33 +50,40 @@ typedef struct { char *strval; /* filter expression */ } filter_def; +typedef struct { + filter_list_type_t type; + GList *list; +} filter_list_t; + /* * Read in a list of filters. * * On error, report the error via the UI. */ WS_DLL_PUBLIC -void read_filter_list(filter_list_type_t list_type); +WS_RETNONNULL +filter_list_t *ws_filter_list_read(filter_list_type_t list_type); /* - * Get a pointer to the first entry in a filter list. + * Add a new filter to the end of a list. + * Returns a pointer to the newly-added entry. */ WS_DLL_PUBLIC -GList *get_filter_list_first(filter_list_type_t list); +void ws_filter_list_add(filter_list_t *list, const char *name, + const char *expression); /* - * Add a new filter to the end of a list. - * Returns a pointer to the newly-added entry. + * Find a filter in a list by name. + * Returns a pointer to the found entry. */ WS_DLL_PUBLIC -GList *add_to_filter_list(filter_list_type_t list, const char *name, - const char *expression); +GList *ws_filter_list_find(filter_list_t *list, const char *name); /* * Remove a filter from a list. */ WS_DLL_PUBLIC -void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); +bool ws_filter_list_remove(filter_list_t *list, const char *name); /* * Write out a list of filters. @@ -83,13 +91,13 @@ void remove_from_filter_list(filter_list_type_t list, GList *fl_entry); * On error, report the error via the UI. */ WS_DLL_PUBLIC -void save_filter_list(filter_list_type_t list_type); +void ws_filter_list_write(filter_list_t *list); /* * Free all filter lists */ WS_DLL_PUBLIC -void free_filter_lists(void); +void ws_filter_list_free(filter_list_t *list); #ifdef __cplusplus } diff --git a/wsutil/g711.c b/wsutil/g711.c index e6c3dcae..7e2345c1 100644 --- a/wsutil/g711.c +++ b/wsutil/g711.c @@ -37,11 +37,11 @@ #define SEG_SHIFT (4) /* Left shift for segment number. */ #define SEG_MASK (0x70) /* Segment field mask. */ -static short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, - 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; +static const short seg_end[8] = {0xFF, 0x1FF, 0x3FF, 0x7FF, + 0xFFF, 0x1FFF, 0x3FFF, 0x7FFF}; /* copy from CCITT G.711 specifications */ -unsigned char _u2a[128] = { /* u- to A-law conversions */ +const unsigned char _u2a[128] = { /* u- to A-law conversions */ 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 10, 11, 12, 13, 14, 15, 16, @@ -59,7 +59,7 @@ unsigned char _u2a[128] = { /* u- to A-law conversions */ 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128}; -unsigned char _a2u[128] = { /* A- to u-law conversions */ +const unsigned char _a2u[128] = { /* A- to u-law conversions */ 1, 3, 5, 7, 9, 11, 13, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, @@ -80,7 +80,7 @@ unsigned char _a2u[128] = { /* A- to u-law conversions */ static int search( int val, - short *table, + const short *table, int size) { int i; diff --git a/wsutil/glib-compat.h b/wsutil/glib-compat.h index 08c87009..ed7511cf 100644 --- a/wsutil/glib-compat.h +++ b/wsutil/glib-compat.h @@ -22,9 +22,71 @@ extern "C" { #endif /* __cplusplus */ +#if !GLIB_CHECK_VERSION(2, 61, 2) + +typedef volatile gint gatomicrefcount; + +typedef struct _GRealArray GRealArray; +struct _GRealArray +{ + guint8 *data; + guint len; + guint alloc; + guint elt_size; + guint zero_terminated ; + guint clear; + gatomicrefcount ref_count; + GDestroyNotify clear_func; +}; + +static inline gboolean +g_array_binary_search (GArray *array, + const void * target, + GCompareFunc compare_func, + guint *out_match_index) +{ + gboolean result = FALSE; + GRealArray *_array = (GRealArray *) array; + guint left, middle, right; + gint val; + + g_return_val_if_fail (_array != NULL, FALSE); + g_return_val_if_fail (compare_func != NULL, FALSE); + + if (G_LIKELY(_array->len)) + { + left = 0; + right = _array->len - 1; + + while (left <= right) + { + middle = left + (right - left) / 2; + + val = compare_func (_array->data + (_array->elt_size * middle), target); + if (val == 0) + { + result = TRUE; + break; + } + else if (val < 0) + left = middle + 1; + else if (/* val > 0 && */ middle > 0) + right = middle - 1; + else + break; /* element not found */ + } + } + + if (result && out_match_index != NULL) + *out_match_index = middle; + + return result; +} +#endif + #if !GLIB_CHECK_VERSION(2, 68, 0) static inline void * -g_memdup2(gconstpointer mem, size_t byte_size) +g_memdup2(const void *mem, size_t byte_size) { void * new_mem; diff --git a/wsutil/inet_addr.h b/wsutil/inet_addr.h index 7147c2ae..6c7feb9b 100644 --- a/wsutil/inet_addr.h +++ b/wsutil/inet_addr.h @@ -12,8 +12,79 @@ #include <wireshark.h> -#include "inet_ipv4.h" -#include "inet_ipv6.h" +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +typedef uint32_t ws_in4_addr; /* 32 bit IPv4 address, in network byte order */ + +typedef struct e_in6_addr { + uint8_t bytes[16]; /* 128 bit IPv6 address */ +} ws_in6_addr; + + +/** + * Unicast Local + * Returns true if the address is in the 224.0.0.0/24 local network + * control block + */ +#define in4_addr_is_local_network_control_block(addr) \ + ((addr & 0xffffff00) == 0xe0000000) + +/** + * Multicast + * Returns true if the address is in the 224.0.0.0/4 network block + */ +#define in4_addr_is_multicast(addr) \ + ((addr & 0xf0000000) == 0xe0000000) + +/** + * Private address + * Returns true if the address is in one of the three blocks reserved + * for private IPv4 addresses by section 3 of RFC 1918, namely: + * 10/8, 172.16/12, and 192.168/16 + */ +#define in4_addr_is_private(addr) \ + (((addr & 0xff000000) == 0x0a000000) || \ + ((addr & 0xfff00000) == 0xac100000) || \ + ((addr & 0xffff0000) == 0xc0a80000)) + +/** + * Link-local address + * Returns true if the address is in the 169.254/16 network block + */ +#define in4_addr_is_link_local(addr) \ + ((addr & 0xffff0000) == 0xa9fe0000) + +/** + * Unicast Scope + * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). + */ +static inline bool +in6_addr_is_linklocal(const ws_in6_addr *a) +{ + return (a->bytes[0] == 0xfe) && ((a->bytes[1] & 0xc0) == 0x80); +} + +static inline bool +in6_addr_is_sitelocal(const ws_in6_addr *a) +{ + return (a->bytes[0] == 0xfe) && ((a->bytes[1] & 0xc0) == 0xc0); +} + +static inline bool in6_addr_is_uniquelocal(const ws_in6_addr *a) +{ + return (a->bytes[0] & 0xfe) == 0xfc; +} + +/** + * Multicast + */ +static inline bool +in6_addr_is_multicast(const ws_in6_addr *a) +{ + return a->bytes[0] == 0xff; +} /* * These are the values specified by RFC 2133 and its successors for @@ -48,24 +119,29 @@ #define WS_INET_ADDRSTRLEN 16 #define WS_INET6_ADDRSTRLEN 46 -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ +/* + * Utility for CIDR notation of subnets + */ +#define WS_INET_CIDRADDRSTRLEN 19 /* * To check for errors set errno to zero before calling ws_inet_ntop{4,6}. * ENOSPC is set if the result exceeds the given buffer size. */ -WS_DLL_PUBLIC WS_RETNONNULL const char * +WS_DLL_PUBLIC WS_RETNONNULL +const char * ws_inet_ntop4(const void *src, char *dst, size_t dst_size); -WS_DLL_PUBLIC WS_RETNONNULL const char * +WS_DLL_PUBLIC WS_RETNONNULL +const char * ws_inet_ntop6(const void *src, char *dst, size_t dst_size); -WS_DLL_PUBLIC bool +WS_DLL_PUBLIC +bool ws_inet_pton4(const char *src, ws_in4_addr *dst); -WS_DLL_PUBLIC bool +WS_DLL_PUBLIC +bool ws_inet_pton6(const char *src, ws_in6_addr *dst); #ifdef __cplusplus diff --git a/wsutil/inet_cidr.c b/wsutil/inet_cidr.c new file mode 100644 index 00000000..89777e16 --- /dev/null +++ b/wsutil/inet_cidr.c @@ -0,0 +1,110 @@ +/* ipv4.c + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#include "inet_cidr.h" + + +uint32_t +ws_ipv4_get_subnet_mask(const uint32_t mask_length) +{ + static const uint32_t masks[33] = { + 0x00000000, + 0x80000000, 0xc0000000, 0xe0000000, 0xf0000000, + 0xf8000000, 0xfc000000, 0xfe000000, 0xff000000, + 0xff800000, 0xffc00000, 0xffe00000, 0xfff00000, + 0xfff80000, 0xfffc0000, 0xfffe0000, 0xffff0000, + 0xffff8000, 0xffffc000, 0xffffe000, 0xfffff000, + 0xfffff800, 0xfffffc00, 0xfffffe00, 0xffffff00, + 0xffffff80, 0xffffffc0, 0xffffffe0, 0xfffffff0, + 0xfffffff8, 0xfffffffc, 0xfffffffe, 0xffffffff, + }; + + ws_assert(mask_length <= 32); + + return masks[mask_length]; +} + +static int +compare_ipv4(const ipv4_addr_and_mask *a, const ipv4_addr_and_mask *b) +{ + uint32_t addr_a, addr_b, nmask; + + nmask = MIN(a->nmask, b->nmask); + addr_a = a->addr & nmask; + addr_b = b->addr & nmask; + if (addr_a < addr_b) + return -1; + if (addr_a > addr_b) + return 1; + return 0; +} + +void +ws_ipv4_addr_and_mask_init(ipv4_addr_and_mask *dst, ws_in4_addr src_addr, int src_bits) +{ + dst->addr = g_ntohl(src_addr); + dst->nmask = ws_ipv4_get_subnet_mask(src_bits); +} + +bool +ws_ipv4_addr_and_mask_contains(const ipv4_addr_and_mask *ipv4, const ws_in4_addr *in_addr) +{ + ipv4_addr_and_mask addr_and_mask; + + addr_and_mask.addr = g_ntohl(*in_addr); + addr_and_mask.nmask = ws_ipv4_get_subnet_mask(32); + return compare_ipv4(ipv4, &addr_and_mask) == 0; +} + +static const uint8_t bitmasks[9] = + { 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff }; + +static int +compare_ipv6(const ipv6_addr_and_prefix *a, const ipv6_addr_and_prefix *b) +{ + uint32_t prefix; + int pos = 0; + + prefix = MIN(a->prefix, b->prefix); /* MIN() like IPv4 */ + prefix = MIN(prefix, 128); /* sanitize, max prefix is 128 */ + + while (prefix >= 8) { + int byte_a = (int) (a->addr.bytes[pos]); + int byte_b = (int) (b->addr.bytes[pos]); + + if (byte_a != byte_b) { + return byte_a - byte_b; + } + + prefix -= 8; + pos++; + } + + if (prefix != 0) { + int byte_a = (int) (a->addr.bytes[pos] & (bitmasks[prefix])); + int byte_b = (int) (b->addr.bytes[pos] & (bitmasks[prefix])); + + if (byte_a != byte_b) { + return byte_a - byte_b; + } + } + + return 0; +} + + +bool +ws_ipv6_addr_and_prefix_contains(const ipv6_addr_and_prefix *ipv6, const ws_in6_addr *in_addr) +{ + ipv6_addr_and_prefix addr_and_mask; + + addr_and_mask.addr = *in_addr; + addr_and_mask.prefix = 128; + return compare_ipv6(ipv6, &addr_and_mask) == 0; +} diff --git a/wsutil/inet_cidr.h b/wsutil/inet_cidr.h new file mode 100644 index 00000000..352b01de --- /dev/null +++ b/wsutil/inet_cidr.h @@ -0,0 +1,62 @@ +/** @file + * Definitions of IPv4 address-and-mask structure, which is what an + * FT_IPV4 value is (even if there's no mask in a packet, those + * values can be compared against an address+mask in a filter + * expression). + * + * Gilbert Ramirez <gram@alumni.rice.edu> + * + * Wireshark - Network traffic analyzer + * By Gerald Combs <gerald@wireshark.org> + * Copyright 1998 Gerald Combs + * + * SPDX-License-Identifier: GPL-2.0-or-later + */ + +#ifndef __IPV4_H__ +#define __IPV4_H__ + +#include <wireshark.h> +#include <wsutil/inet_addr.h> + +typedef struct { + uint32_t addr; /* stored in host order */ + uint32_t nmask; /* stored in host order */ +} ipv4_addr_and_mask; + +typedef struct { + ws_in6_addr addr; + uint32_t prefix; +} ipv6_addr_and_prefix; + +/* + ********** IPv4 ********* + */ + +/** +* Returns the IPv4 subnet mask of the specified length +* +* @param mask_length the number of bits in the subnet mask (max of 32) +* @return the subnet mask of the specified length +*/ +WS_DLL_PUBLIC +uint32_t +ws_ipv4_get_subnet_mask(const uint32_t mask_length); + +WS_DLL_PUBLIC +void +ws_ipv4_addr_and_mask_init(ipv4_addr_and_mask *dst, ws_in4_addr src_addr, int src_bits); + +WS_DLL_PUBLIC +bool +ws_ipv4_addr_and_mask_contains(const ipv4_addr_and_mask *ipv4, const ws_in4_addr *addr); + +/* + ********** IPv6 ********* + */ + +WS_DLL_PUBLIC +bool +ws_ipv6_addr_and_prefix_contains(const ipv6_addr_and_prefix *ipv6, const ws_in6_addr *addr); + +#endif diff --git a/wsutil/inet_ipv4.h b/wsutil/inet_ipv4.h deleted file mode 100644 index a5a8fddd..00000000 --- a/wsutil/inet_ipv4.h +++ /dev/null @@ -1,57 +0,0 @@ -/** @file - * - * Wireshark - Network traffic analyzer - * By Gerald Combs <gerald@wireshark.org> - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef __INET_IPV4_H__ -#define __INET_IPV4_H__ - -#include <inttypes.h> -#include <glib.h> - -typedef uint32_t ws_in4_addr; /* 32 bit IPv4 address, in network byte order */ - -/* - * We define these in *network byte order*, unlike the C library. Therefore - * it uses a different prefix than INADDR_* to make the distinction more obvious. - */ -#define WS_IN4_LOOPBACK ((ws_in4_addr)GUINT32_TO_BE(0x7f000001)) - -/** - * Unicast Local - * Returns true if the address is in the 224.0.0.0/24 local network - * control block - */ -#define in4_addr_is_local_network_control_block(addr) \ - ((addr & 0xffffff00) == 0xe0000000) - -/** - * Multicast - * Returns true if the address is in the 224.0.0.0/4 network block - */ -#define in4_addr_is_multicast(addr) \ - ((addr & 0xf0000000) == 0xe0000000) - -/** - * Private address - * Returns true if the address is in one of the three blocks reserved - * for private IPv4 addresses by section 3 of RFC 1918, namely: - * 10/8, 172.16/12, and 192.168/16 - */ -#define in4_addr_is_private(addr) \ - (((addr & 0xff000000) == 0x0a000000) || \ - ((addr & 0xfff00000) == 0xac100000) || \ - ((addr & 0xffff0000) == 0xc0a80000)) - -/** - * Link-local address - * Returns true if the address is in the 169.254/16 network block - */ -#define in4_addr_is_link_local(addr) \ - ((addr & 0xffff0000) == 0xa9fe0000) - -#endif diff --git a/wsutil/inet_ipv6.h b/wsutil/inet_ipv6.h deleted file mode 100644 index 0cd70394..00000000 --- a/wsutil/inet_ipv6.h +++ /dev/null @@ -1,103 +0,0 @@ -/** @file - * - * Wireshark - Network traffic analyzer - * By Gerald Combs <gerald@wireshark.org> - * Copyright 1998 Gerald Combs - * - * SPDX-License-Identifier: GPL-2.0-or-later - */ - -#ifndef __INET_IPV6_H__ -#define __INET_IPV6_H__ - -#include <inttypes.h> -#include <stdbool.h> - -#define IPv6_ADDR_SIZE 16 - -#define IPv6_HDR_SIZE 40 -#define IPv6_FRAGMENT_HDR_SIZE 8 - -typedef struct e_in6_addr { - uint8_t bytes[16]; /* 128 bit IPv6 address */ -} ws_in6_addr; - -/* - * Definition for internet protocol version 6. - * RFC 2460 - */ -struct ws_ip6_hdr { - uint32_t ip6h_vc_flow; /* version, class, flow */ - uint16_t ip6h_plen; /* payload length */ - uint8_t ip6h_nxt; /* next header */ - uint8_t ip6h_hlim; /* hop limit */ - ws_in6_addr ip6h_src; /* source address */ - ws_in6_addr ip6h_dst; /* destination address */ -}; - -/* - * Extension Headers - */ - -struct ip6_ext { - unsigned char ip6e_nxt; - unsigned char ip6e_len; -}; - -/* Routing header */ -struct ip6_rthdr { - uint8_t ip6r_nxt; /* next header */ - uint8_t ip6r_len; /* length in units of 8 octets */ - uint8_t ip6r_type; /* routing type */ - uint8_t ip6r_segleft; /* segments left */ - /* followed by routing type specific data */ -}; - -/* Type 0 Routing header */ -struct ip6_rthdr0 { - uint8_t ip6r0_nxt; /* next header */ - uint8_t ip6r0_len; /* length in units of 8 octets */ - uint8_t ip6r0_type; /* always zero */ - uint8_t ip6r0_segleft; /* segments left */ - uint8_t ip6r0_reserved; /* reserved field */ - uint8_t ip6r0_slmap[3]; /* strict/loose bit map */ - /* followed by up to 127 addresses */ - ws_in6_addr ip6r0_addr[1]; -}; - -/* Fragment header */ -struct ip6_frag { - uint8_t ip6f_nxt; /* next header */ - uint8_t ip6f_reserved; /* reserved field */ - uint16_t ip6f_offlg; /* offset, reserved, and flag */ - uint32_t ip6f_ident; /* identification */ -}; - -#define IP6F_OFF_MASK 0xfff8 /* mask out offset from _offlg */ -#define IP6F_RESERVED_MASK 0x0006 /* reserved bits in ip6f_offlg */ -#define IP6F_MORE_FRAG 0x0001 /* more-fragments flag */ - - -/** - * Unicast Scope - * Note that we must check topmost 10 bits only, not 16 bits (see RFC2373). - */ -static inline bool in6_addr_is_linklocal(const ws_in6_addr *a) -{ - return (a->bytes[0] == 0xfe) && ((a->bytes[1] & 0xc0) == 0x80); -} - -static inline bool in6_addr_is_sitelocal(const ws_in6_addr *a) -{ - return (a->bytes[0] == 0xfe) && ((a->bytes[1] & 0xc0) == 0xc0); -} - -/** - * Multicast - */ -static inline bool in6_addr_is_multicast(const ws_in6_addr *a) -{ - return a->bytes[0] == 0xff; -} - -#endif diff --git a/wsutil/json_dumper.c b/wsutil/json_dumper.c index 5cbc9494..2761d37c 100644 --- a/wsutil/json_dumper.c +++ b/wsutil/json_dumper.c @@ -11,13 +11,15 @@ * SPDX-License-Identifier: GPL-2.0-or-later */ +#include "config.h" +#define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL + #include <glib.h> #include "json_dumper.h" -#define WS_LOG_DOMAIN LOG_DOMAIN_WSUTIL - #include <math.h> +#include <wsutil/array.h> #include <wsutil/wslog.h> /* @@ -49,7 +51,7 @@ static const char *json_dumper_element_type_names[] = { [JSON_DUMPER_TYPE_ARRAY] = "array", [JSON_DUMPER_TYPE_BASE64] = "base64" }; -#define NUM_JSON_DUMPER_ELEMENT_TYPE_NAMES (sizeof json_dumper_element_type_names / sizeof json_dumper_element_type_names[0]) +#define NUM_JSON_DUMPER_ELEMENT_TYPE_NAMES array_length(json_dumper_element_type_names) #define JSON_DUMPER_FLAGS_ERROR (1 << 16) /* Output flag: an error occurred. */ @@ -414,7 +416,7 @@ json_dumper_end_nested_element(json_dumper *dumper, enum json_dumper_element_typ break; } default: - json_dumper_bad(dumper, "endning unknown nested element type"); + json_dumper_bad(dumper, "ending unknown nested element type"); return false; } diff --git a/wsutil/json_dumper.h b/wsutil/json_dumper.h index 184960ae..d74c6027 100644 --- a/wsutil/json_dumper.h +++ b/wsutil/json_dumper.h @@ -59,7 +59,7 @@ typedef struct json_dumper { GString *output_string; /**< Output GLib strings. If it is not NULL, JSON will be dumped in the string. */ #define JSON_DUMPER_FLAGS_PRETTY_PRINT (1 << 0) /* Enable pretty printing. */ #define JSON_DUMPER_DOT_TO_UNDERSCORE (1 << 1) /* Convert dots to underscores in keys */ -#define JSON_DUMPER_FLAGS_NO_DEBUG (1 << 17) /* Disable fatal ws_error messsges on error(intended for speeding up fuzzing). */ +#define JSON_DUMPER_FLAGS_NO_DEBUG (1 << 17) /* Disable fatal ws_error messages on error(intended for speeding up fuzzing). */ int flags; /* for internal use, initialize with zeroes. */ unsigned current_depth; diff --git a/wsutil/nstime.c b/wsutil/nstime.c index 1f58dbb4..70890afa 100644 --- a/wsutil/nstime.c +++ b/wsutil/nstime.c @@ -183,6 +183,8 @@ double nstime_to_sec(const nstime_t *nstime) } /* + * Compute the minimum and maximum time_t values. + * * This code is based on the Samba code: * * Unix SMB/Netbios implementation. @@ -252,7 +254,7 @@ filetime_to_nstime(nstime_t *nstime, uint64_t filetime) } /* - * function: nsfiletime_to_nstime + * function: filetime_ns_to_nstime * converts a Windows FILETIME-like value, but given in nanoseconds * rather than 10ths of microseconds, to an nstime_t * returns true if the conversion succeeds, false if it doesn't @@ -260,7 +262,7 @@ filetime_to_nstime(nstime_t *nstime, uint64_t filetime) * underflows time_t) */ bool -nsfiletime_to_nstime(nstime_t *nstime, uint64_t nsfiletime) +filetime_ns_to_nstime(nstime_t *nstime, uint64_t nsfiletime) { uint64_t ftsecs; int nsecs; @@ -273,6 +275,25 @@ nsfiletime_to_nstime(nstime_t *nstime, uint64_t nsfiletime) } /* + * function: filetime_1sec_to_nstime + * converts a Windows FILETIME-like value, but given in seconds + * rather than 10ths of microseconds, to an nstime_t + * returns true if the conversion succeeds, false if it doesn't + * (for example, with a 32-bit time_t, the time overflows or + * underflows time_t) + */ +bool +filetime_1sec_to_nstime(nstime_t *nstime, uint64_t filetime_1sec) +{ + /* + * Make sure filetime_1sec fits in a 64-bit signed integer. + */ + if (filetime_1sec > INT64_MAX) + return false; /* No, it doesn't */ + return common_filetime_to_nstime(nstime, filetime_1sec, 0); +} + +/* * function: iso8601_to_nstime * parses a character string for a date and time given in * ISO 8601 date-time format (eg: 2014-04-07T05:41:56.782+00:00) diff --git a/wsutil/nstime.h b/wsutil/nstime.h index acc78b53..bfac25e6 100644 --- a/wsutil/nstime.h +++ b/wsutil/nstime.h @@ -121,7 +121,12 @@ WS_DLL_PUBLIC bool filetime_to_nstime(nstime_t *nstime, uint64_t filetime); /** converts time like Windows FILETIME, but expressed in nanoseconds rather than tenths of microseconds, to nstime, returns true on success, false on failure */ -WS_DLL_PUBLIC bool nsfiletime_to_nstime(nstime_t *nstime, uint64_t nsfiletime); +WS_DLL_PUBLIC bool filetime_ns_to_nstime(nstime_t *nstime, uint64_t nsfiletime); + +/** converts time like Windows FILETIME, but expressed in seconds + rather than tenths of microseconds, to nstime, returns true on success, + false on failure */ +WS_DLL_PUBLIC bool filetime_1sec_to_nstime(nstime_t *nstime, uint64_t filetime); typedef enum { ISO8601_DATETIME, /** e.g. 2014-07-04T12:34:56.789+00:00 */ diff --git a/wsutil/os_version_info.c b/wsutil/os_version_info.c index 69a80c8f..7e9daa05 100644 --- a/wsutil/os_version_info.c +++ b/wsutil/os_version_info.c @@ -565,7 +565,7 @@ DIAG_ON(cast-function-type) * trusted at all? * * As for the Windows Server 2022 entry, - * is that just becuase that script doesn't + * is that just because that script doesn't * bother checking for "workstation" vs. * "server"? */ @@ -760,7 +760,7 @@ DIAG_ON(cast-function-type) * The first line parser reads the first line of the file. * If a string is passed to it, it constructs a distribution * name string by concatenating the parameter, a space, - * and the contents of that line (iwth the newline removed), + * and the contents of that line (with the newline removed), * otherwise it constructs it from the contents of the line. * * Fall back on just "Linux" if nothing works. diff --git a/wsutil/path_config.h.in b/wsutil/path_config.h.in index 6539a5ab..59d1f504 100644 --- a/wsutil/path_config.h.in +++ b/wsutil/path_config.h.in @@ -6,5 +6,6 @@ #define DOC_DIR "@PATH_DOC_DIR@" #define PLUGIN_DIR "@PATH_PLUGIN_DIR@" #define EXTCAP_DIR "@PATH_EXTCAP_DIR@" +#define LOG_EXTCAP_DIR "@PATH_LOG_EXTCAP_DIR@" #endif diff --git a/wsutil/pint.h b/wsutil/pint.h index 97b6da23..b4984b5f 100644 --- a/wsutil/pint.h +++ b/wsutil/pint.h @@ -52,7 +52,7 @@ */ #if defined(_MSC_VER) && !defined(__INTEL_COMPILER) && !defined(__INTEL_LLVM_COMPILER) && !defined(__clang__) /* Intel and clang-cl both define _MSC_VER when compiling on Windows for - * greater compatiblity (just as they define __GNUC__ on other platforms). + * greater compatibility (just as they define __GNUC__ on other platforms). * However, at least on some versions, while including the MSVC <stdlib.h> * provides access to the _byteswap_ intrinsics, they are not actually * optimized into a single x86 BSWAP function, unlike the gcc-style intrinsics @@ -366,9 +366,6 @@ static inline uint64_t pletoh56(const void *p) (uint64_t)*((const uint8_t *)(p)+0)<<0; } -/* Subtract two guint32s with respect to wraparound */ -#define guint32_wraparound_diff(higher, lower) ((higher>lower)?(higher-lower):(higher+0xffffffff-lower+1)) - #endif /* PINT_H */ /* diff --git a/wsutil/plugins.c b/wsutil/plugins.c index 2798fdc3..23862949 100644 --- a/wsutil/plugins.c +++ b/wsutil/plugins.c @@ -30,19 +30,14 @@ typedef struct _plugin { GModule *handle; /* handle returned by g_module_open */ char *name; /* plugin name */ const char *version; /* plugin version */ - const char *type_name; /* user-facing name (what it does). Should these be capitalized? */ + uint32_t flags; /* plugin flags */ } plugin; #define TYPE_DIR_EPAN "epan" #define TYPE_DIR_WIRETAP "wiretap" #define TYPE_DIR_CODECS "codecs" -#define TYPE_NAME_DISSECTOR "dissector" -#define TYPE_NAME_FILE_TYPE "file type" -#define TYPE_NAME_CODEC "codec" - - -static GSList *plugins_module_list = NULL; +static GSList *plugins_module_list; static inline const char * @@ -63,20 +58,24 @@ type_to_dir(plugin_type_e type) } static inline const char * -type_to_name(plugin_type_e type) +flags_to_str(uint32_t flags) { - switch (type) { - case WS_PLUGIN_EPAN: - return TYPE_NAME_DISSECTOR; - case WS_PLUGIN_WIRETAP: - return TYPE_NAME_FILE_TYPE; - case WS_PLUGIN_CODEC: - return TYPE_NAME_CODEC; - default: - ws_error("Unknown plugin type: %u. Aborting.", (unsigned) type); - break; - } - ws_assert_not_reached(); + /* XXX: Allow joining multiple types? Our plugins only implement a + * single type but out in the wild this may not be true. */ + if (flags & WS_PLUGIN_DESC_DISSECTOR) + return "dissector"; + else if (flags & WS_PLUGIN_DESC_FILE_TYPE) + return "file type"; + else if (flags & WS_PLUGIN_DESC_CODEC) + return "codec"; + else if (flags & WS_PLUGIN_DESC_EPAN) + return "epan"; + else if (flags & WS_PLUGIN_DESC_TAP_LISTENER) + return "tap listener"; + else if (flags & WS_PLUGIN_DESC_DFILTER) + return "dfilter"; + else + return "unknown"; } static void @@ -89,7 +88,7 @@ free_plugin(void * data) } static int -compare_plugins(gconstpointer a, gconstpointer b) +compare_plugins(const void *a, const void *b) { return g_strcmp0((*(plugin *const *)a)->name, (*(plugin *const *)b)->name); } @@ -138,6 +137,7 @@ scan_plugins_dir(GHashTable *plugins_module, const char *dirpath, plugin_type_e GModule *handle; /* handle returned by g_module_open */ void * symbol; const char *plug_version; + uint32_t flags; plugin *new_plug; if (append_type) @@ -206,11 +206,17 @@ DIAG_OFF_PEDANTIC ((plugin_register_func)symbol)(); DIAG_ON_PEDANTIC + /* Search for the (optional) description flag registration function */ + if (g_module_symbol(handle, "plugin_describe", &symbol)) + flags = ((plugin_describe_func)symbol)(); + else + flags = 0; + new_plug = g_new(plugin, 1); new_plug->handle = handle; new_plug->name = g_strdup(name); new_plug->version = plug_version; - new_plug->type_name = type_to_name(type); + new_plug->flags = flags; /* Add it to the list of plugins. */ g_hash_table_replace(plugins_module, new_plug->name, new_plug); @@ -272,7 +278,7 @@ plugins_get_descriptions(plugin_description_callback callback, void *callback_da for (unsigned i = 0; i < plugins_array->len; i++) { plugin *plug = (plugin *)plugins_array->pdata[i]; - callback(plug->name, plug->version, plug->type_name, g_module_name(plug->handle), callback_data); + callback(plug->name, plug->version, plug->flags, g_module_name(plug->handle), callback_data); } g_ptr_array_free(plugins_array, true); @@ -280,10 +286,10 @@ plugins_get_descriptions(plugin_description_callback callback, void *callback_da static void print_plugin_description(const char *name, const char *version, - const char *description, const char *filename, + uint32_t flags, const char *filename, void *user_data _U_) { - printf("%-16s\t%s\t%s\t%s\n", name, version, description, filename); + printf("%-16s\t%s\t%s\t%s\n", name, version, flags_to_str(flags), filename); } void diff --git a/wsutil/plugins.h b/wsutil/plugins.h index 96f3ac03..113f1f68 100644 --- a/wsutil/plugins.h +++ b/wsutil/plugins.h @@ -18,6 +18,7 @@ extern "C" { #endif /* __cplusplus */ typedef void (*plugin_register_func)(void); +typedef uint32_t (*plugin_describe_func)(void); typedef void plugins_t; @@ -27,10 +28,17 @@ typedef enum { WS_PLUGIN_CODEC } plugin_type_e; +#define WS_PLUGIN_DESC_DISSECTOR (1UL << 0) +#define WS_PLUGIN_DESC_FILE_TYPE (1UL << 1) +#define WS_PLUGIN_DESC_CODEC (1UL << 2) +#define WS_PLUGIN_DESC_EPAN (1UL << 3) +#define WS_PLUGIN_DESC_TAP_LISTENER (1UL << 4) +#define WS_PLUGIN_DESC_DFILTER (1UL << 5) + WS_DLL_PUBLIC plugins_t *plugins_init(plugin_type_e type); typedef void (*plugin_description_callback)(const char *name, const char *version, - const char *types, const char *filename, + uint32_t flags, const char *filename, void *user_data); WS_DLL_PUBLIC void plugins_get_descriptions(plugin_description_callback callback, void *user_data); diff --git a/wsutil/privileges.c b/wsutil/privileges.c index 2ca30203..6ee0dfd5 100644 --- a/wsutil/privileges.c +++ b/wsutil/privileges.c @@ -118,7 +118,7 @@ get_cur_groupname(void) { static uid_t ruid, euid; static gid_t rgid, egid; -static bool init_process_policies_called = false; +static bool init_process_policies_called; /* * Called when the program starts, to save whatever credential information diff --git a/wsutil/regex.c b/wsutil/regex.c index bb27189b..464a4223 100644 --- a/wsutil/regex.c +++ b/wsutil/regex.c @@ -60,6 +60,8 @@ compile_pcre2(const char *patt, ssize_t size, char **errmsg, unsigned flags) options |= PCRE2_NEVER_UTF; if (flags & WS_REGEX_CASELESS) options |= PCRE2_CASELESS; + if (flags & WS_REGEX_ANCHORED) + options |= PCRE2_ANCHORED; /* By default UTF-8 is off. */ code = pcre2_compile_8((PCRE2_SPTR)patt, @@ -103,7 +105,7 @@ ws_regex_compile(const char *patt, char **errmsg) static bool match_pcre2(pcre2_code *code, const char *subject, ssize_t subj_length, - pcre2_match_data *match_data) + size_t subj_offset, pcre2_match_data *match_data) { PCRE2_SIZE length; int rc; @@ -116,7 +118,7 @@ match_pcre2(pcre2_code *code, const char *subject, ssize_t subj_length, rc = pcre2_match(code, subject, length, - 0, /* start at offset zero of the subject */ + (PCRE2_SIZE)subj_offset, 0, /* default options */ match_data, NULL); @@ -158,7 +160,7 @@ ws_regex_matches_length(const ws_regex_t *re, /* We don't use the matched substring but pcre2_match requires * at least one pair of offsets. */ match_data = pcre2_match_data_create(1, NULL); - matched = match_pcre2(re->code, subj, subj_length, match_data); + matched = match_pcre2(re->code, subj, subj_length, 0, match_data); pcre2_match_data_free(match_data); return matched; } @@ -167,7 +169,7 @@ ws_regex_matches_length(const ws_regex_t *re, bool ws_regex_matches_pos(const ws_regex_t *re, const char *subj, ssize_t subj_length, - size_t pos_vect[2]) + size_t subj_offset, size_t pos_vect[2]) { bool matched; pcre2_match_data *match_data; @@ -176,7 +178,7 @@ ws_regex_matches_pos(const ws_regex_t *re, ws_return_val_if(!subj, false); match_data = pcre2_match_data_create(1, NULL); - matched = match_pcre2(re->code, subj, subj_length, match_data); + matched = match_pcre2(re->code, subj, subj_length, subj_offset, match_data); if (matched && pos_vect) { PCRE2_SIZE *ovect = pcre2_get_ovector_pointer(match_data); pos_vect[0] = ovect[0]; diff --git a/wsutil/regex.h b/wsutil/regex.h index 0484eab3..199779a2 100644 --- a/wsutil/regex.h +++ b/wsutil/regex.h @@ -26,6 +26,7 @@ ws_regex_compile(const char *patt, char **errmsg); /* By default UTF-8 is off. This option also prevents it from being * turned on using a pattern option. */ #define WS_REGEX_NEVER_UTF (1U << 1) +#define WS_REGEX_ANCHORED (1U << 2) WS_DLL_PUBLIC ws_regex_t * ws_regex_compile_ex(const char *patt, ssize_t size, char **errmsg, unsigned flags); @@ -41,14 +42,19 @@ ws_regex_matches_length(const ws_regex_t *re, /** Returns start and end position of the matched substring. * + * @note Using a nonzero subj_offset produces different results than + * passing a pointer to the later offset as subj when the pattern + * begins with a lookbehind. + * * pos_vect[0] is first codepoint in the matched substring. - * pos_vect[1] is the next to last codepoint in the matched substring. + * pos_vect[1] is first codepoint past the matched substring. * pos_vect[1] - pos_vect[0] is the matched substring length. + * */ WS_DLL_PUBLIC bool ws_regex_matches_pos(const ws_regex_t *re, const char *subj, ssize_t subj_length, - size_t pos_vect[2]); + size_t subj_offset, size_t pos_vect[2]); WS_DLL_PUBLIC void ws_regex_free(ws_regex_t *re); diff --git a/wsutil/report_message.c b/wsutil/report_message.c index 6f797fab..5e88466a 100644 --- a/wsutil/report_message.c +++ b/wsutil/report_message.c @@ -124,7 +124,7 @@ report_cfile_read_failure(const char *filename, int err, char *err_info) */ void report_cfile_write_failure(const char *in_filename, const char *out_filename, - int err, char *err_info, uint32_t framenum, int file_type_subtype) + int err, char *err_info, uint64_t framenum, int file_type_subtype) { (*routines->report_cfile_write_failure)(in_filename, out_filename, err, err_info, framenum, file_type_subtype); diff --git a/wsutil/report_message.h b/wsutil/report_message.h index 7be1808b..7c64e8ae 100644 --- a/wsutil/report_message.h +++ b/wsutil/report_message.h @@ -32,14 +32,14 @@ extern "C" { struct report_message_routines { void (*vreport_failure)(const char *, va_list); void (*vreport_warning)(const char *, va_list); - void (*report_open_failure)(const char *, int, gboolean); + void (*report_open_failure)(const char *, int, bool); void (*report_read_failure)(const char *, int); void (*report_write_failure)(const char *, int); void (*report_cfile_open_failure)(const char *, int, char *); void (*report_cfile_dump_open_failure)(const char *, int, char *, int); void (*report_cfile_read_failure)(const char *, int, char *); void (*report_cfile_write_failure)(const char *, const char *, - int, char *, uint32_t, int); + int, char *, uint64_t, int); void (*report_cfile_close_failure)(const char *, int, char *); }; @@ -99,7 +99,7 @@ WS_DLL_PUBLIC void report_cfile_read_failure(const char *filename, * Report an error from attempting to write to a capture file. */ WS_DLL_PUBLIC void report_cfile_write_failure(const char *in_filename, - const char *out_filename, int err, char *err_info, uint32_t framenum, + const char *out_filename, int err, char *err_info, uint64_t framenum, int file_type_subtype); /* diff --git a/wsutil/sign_ext.h b/wsutil/sign_ext.h index 67401edb..e8c622a9 100644 --- a/wsutil/sign_ext.h +++ b/wsutil/sign_ext.h @@ -52,8 +52,8 @@ ws_sign_ext64(uint64_t val, int no_of_bits) * the number of bits in the value - 1, and we might get * compile-time or run-time complaints about that. */ - if (val & (G_GUINT64_CONSTANT(1) << (no_of_bits-1))) - val |= (G_GUINT64_CONSTANT(0xFFFFFFFFFFFFFFFF) << no_of_bits); + if (val & (UINT64_C(1) << (no_of_bits-1))) + val |= (UINT64_C(0xFFFFFFFFFFFFFFFF) << no_of_bits); return val; } diff --git a/wsutil/str_util.c b/wsutil/str_util.c index 4243b22b..556ef5a9 100644 --- a/wsutil/str_util.c +++ b/wsutil/str_util.c @@ -13,6 +13,8 @@ #include "str_util.h" #include <string.h> +#include <locale.h> +#include <math.h> #include <ws_codepoints.h> @@ -339,10 +341,41 @@ ws_ascii_strcasestr(const char *haystack, const char *needle) return NULL; } +/* Return the last occurrence of ch in the n bytes of haystack. + * If not found or n is 0, return NULL. */ +const uint8_t * +ws_memrchr(const void *_haystack, int ch, size_t n) +{ +#ifdef HAVE_MEMRCHR + return memrchr(_haystack, ch, n); +#else + /* A generic implementation. This could be optimized considerably, + * e.g. by fetching a word at a time. + */ + if (n == 0) { + return NULL; + } + const uint8_t *haystack = _haystack; + const uint8_t *p; + uint8_t c = (uint8_t)ch; + + const uint8_t *const end = haystack + n - 1; + + for (p = end; p >= haystack; --p) { + if (*p == c) { + return p; + } + } + + return NULL; +#endif /* HAVE_MEMRCHR */ +} + #define FORMAT_SIZE_UNIT_MASK 0x00ff #define FORMAT_SIZE_PFX_MASK 0xff00 -static const char *thousands_grouping_fmt = NULL; +static const char *thousands_grouping_fmt; +static const char *thousands_grouping_fmt_flt; DIAG_OFF(format) static void test_printf_thousands_grouping(void) { @@ -351,16 +384,213 @@ static void test_printf_thousands_grouping(void) { wmem_strbuf_append_printf(buf, "%'d", 22); if (g_strcmp0(wmem_strbuf_get_str(buf), "22") == 0) { thousands_grouping_fmt = "%'"PRId64; + thousands_grouping_fmt_flt = "%'.*f"; } else { /* Don't use */ thousands_grouping_fmt = "%"PRId64; + thousands_grouping_fmt_flt = "%.*f"; } wmem_strbuf_destroy(buf); } DIAG_ON(format) +static const char* decimal_point = NULL; + +static void truncate_numeric_strbuf(wmem_strbuf_t *strbuf, int n) { + + const char *s = wmem_strbuf_get_str(strbuf); + char *p; + int count; + + if (decimal_point == NULL) { + decimal_point = localeconv()->decimal_point; + } + + p = strchr(s, decimal_point[0]); + if (p != NULL) { + count = n; + while (count >= 0) { + count--; + if (*p == '\0') + break; + p++; + } + + p--; + while (*p == '0') { + p--; + } + + if (*p != decimal_point[0]) { + p++; + } + wmem_strbuf_truncate(strbuf, p - s); + } +} + +/* Given a floating point value, return it in a human-readable format, + * using units with metric prefixes (falling back to scientific notation + * with the base units if outside the range.) + */ +char * +format_units(wmem_allocator_t *allocator, double size, + format_size_units_e unit, uint16_t flags, + int precision) +{ + wmem_strbuf_t *human_str = wmem_strbuf_new(allocator, NULL); + double power = 1000.0; + int pfx_off = 6; + bool is_small = false; + /* is_small is when to use the longer, spelled out unit. + * We use it for inf, NaN, 0, and unprefixed small values, + * but not for unprefixed values using scientific notation + * the value is outside the supported prefix range. + */ + bool scientific = false; + double abs_size = fabs(size); + int exponent = 0; + static const char * const si_prefix[] = {" a", " f", " p", " n", " μ", " m", " ", " k", " M", " G", " T", " P", " E"}; + static const char * const iec_prefix[] = {" ", " Ki", " Mi", " Gi", " Ti", " Pi", " Ei"}; + const char * const *prefix = si_prefix; + int max_exp = (int)G_N_ELEMENTS(si_prefix) - 1; + + char *ret_val; + + if (thousands_grouping_fmt == NULL) + test_printf_thousands_grouping(); + + if (flags & FORMAT_SIZE_PREFIX_IEC) { + prefix = iec_prefix; + max_exp = (int)G_N_ELEMENTS(iec_prefix) - 1; + power = 1024.0; + } + + if (isfinite(size) && size != 0.0) { + + double comp = precision == 0 ? 10.0 : 1.0; + + /* For precision 0, use the range [10, 10*power) because only + * one significant digit is not as useful. This is what format_size + * does for integers. ("ls -h" uses one digit after the decimal + * point only for the [1, 10) range, g_format_size() always displays + * tenths.) Prefer non-prefixed units for the range [1,10), though. + * + * We have a limited number of units to check, so this (which + * can be unrolled) is presumably faster than log + floor + pow/exp + */ + if (abs_size < 1.0) { + while (abs_size < comp) { + abs_size *= power; + exponent--; + if ((exponent + pfx_off) < 0) { + scientific = true; + break; + } + } + } else { + while (abs_size >= comp*power) { + abs_size *= 1/power; + exponent++; + if ((exponent + pfx_off) > max_exp) { + scientific = true; + break; + } + } + } + } + + if (scientific) { + wmem_strbuf_append_printf(human_str, "%.*g", precision + 1, size); + exponent = 0; + } else { + if (exponent == 0) { + is_small = true; + } + size = copysign(abs_size, size); + // Truncate trailing zeros, but do it this way because we know + // we don't want scientific notation, and we don't want %g to + // switch to that if precision is small. (We could always use + // %g when precision is large.) + wmem_strbuf_append_printf(human_str, thousands_grouping_fmt_flt, precision, size); + truncate_numeric_strbuf(human_str, precision); + // XXX - when rounding to a certain precision, printf might + // round up to "power" from something like 999.99999995, which + // looks a little odd on a graph when transitioning from 1,000 bytes + // (for values just under 1 kB) to 1 kB (for values 1 kB and larger.) + // Due to edge cases in binary fp representation and how printf might + // round things, the right way to handle it is taking the printf output + // and comparing it to "1000" and "1024" and adjusting the exponent + // if so - though we need to compare to the version with the thousands + // separator if we have that (which makes it harder to use strnatcmp + // as is.) + } + + if ((size_t)(pfx_off + exponent) < G_N_ELEMENTS(si_prefix)) { + wmem_strbuf_append(human_str, prefix[pfx_off+exponent]); + } + + switch (unit) { + case FORMAT_SIZE_UNIT_NONE: + break; + case FORMAT_SIZE_UNIT_BYTES: + wmem_strbuf_append(human_str, is_small ? "bytes" : "B"); + break; + case FORMAT_SIZE_UNIT_BITS: + wmem_strbuf_append(human_str, is_small ? "bits" : "b"); + break; + case FORMAT_SIZE_UNIT_BITS_S: + wmem_strbuf_append(human_str, is_small ? "bits/s" : "bps"); + break; + case FORMAT_SIZE_UNIT_BYTES_S: + wmem_strbuf_append(human_str, is_small ? "bytes/s" : "Bps"); + break; + case FORMAT_SIZE_UNIT_PACKETS: + wmem_strbuf_append(human_str, is_small ? "packets" : "packets"); + break; + case FORMAT_SIZE_UNIT_PACKETS_S: + wmem_strbuf_append(human_str, is_small ? "packets/s" : "packets/s"); + break; + case FORMAT_SIZE_UNIT_EVENTS: + wmem_strbuf_append(human_str, is_small ? "events" : "events"); + break; + case FORMAT_SIZE_UNIT_EVENTS_S: + wmem_strbuf_append(human_str, is_small ? "events/s" : "events/s"); + break; + case FORMAT_SIZE_UNIT_FIELDS: + wmem_strbuf_append(human_str, is_small ? "fields" : "fields"); + break; + case FORMAT_SIZE_UNIT_SECONDS: + wmem_strbuf_append(human_str, is_small ? "seconds" : "s"); + break; + case FORMAT_SIZE_UNIT_ERLANGS: + wmem_strbuf_append(human_str, is_small ? "erlangs" : "E"); + break; + default: + ws_assert_not_reached(); + } + + ret_val = wmem_strbuf_finalize(human_str); + /* Convention is a space between the value and the units. If we have + * a prefix, the space is before the prefix. There are two possible + * uses of FORMAT_SIZE_UNIT_NONE: + * 1. Add a unit immediately after the string returned. In this case, + * we would want the string to end with a space if there's no prefix. + * 2. The unit appears somewhere else, e.g. in a legend, header, or + * different column. In this case, we don't want the string to end + * with a space if there's no prefix. + * chomping the string here, as we've traditionally done, optimizes for + * the latter case but makes the former case harder. + * Perhaps the right approach is to distinguish the cases with a new + * enum value. + */ + return g_strchomp(ret_val); +} + /* Given a size, return its value in a human-readable format */ -/* This doesn't handle fractional values. We might want to make size a double. */ +/* This doesn't handle fractional values. We might want to just + * call the version with the double and precision 0 (possibly + * slower due to the use of floating point math, but do we care?) + */ char * format_size_wmem(wmem_allocator_t *allocator, int64_t size, format_size_units_e unit, uint16_t flags) @@ -418,6 +648,18 @@ format_size_wmem(wmem_allocator_t *allocator, int64_t size, case FORMAT_SIZE_UNIT_PACKETS_S: wmem_strbuf_append(human_str, is_small ? " packets/s" : "packets/s"); break; + case FORMAT_SIZE_UNIT_FIELDS: + wmem_strbuf_append(human_str, is_small ? " fields" : "fields"); + break; + /* These aren't that practical to use with integers, but + * perhaps better than asserting. + */ + case FORMAT_SIZE_UNIT_SECONDS: + wmem_strbuf_append(human_str, is_small ? " seconds" : "s"); + break; + case FORMAT_SIZE_UNIT_ERLANGS: + wmem_strbuf_append(human_str, is_small ? " erlangs" : "E"); + break; default: ws_assert_not_reached(); } @@ -443,8 +685,9 @@ escape_char(char c, char *p) ws_assert(p); /* - * Backslashes and double-quotes must - * be escaped. Whitespace is also escaped. + * backslashes and double-quotes must be escaped (double-quotes + * are escaped by passing '"' as quote_char in escape_string_len) + * whitespace is also escaped. */ switch (c) { case '\a': r = 'a'; break; @@ -454,7 +697,6 @@ escape_char(char c, char *p) case '\r': r = 'r'; break; case '\t': r = 't'; break; case '\v': r = 'v'; break; - case '"': r = '"'; break; case '\\': r = '\\'; break; case '\0': r = '0'; break; } @@ -479,7 +721,8 @@ escape_null(char c, char *p) static char * escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t len, - bool (*escape_func)(char c, char *p), bool add_quotes) + bool (*escape_func)(char c, char *p), bool add_quotes, + char quote_char, bool double_quote) { char c, r; wmem_strbuf_t *buf; @@ -495,8 +738,8 @@ escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t len, buf = wmem_strbuf_new_sized(alloc, alloc_size); - if (add_quotes) - wmem_strbuf_append_c(buf, '"'); + if (add_quotes && quote_char != '\0') + wmem_strbuf_append_c(buf, quote_char); for (i = 0; i < len; i++) { c = string[i]; @@ -504,14 +747,30 @@ escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t len, wmem_strbuf_append_c(buf, '\\'); wmem_strbuf_append_c(buf, r); } + else if (c == quote_char && quote_char != '\0') { + /* If quoting, we must escape the quote_char somehow. */ + if (double_quote) { + wmem_strbuf_append_c(buf, c); + wmem_strbuf_append_c(buf, c); + } else { + wmem_strbuf_append_c(buf, '\\'); + wmem_strbuf_append_c(buf, c); + } + } + else if (c == '\\' && quote_char != '\0' && !double_quote) { + /* If quoting, and escaping the quote_char with a backslash, + * then backslash must be escaped, even if escape_func doesn't. */ + wmem_strbuf_append_c(buf, '\\'); + wmem_strbuf_append_c(buf, '\\'); + } else { /* Other UTF-8 bytes are passed through. */ wmem_strbuf_append_c(buf, c); } } - if (add_quotes) - wmem_strbuf_append_c(buf, '"'); + if (add_quotes && quote_char != '\0') + wmem_strbuf_append_c(buf, quote_char); return wmem_strbuf_finalize(buf); } @@ -519,18 +778,29 @@ escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t len, char * ws_escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t len, bool add_quotes) { - return escape_string_len(alloc, string, len, escape_char, add_quotes); + return escape_string_len(alloc, string, len, escape_char, add_quotes, '"', false); } char * ws_escape_string(wmem_allocator_t *alloc, const char *string, bool add_quotes) { - return escape_string_len(alloc, string, -1, escape_char, add_quotes); + return escape_string_len(alloc, string, -1, escape_char, add_quotes, '"', false); } char *ws_escape_null(wmem_allocator_t *alloc, const char *string, size_t len, bool add_quotes) { - return escape_string_len(alloc, string, len, escape_null, add_quotes); + /* XXX: The existing behavior (maintained) here is not to escape + * backslashes even though NUL is escaped. + */ + return escape_string_len(alloc, string, len, escape_null, add_quotes, add_quotes ? '"' : '\0', false); +} + +char *ws_escape_csv(wmem_allocator_t *alloc, const char *string, bool add_quotes, char quote_char, bool double_quote, bool escape_whitespace) +{ + if (escape_whitespace) + return escape_string_len(alloc, string, -1, escape_char, add_quotes, quote_char, double_quote); + else + return escape_string_len(alloc, string, -1, escape_null, add_quotes, quote_char, double_quote); } const char * diff --git a/wsutil/str_util.h b/wsutil/str_util.h index 7f1362f4..6cbcc6b3 100644 --- a/wsutil/str_util.h +++ b/wsutil/str_util.h @@ -182,6 +182,17 @@ bool isdigit_string(const unsigned char *str); WS_DLL_PUBLIC const char *ws_ascii_strcasestr(const char *haystack, const char *needle); +/** Like the memchr() function, except it scans backwards from the end. + * + * @param haystack Pointer to the bytes of memory to search + * @param ch The character to search + * @param n The length of bytes to search from the end + * @return A pointer to the last occurrence of "ch" in "haystack". + * If "ch" isn't found or "n" is 0, returns NULL. + */ +WS_DLL_PUBLIC +const uint8_t *ws_memrchr(const void *haystack, int ch, size_t n); + WS_DLL_PUBLIC char *ws_escape_string(wmem_allocator_t *alloc, const char *string, bool add_quotes); @@ -192,22 +203,75 @@ char *ws_escape_string_len(wmem_allocator_t *alloc, const char *string, ssize_t WS_DLL_PUBLIC char *ws_escape_null(wmem_allocator_t *alloc, const char *string, size_t len, bool add_quotes); +/* Escape as in a number of CSV dialects. + * + * @param allocator The wmem scope to use to allocate the returned string + * @param string The input string to escape + * @param add_quotes Whether to surround the string with quote_char + * @param quote_char The quote character, always escaped in some way. + * @param double_quote Whether to escape the quote character by doubling it + * @param escape_whitespace Whether to escape whitespace with a backslash + * @return The escaped string + * + * @note If double_quote is false, then quote_or_delim is escaped with a + * backslash ('\'). The quote character can be '\0', in which case it is + * ignored. If any character is being escaped with a backslash (i.e., + * quote_char is not '\0' and double_quote is false, or escape_whitespace + * is true), then backslash is also escaped. If add_quotes is false, then + * quote_char can either be a quote character (if the string will be quoted + * later after further manipulation) or the delimiter (to escape it, since + * the string is not being quoted.). + */ +WS_DLL_PUBLIC +char *ws_escape_csv(wmem_allocator_t *alloc, const char *string, bool add_quotes, char quote_char, bool double_quote, bool escape_whitespace); + WS_DLL_PUBLIC int ws_xton(char ch); typedef enum { FORMAT_SIZE_UNIT_NONE, /**< No unit will be appended. You must supply your own. */ + /* XXX - This does not append a trailing space if there is no prefix. + * That's good if you intend to list the unit somewhere else, e.g. in a + * legend, header, or other column, but doesn't work well if intending + * to append your own unit. You can test whether there's a prefix or + * not with g_ascii_isdigit() (plus special handling for inf and NaN). + */ FORMAT_SIZE_UNIT_BYTES, /**< "bytes" for un-prefixed sizes, "B" otherwise. */ FORMAT_SIZE_UNIT_BITS, /**< "bits" for un-prefixed sizes, "b" otherwise. */ FORMAT_SIZE_UNIT_BITS_S, /**< "bits/s" for un-prefixed sizes, "bps" otherwise. */ FORMAT_SIZE_UNIT_BYTES_S, /**< "bytes/s" for un-prefixed sizes, "Bps" otherwise. */ FORMAT_SIZE_UNIT_PACKETS, /**< "packets" */ FORMAT_SIZE_UNIT_PACKETS_S, /**< "packets/s" */ + FORMAT_SIZE_UNIT_EVENTS, /**< "events" */ + FORMAT_SIZE_UNIT_EVENTS_S, /**< "events/s" */ + FORMAT_SIZE_UNIT_FIELDS, /**< "fields" */ + /* These next two aren't really for format_size (which takes an int) */ + FORMAT_SIZE_UNIT_SECONDS, /**< "seconds" for un-prefixed sizes, "s" otherwise. */ + FORMAT_SIZE_UNIT_ERLANGS, /**< "erlangs" for un-prefixed sizes, "E" otherwise. */ } format_size_units_e; #define FORMAT_SIZE_PREFIX_SI (1 << 0) /**< SI (power of 1000) prefixes will be used. */ #define FORMAT_SIZE_PREFIX_IEC (1 << 1) /**< IEC (power of 1024) prefixes will be used. */ +/** Given a floating point value, return it in a human-readable format + * + * Prefixes up to "E/Ei" (exa, exbi) and down to "a" (atto; negative + * prefixes are SI-only) are currently supported. Values outside that + * range will use scientific notation. + * + * @param size The size value + * @param flags Flags to control the output (unit of measurement, + * SI vs IEC, etc). Unit and prefix flags may be ORed together. + * @param precision Maximum number of digits to appear after the + * decimal point. Trailing zeros are removed, as is the decimal + * point if not digits follow it. + * @return A newly-allocated string representing the value. + */ +WS_DLL_PUBLIC +char *format_units(wmem_allocator_t *allocator, double size, + format_size_units_e unit, uint16_t flags, + int precision); + /** Given a size, return its value in a human-readable format * * Prefixes up to "T/Ti" (tera, tebi) are currently supported. diff --git a/wsutil/test_wsutil.c b/wsutil/test_wsutil.c index ff9e2f82..755f0853 100644 --- a/wsutil/test_wsutil.c +++ b/wsutil/test_wsutil.c @@ -12,6 +12,7 @@ #include <glib.h> #include <wsutil/utf8_entities.h> #include <wsutil/time_util.h> +#include <wsutil/to_str.h> #include "inet_addr.h" @@ -46,7 +47,7 @@ struct in6_test { ws_in6_addr addr; }; -static struct in6_test in6_test1 = { +static const struct in6_test in6_test1 = { .str = "2001:db8:ffaa:ddbb:1199:2288:3377:1", .addr = { { 0x20, 0x01, 0x0d, 0xb8, 0xff, 0xaa, 0xdd, 0xbb, 0x11, 0x99, 0x22, 0x88, 0x33, 0x77, 0x00, 0x01 } } @@ -72,6 +73,19 @@ static void test_inet_ntop6_test1(void) g_assert_cmpstr(result, ==, in6_test1.str); } +static void test_ip_addr_to_str_test1(void) +{ + char result[WS_INET_ADDRSTRLEN]; + const char *expect; + ws_in4_addr addr; + + addr = g_htonl(3325256904); + expect = "198.51.100.200"; + ip_addr_to_str_buf(&addr, result, sizeof(result)); + + g_assert_cmpstr(result, ==, expect); +} + #include "str_util.h" static void test_format_size(void) @@ -107,6 +121,15 @@ static void test_escape_string(void) buf = ws_escape_null(NULL, s1, sizeof(s1), true); g_assert_cmpstr(buf, ==, "\"abc\\0efg\""); wmem_free(NULL, buf); + + const char s2[] = { 'a', 'b', 'c', '\0', '"', 'e', 'f', 'g'}; + buf = ws_escape_null(NULL, s2, sizeof(s2), true); + g_assert_cmpstr(buf, ==, "\"abc\\0\\\"efg\""); + wmem_free(NULL, buf); + + buf = ws_escape_csv(NULL, "CSV-style \" escape", true, '"', true, false); + g_assert_cmpstr(buf, ==, "\"CSV-style \"\" escape\""); + wmem_free(NULL, buf); } static void test_strconcat(void) @@ -261,7 +284,7 @@ static void test_word_to_hex(void) static char buf[32]; char *str; /* String is not NULL terminated. */ - str = guint8_to_hex(buf, 0x34); + str = uint8_to_hex(buf, 0x34); g_assert_true(str == buf + 2); g_assert_cmpint(str[-1], ==, '4'); g_assert_cmpint(str[-2], ==, '3'); @@ -284,7 +307,7 @@ static void test_word_to_hex(void) g_assert_cmpint(str[-7], ==, '0'); g_assert_cmpint(str[-8], ==, '0'); - str = qword_to_hex(buf, G_GUINT64_CONSTANT(0xFEDCBA987654321)); + str = qword_to_hex(buf, UINT64_C(0xFEDCBA987654321)); g_assert_true(str == buf + 16); g_assert_cmpint(str[-1], ==, '1'); g_assert_cmpint(str[-2], ==, '2'); @@ -448,13 +471,13 @@ static void test_oct64_to_str_back(void) { char *str; - str = oct64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(13873797580070999420)); + str = oct64_to_str_back(BACK_PTR, UINT64_C(13873797580070999420)); g_assert_cmpstr(str, ==, "01402115026217563452574"); - str = oct64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(7072159458371400691)); + str = oct64_to_str_back(BACK_PTR, UINT64_C(7072159458371400691)); g_assert_cmpstr(str, ==, "0610452670726711271763"); - str = oct64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(12453513102400590374)); + str = oct64_to_str_back(BACK_PTR, UINT64_C(12453513102400590374)); g_assert_cmpstr(str, ==, "01263236102754220511046"); } @@ -476,13 +499,13 @@ static void test_hex64_to_str_back_len(void) { char *str; - str = hex64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(1), 16); + str = hex64_to_str_back_len(BACK_PTR, UINT64_C(1), 16); g_assert_cmpstr(str, ==, "0x0000000000000001"); - str = hex64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(4294967295), 16); + str = hex64_to_str_back_len(BACK_PTR, UINT64_C(4294967295), 16); g_assert_cmpstr(str, ==, "0x00000000ffffffff"); - str = hex64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(18446744073709551615), 16); + str = hex64_to_str_back_len(BACK_PTR, UINT64_C(18446744073709551615), 16); g_assert_cmpstr(str, ==, "0xffffffffffffffff"); } @@ -504,13 +527,13 @@ static void test_uint64_to_str_back(void) { char *str; - str = uint64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(585143757104211265)); + str = uint64_to_str_back(BACK_PTR, UINT64_C(585143757104211265)); g_assert_cmpstr(str, ==, "585143757104211265"); - str = uint64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(7191580247919484847)); + str = uint64_to_str_back(BACK_PTR, UINT64_C(7191580247919484847)); g_assert_cmpstr(str, ==, "7191580247919484847"); - str = uint64_to_str_back(BACK_PTR, G_GUINT64_CONSTANT(95778573911934485)); + str = uint64_to_str_back(BACK_PTR, UINT64_C(95778573911934485)); g_assert_cmpstr(str, ==, "95778573911934485"); } @@ -532,13 +555,13 @@ static void test_uint64_to_str_back_len(void) { char *str; - str = uint64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(1), 16); + str = uint64_to_str_back_len(BACK_PTR, UINT64_C(1), 16); g_assert_cmpstr(str, ==, "0000000000000001"); - str = uint64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(4294967295), 16); + str = uint64_to_str_back_len(BACK_PTR, UINT64_C(4294967295), 16); g_assert_cmpstr(str, ==, "0000004294967295"); - str = uint64_to_str_back_len(BACK_PTR, G_GUINT64_CONSTANT(18446744073709551615), 16); + str = uint64_to_str_back_len(BACK_PTR, UINT64_C(18446744073709551615), 16); g_assert_cmpstr(str, ==, "18446744073709551615"); } @@ -560,13 +583,13 @@ static void test_int64_to_str_back(void) { char *str; - str = int64_to_str_back(BACK_PTR, G_GINT64_CONSTANT(-9223372036854775807)); + str = int64_to_str_back(BACK_PTR, INT64_C(-9223372036854775807)); g_assert_cmpstr(str, ==, "-9223372036854775807"); - str = int64_to_str_back(BACK_PTR, G_GINT64_CONSTANT(1)); + str = int64_to_str_back(BACK_PTR, INT64_C(1)); g_assert_cmpstr(str, ==, "1"); - str = int64_to_str_back(BACK_PTR, G_GINT64_CONSTANT(9223372036854775807)); + str = int64_to_str_back(BACK_PTR, INT64_C(9223372036854775807)); g_assert_cmpstr(str, ==, "9223372036854775807"); } @@ -854,6 +877,7 @@ int main(int argc, char **argv) g_test_add_func("/to_str/uint64_to_str_back_len", test_uint64_to_str_back_len); g_test_add_func("/to_str/int_to_str_back", test_int_to_str_back); g_test_add_func("/to_str/int64_to_str_back", test_int64_to_str_back); + g_test_add_func("/to_str/ip_addr_to_str_test1", test_ip_addr_to_str_test1); g_test_add_func("/nstime/from_iso8601", test_nstime_from_iso8601); diff --git a/wsutil/time_util.c b/wsutil/time_util.c index 6d967953..1fda2c57 100644 --- a/wsutil/time_util.c +++ b/wsutil/time_util.c @@ -199,7 +199,7 @@ void log_resource_usage(bool reset_delta, const char *format, ...) { va_end(ap); ws_warning("%s", log_str->str); - g_string_free(log_str, true); + g_string_free(log_str, TRUE); } diff --git a/wsutil/to_str.c b/wsutil/to_str.c index d3e41538..58dda056 100644 --- a/wsutil/to_str.c +++ b/wsutil/to_str.c @@ -95,7 +95,7 @@ byte_to_hex(char *out, uint32_t dword) } char * -guint8_to_hex(char *out, uint8_t val) +uint8_to_hex(char *out, uint8_t val) { return byte_to_hex(out, val); } @@ -418,7 +418,7 @@ uint_to_str_back_len(char *ptr, uint32_t value, int len) new_ptr = uint_to_str_back(ptr, value); - /* substract from len number of generated characters */ + /* subtract from len number of generated characters */ len -= (int)(ptr - new_ptr); /* pad remaining with '0' */ @@ -438,7 +438,7 @@ uint64_to_str_back_len(char *ptr, uint64_t value, int len) new_ptr = uint64_to_str_back(ptr, value); - /* substract from len number of generated characters */ + /* subtract from len number of generated characters */ len -= (int)(ptr - new_ptr); /* pad remaining with '0' */ @@ -476,7 +476,7 @@ int64_to_str_back(char *ptr, int64_t value) } static size_t -guint32_to_str_buf_len(const uint32_t u) +uint32_to_str_buf_len(const uint32_t u) { /* ((2^32)-1) == 2147483647 */ if (u >= 1000000000)return 10; @@ -493,9 +493,9 @@ guint32_to_str_buf_len(const uint32_t u) } void -guint32_to_str_buf(uint32_t u, char *buf, size_t buf_len) +uint32_to_str_buf(uint32_t u, char *buf, size_t buf_len) { - size_t str_len = guint32_to_str_buf_len(u)+1; + size_t str_len = uint32_to_str_buf_len(u)+1; char *bp = &buf[str_len]; @@ -507,37 +507,37 @@ guint32_to_str_buf(uint32_t u, char *buf, size_t buf_len) } static size_t -guint64_to_str_buf_len(const uint64_t u) +uint64_to_str_buf_len(const uint64_t u) { /* ((2^64)-1) == 18446744073709551615 */ - if (u >= G_GUINT64_CONSTANT(10000000000000000000)) return 20; - if (u >= G_GUINT64_CONSTANT(1000000000000000000)) return 19; - if (u >= G_GUINT64_CONSTANT(100000000000000000)) return 18; - if (u >= G_GUINT64_CONSTANT(10000000000000000)) return 17; - if (u >= G_GUINT64_CONSTANT(1000000000000000)) return 16; - if (u >= G_GUINT64_CONSTANT(100000000000000)) return 15; - if (u >= G_GUINT64_CONSTANT(10000000000000)) return 14; - if (u >= G_GUINT64_CONSTANT(1000000000000)) return 13; - if (u >= G_GUINT64_CONSTANT(100000000000)) return 12; - if (u >= G_GUINT64_CONSTANT(10000000000)) return 11; - if (u >= G_GUINT64_CONSTANT(1000000000)) return 10; - if (u >= G_GUINT64_CONSTANT(100000000)) return 9; - if (u >= G_GUINT64_CONSTANT(10000000)) return 8; - if (u >= G_GUINT64_CONSTANT(1000000)) return 7; - if (u >= G_GUINT64_CONSTANT(100000)) return 6; - if (u >= G_GUINT64_CONSTANT(10000)) return 5; - if (u >= G_GUINT64_CONSTANT(1000)) return 4; - if (u >= G_GUINT64_CONSTANT(100)) return 3; - if (u >= G_GUINT64_CONSTANT(10)) return 2; + if (u >= UINT64_C(10000000000000000000)) return 20; + if (u >= UINT64_C(1000000000000000000)) return 19; + if (u >= UINT64_C(100000000000000000)) return 18; + if (u >= UINT64_C(10000000000000000)) return 17; + if (u >= UINT64_C(1000000000000000)) return 16; + if (u >= UINT64_C(100000000000000)) return 15; + if (u >= UINT64_C(10000000000000)) return 14; + if (u >= UINT64_C(1000000000000)) return 13; + if (u >= UINT64_C(100000000000)) return 12; + if (u >= UINT64_C(10000000000)) return 11; + if (u >= UINT64_C(1000000000)) return 10; + if (u >= UINT64_C(100000000)) return 9; + if (u >= UINT64_C(10000000)) return 8; + if (u >= UINT64_C(1000000)) return 7; + if (u >= UINT64_C(100000)) return 6; + if (u >= UINT64_C(10000)) return 5; + if (u >= UINT64_C(1000)) return 4; + if (u >= UINT64_C(100)) return 3; + if (u >= UINT64_C(10)) return 2; return 1; } void -guint64_to_str_buf(uint64_t u, char *buf, size_t buf_len) +uint64_to_str_buf(uint64_t u, char *buf, size_t buf_len) { - size_t str_len = guint64_to_str_buf_len(u)+1; + size_t str_len = uint64_to_str_buf_len(u)+1; char *bp = &buf[str_len]; @@ -553,8 +553,9 @@ guint64_to_str_buf(uint64_t u, char *buf, size_t buf_len) XXX update the address_to_str stuff to use this function. */ void -ip_to_str_buf(const uint8_t *ad, char *buf, const int buf_len) +ip_addr_to_str_buf(const ws_in4_addr *_ad, char *buf, const int buf_len) { + uint8_t *ad = (uint8_t *)_ad; register char const *p; register char *b=buf; @@ -589,16 +590,44 @@ ip_to_str_buf(const uint8_t *ad, char *buf, const int buf_len) *b=0; } -char *ip_to_str(wmem_allocator_t *scope, const uint8_t *ad) +char * +ip_addr_to_str(wmem_allocator_t *scope, const ws_in4_addr *ad) { char *buf = wmem_alloc(scope, WS_INET_ADDRSTRLEN * sizeof(char)); - ip_to_str_buf(ad, buf, WS_INET_ADDRSTRLEN); + ip_addr_to_str_buf(ad, buf, WS_INET_ADDRSTRLEN); return buf; } void +ip_num_to_str_buf(uint32_t ad, char *buf, const int buf_len) +{ + ws_in4_addr addr = g_htonl(ad); + ip_addr_to_str_buf(&addr, buf, buf_len); +} + +/* Host byte order */ +char * +ip_num_to_str(wmem_allocator_t *scope, uint32_t ad) +{ + ws_in4_addr addr = g_htonl(ad); + return ip_addr_to_str(scope, &addr); +} + +void +ip_to_str_buf(const uint8_t *ad, char *buf, const int buf_len) +{ + ip_addr_to_str_buf((const ws_in4_addr *)ad, buf, buf_len); +} + +char * +ip_to_str(wmem_allocator_t *scope, const uint8_t *ad) +{ + return ip_addr_to_str(scope, (const ws_in4_addr *)ad); +} + +void ip6_to_str_buf(const ws_in6_addr *addr, char *buf, size_t buf_size) { /* diff --git a/wsutil/to_str.h b/wsutil/to_str.h index 08bd536b..565d34b3 100644 --- a/wsutil/to_str.h +++ b/wsutil/to_str.h @@ -15,7 +15,7 @@ #include <wireshark.h> #include <wsutil/wmem/wmem.h> -#include <wsutil/inet_ipv6.h> +#include <wsutil/inet_addr.h> #include <wsutil/nstime.h> #ifdef __cplusplus @@ -23,7 +23,7 @@ extern "C" { #endif /* __cplusplus */ /** - * guint8_to_hex() + * uint8_to_hex() * * Output uint8_t hex representation to 'out', and return pointer after last character (out + 2). * It will always output full representation (padded with 0). @@ -31,7 +31,10 @@ extern "C" { * String is not NUL terminated by this routine. * There needs to be at least 2 bytes in the buffer. */ -WS_DLL_PUBLIC char *guint8_to_hex(char *out, uint8_t val); +WS_DLL_PUBLIC char *uint8_to_hex(char *out, uint8_t val); + +WS_DEPRECATED_X("Use uint8_to_hex instead") +static inline char *guint8_to_hex(char *out, uint8_t val) { return uint8_to_hex(out, val); } /** * word_to_hex() @@ -282,15 +285,32 @@ WS_DLL_PUBLIC char *int_to_str_back(char *ptr, int32_t value); */ WS_DLL_PUBLIC char *int64_to_str_back(char *ptr, int64_t value); -WS_DLL_PUBLIC void guint32_to_str_buf(uint32_t u, char *buf, size_t buf_len); +WS_DLL_PUBLIC void uint32_to_str_buf(uint32_t u, char *buf, size_t buf_len); + +WS_DEPRECATED_X("Use uint32_to_str_buf instead") +static inline void guint32_to_str_buf(uint32_t u, char *buf, size_t buf_len) { uint32_to_str_buf(u, buf, buf_len); } -WS_DLL_PUBLIC void guint64_to_str_buf(uint64_t u, char *buf, size_t buf_len); +WS_DLL_PUBLIC void uint64_to_str_buf(uint64_t u, char *buf, size_t buf_len); +WS_DEPRECATED_X("Use uint64_to_str_buf instead") +static inline void guint64_to_str_buf(uint64_t u, char *buf, size_t buf_len) { uint64_to_str_buf(u, buf, buf_len); } + +WS_DEPRECATED_X("Use ip_num_to_str_buf() or ip_addr_to_str() instead") WS_DLL_PUBLIC void ip_to_str_buf(const uint8_t *ad, char *buf, const int buf_len); +WS_DEPRECATED_X("Use ip_num_to_str() or ip_addr_to_str() instead") WS_DLL_PUBLIC char *ip_to_str(wmem_allocator_t *scope, const uint8_t *ad); -/* Returns length of the result. */ +/* Host byte order */ +WS_DLL_PUBLIC void ip_num_to_str_buf(uint32_t ad, char *buf, const int buf_len); + +/* Host byte order */ +WS_DLL_PUBLIC char *ip_num_to_str(wmem_allocator_t *scope, uint32_t ad); + +WS_DLL_PUBLIC void ip_addr_to_str_buf(const ws_in4_addr *ad, char *buf, const int buf_len); + +WS_DLL_PUBLIC char *ip_addr_to_str(wmem_allocator_t *scope, const ws_in4_addr *ad); + WS_DLL_PUBLIC void ip6_to_str_buf(const ws_in6_addr *ad, char *buf, size_t buf_size); WS_DLL_PUBLIC char *ip6_to_str(wmem_allocator_t *scope, const ws_in6_addr *ad); diff --git a/wsutil/type_util.c b/wsutil/type_util.c index f98a1b1d..cfe9fe70 100644 --- a/wsutil/type_util.c +++ b/wsutil/type_util.c @@ -36,16 +36,16 @@ */ double -type_util_guint64_to_gdouble(uint64_t value) +type_util_uint64_to_double(uint64_t value) { - if (value & G_GUINT64_CONSTANT (0x8000000000000000)) + if (value & UINT64_C (0x8000000000000000)) return (double) ((int64_t) value) + (double) 18446744073709551616.; else return (double) ((int64_t) value); } uint64_t -type_util_gdouble_to_guint64(double value) +type_util_double_to_uint64(double value) { if (value < (double) 9223372036854775808.) /* 1 << 63 */ return ((uint64_t) ((int64_t) value)); diff --git a/wsutil/type_util.h b/wsutil/type_util.h index eab9ff9b..cc8199f5 100644 --- a/wsutil/type_util.h +++ b/wsutil/type_util.h @@ -29,16 +29,16 @@ */ WS_DLL_PUBLIC -uint64_t type_util_gdouble_to_guint64(double value); +uint64_t type_util_double_to_uint64(double value); WS_DLL_PUBLIC -double type_util_guint64_to_gdouble(uint64_t value); +double type_util_uint64_to_double(uint64_t value); #ifdef _WIN32 -#define gdouble_to_guint64(value) type_util_gdouble_to_guint64(value) -#define guint64_to_gdouble(value) type_util_guint64_to_gdouble(value) +#define double_to_uint64(value) type_util_double_to_uint64(value) +#define uint64_to_double(value) type_util_uint64_to_double(value) #else -#define gdouble_to_guint64(value) ((uint64_t)(value)) -#define guint64_to_gdouble(value) ((double)(value)) +#define double_to_uint64(value) ((uint64_t)(value)) +#define uint64_to_double(value) ((double)(value)) #endif #endif /* __TYPE_UTIL_H__ */ diff --git a/wsutil/unicode-utils.c b/wsutil/unicode-utils.c index 4ed4b326..2e50393a 100644 --- a/wsutil/unicode-utils.c +++ b/wsutil/unicode-utils.c @@ -12,7 +12,7 @@ #include "unicode-utils.h" -int ws_utf8_seqlen[256] = { +const int ws_utf8_seqlen[256] = { 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x00...0x0f */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x10...0x1f */ 1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, /* 0x20...0x2f */ diff --git a/wsutil/unicode-utils.h b/wsutil/unicode-utils.h index 21c50ec0..d8a9a9bf 100644 --- a/wsutil/unicode-utils.h +++ b/wsutil/unicode-utils.h @@ -50,7 +50,7 @@ extern "C" { _CHECK_UTF_8(LOG_LEVEL_ECHO, str, len) WSUTIL_EXPORT -int ws_utf8_seqlen[256]; +const int ws_utf8_seqlen[256]; /** Given the first byte in an UTF-8 encoded code point, * return the length of the multibyte sequence, or *ZERO* diff --git a/wsutil/utf8_entities.h b/wsutil/utf8_entities.h index 3d2f2533..e7ad8cbc 100644 --- a/wsutil/utf8_entities.h +++ b/wsutil/utf8_entities.h @@ -47,6 +47,8 @@ #define UTF8_RIGHTWARDS_ARROW "\xe2\x86\x92" /* 8594 / 0x2192 */ #define UTF8_LEFT_RIGHT_ARROW "\xe2\x86\x94" /* 8596 / 0x2194 */ +#define UTF8_SQUARE_ROOT "\xe2\x88\x9a" /* 8730 / 0x221a */ + /* macOS command key */ #define UTF8_PLACE_OF_INTEREST_SIGN "\xe2\x8c\x98" /* 8984 / 0x2318 */ diff --git a/wsutil/version_info.c b/wsutil/version_info.c index ab450686..9fbee0d2 100644 --- a/wsutil/version_info.c +++ b/wsutil/version_info.c @@ -32,6 +32,10 @@ #include <zlib.h> #endif +//#ifdef HAVE_ZLIBNG +//#include <zlib-ng.h> +//#endif + #include "vcs_version.h" #include <wsutil/cpu_info.h> @@ -60,11 +64,11 @@ ws_init_version_info(const char *appname, copyright_info_str = g_string_new(get_copyright_info()); end_string(copyright_info_str); - copyright_info = g_string_free(copyright_info_str, false); + copyright_info = g_string_free(copyright_info_str, FALSE); license_info_str = g_string_new(get_license_info_short()); end_string(license_info_str); - license_info = g_string_free(license_info_str, false); + license_info = g_string_free(license_info_str, FALSE); /* * Combine the supplied application name string with the @@ -86,8 +90,8 @@ ws_init_version_info(const char *appname, /* Get the run-time version information string */ runtime_info_str = get_runtime_version_info(gather_runtime); - comp_info = g_string_free(comp_info_str, false); - runtime_info = g_string_free(runtime_info_str, false); + comp_info = g_string_free(comp_info_str, FALSE); + runtime_info = g_string_free(runtime_info_str, FALSE); /* Add this information to the information to be reported on a crash. */ ws_add_crash_info("%s\n" @@ -162,7 +166,7 @@ gather_zlib_compile_info(feature_list l) { #ifdef HAVE_ZLIB #ifdef ZLIB_VERSION - with_feature(l, "zlib "ZLIB_VERSION); + with_feature(l, "zlib " ZLIB_VERSION); #else with_feature(l, "zlib (version unknown)"); #endif /* ZLIB_VERSION */ @@ -171,6 +175,17 @@ gather_zlib_compile_info(feature_list l) #endif /* HAVE_ZLIB */ } +void +gather_zlib_ng_compile_info(feature_list l) +{ +#ifdef HAVE_ZLIBNG + with_feature(l, "zlib-ng " ZLIBNG_VERSION_STRING); +#else + without_feature(l, "zlib-ng"); +#endif /* HAVE_ZLIB */ +} + + /* * Get various library compile-time versions, put them in a GString, * and return the GString. @@ -513,18 +528,28 @@ get_runtime_version_info(gather_feature_func gather_runtime) const char * get_ws_vcs_version_info(void) { -#ifdef VCSVERSION - return VERSION " (" VCSVERSION ")"; +#ifdef VCS_VERSION + return VERSION " (" VCS_VERSION ")"; #else return VERSION; #endif } const char * +get_lr_vcs_version_info(void) +{ +#ifdef VCS_COMMIT_ID + return LOG_VERSION " (" VCS_NUM_COMMITS "-" VCS_COMMIT_ID ")"; +#else + return LOG_VERSION; +#endif +} + +const char * get_ws_vcs_version_info_short(void) { -#ifdef VCSVERSION - return VCSVERSION; +#ifdef VCS_VERSION + return VCS_VERSION; #else return VERSION; #endif diff --git a/wsutil/version_info.h b/wsutil/version_info.h index 1285cd2c..d7b8d228 100644 --- a/wsutil/version_info.h +++ b/wsutil/version_info.h @@ -60,6 +60,10 @@ WS_DLL_PUBLIC void gather_zlib_compile_info(feature_list l); +WS_DLL_PUBLIC +void +gather_zlib_ng_compile_info(feature_list l); + /* * Get various library compile-time versions, put them in a GString, * and return the GString. @@ -99,6 +103,14 @@ WS_DLL_PUBLIC const char *get_ws_vcs_version_info(void); /* + * Return a version number string for Logray, including, for builds + * from a tree checked out from Logray's version control system, + * something identifying what version was checked out. + */ +WS_DLL_PUBLIC +const char *get_lr_vcs_version_info(void); + +/* * Shorter version of get_ws_vcs_version_info(). */ WS_DLL_PUBLIC diff --git a/wsutil/win32-utils.c b/wsutil/win32-utils.c index b1cef5cd..60c7378c 100644 --- a/wsutil/win32-utils.c +++ b/wsutil/win32-utils.c @@ -9,6 +9,7 @@ */ #include <config.h> +#include <wsutil/array.h> #include "win32-utils.h" @@ -43,7 +44,7 @@ protect_arg (const char *argv) else if (*p == '\\') { const char *pp = p; - while (*pp && *pp == '\\') + while (*pp == '\\') pp++; if (*pp == '"') len++; @@ -52,7 +53,7 @@ protect_arg (const char *argv) p++; } - q = new_arg = g_malloc (len + need_dblquotes*2 + 1); + q = new_arg = g_malloc (len + (need_dblquotes ? 2 : 0) + 1); p = argv; if (need_dblquotes) @@ -64,7 +65,7 @@ protect_arg (const char *argv) else if (*p == '\\') { const char *pp = p; - while (*pp && *pp == '\\') + while (*pp == '\\') pp++; if (*pp == '"') *q++ = '\\'; @@ -80,6 +81,28 @@ protect_arg (const char *argv) return new_arg; } +#define PIPE_STR "\\pipe\\" + +bool +win32_is_pipe_name(const char *pipe_name) +{ + char *pncopy, *pos; + /* Under Windows, named pipes _must_ have the form + * "\\<server>\pipe\<pipename>". <server> may be "." for localhost. + * https://learn.microsoft.com/en-us/windows/win32/ipc/pipe-names + */ + pncopy = g_strdup(pipe_name); + if ((pos = strstr(pncopy, "\\\\")) == pncopy) { + pos = strchr(pncopy + 3, '\\'); + if (pos && g_ascii_strncasecmp(pos, PIPE_STR, strlen(PIPE_STR)) != 0) + pos = NULL; + } + + g_free(pncopy); + + return (pos != NULL); +} + /* * Generate a UTF-8 string for a Windows error. */ @@ -176,7 +199,7 @@ win32strexception(DWORD exception) { EXCEPTION_STACK_OVERFLOW, "Stack overflow" }, { 0, NULL } }; -#define N_EXCEPTIONS (sizeof exceptions / sizeof exceptions[0]) +#define N_EXCEPTIONS array_length(exceptions) for (size_t i = 0; i < N_EXCEPTIONS; i++) { if (exceptions[i].code == exception) diff --git a/wsutil/win32-utils.h b/wsutil/win32-utils.h index 44471c59..1fba0c0a 100644 --- a/wsutil/win32-utils.h +++ b/wsutil/win32-utils.h @@ -41,6 +41,17 @@ extern "C" { WS_DLL_PUBLIC char * protect_arg (const char *argv); +/** Tests a UTF-8 string to see if it is a Windows pipe name. + * Under Windows, named pipes _must_ have the form "\\<server>\pipe\<pipename>". + * <server> may be "." for localhost. This does not check that a pipe server + * has actually created the pipe, only that the name is the proper form. + * + * @param pipename The UTF-8 string to be checked + * @return TRUE if the string is a valid Windows pipe name. + */ +WS_DLL_PUBLIC +bool win32_is_pipe_name(const char* pipe_name); + /** Generate a string for a Windows error. * * @param error The Windows error code diff --git a/wsutil/wmem/wmem_allocator_block.c b/wsutil/wmem/wmem_allocator_block.c index b8a0f598..4723f0f3 100644 --- a/wsutil/wmem/wmem_allocator_block.c +++ b/wsutil/wmem/wmem_allocator_block.c @@ -18,7 +18,7 @@ #include "wmem_allocator.h" #include "wmem_allocator_block.h" -/* This has turned into a very interesting excercise in algorithms and data +/* This has turned into a very interesting exercise in algorithms and data * structures. * * HISTORY @@ -479,7 +479,7 @@ wmem_block_pop_master(wmem_block_allocator_t *allocator) /* CHUNK HELPERS */ /* Takes a free chunk and checks the chunks to its immediate right and left in - * the block. If they are also free, the contigous free chunks are merged into + * the block. If they are also free, the contiguous free chunks are merged into * a single free chunk. The resulting chunk ends up in either the master list or * the recycler, depending on where the merged chunks were originally. */ diff --git a/wsutil/wmem/wmem_core.c b/wsutil/wmem/wmem_core.c index a166bf84..6a589db1 100644 --- a/wsutil/wmem/wmem_core.c +++ b/wsutil/wmem/wmem_core.c @@ -25,7 +25,7 @@ /* Set according to the WIRESHARK_DEBUG_WMEM_OVERRIDE environment variable in * wmem_init. Should not be set again. */ -static bool do_override = false; +static bool do_override; static wmem_allocator_type_t override_type; void * diff --git a/wsutil/wmem/wmem_core.h b/wsutil/wmem/wmem_core.h index 2f423133..25784c19 100644 --- a/wsutil/wmem/wmem_core.h +++ b/wsutil/wmem/wmem_core.h @@ -73,7 +73,8 @@ typedef enum _wmem_allocator_type_t { WS_DLL_PUBLIC void * wmem_alloc(wmem_allocator_t *allocator, const size_t size) -G_GNUC_MALLOC; +G_GNUC_MALLOC +G_GNUC_ALLOC_SIZE(2); /** Allocate memory sufficient to hold one object of the given type. * @@ -112,7 +113,8 @@ G_GNUC_MALLOC; WS_DLL_PUBLIC void * wmem_alloc0(wmem_allocator_t *allocator, const size_t size) -G_GNUC_MALLOC; +G_GNUC_MALLOC +G_GNUC_ALLOC_SIZE(2); /** Allocate memory sufficient to hold one object of the given type. * Initializes the allocated memory with zeroes. @@ -161,7 +163,7 @@ wmem_free(wmem_allocator_t *allocator, void *ptr); WS_DLL_PUBLIC void * wmem_realloc(wmem_allocator_t *allocator, void *ptr, const size_t size) -G_GNUC_MALLOC; +G_GNUC_ALLOC_SIZE(3); /** Frees all the memory allocated in a pool. Depending on the allocator * implementation used this can be significantly cheaper than calling diff --git a/wsutil/wmem/wmem_interval_tree.c b/wsutil/wmem/wmem_interval_tree.c index 8b28549a..d8ed8e48 100644 --- a/wsutil/wmem/wmem_interval_tree.c +++ b/wsutil/wmem/wmem_interval_tree.c @@ -25,7 +25,6 @@ #include "wmem_interval_tree.h" #include "wmem_user_cb.h" - static void print_range(const void *value) { diff --git a/wsutil/wmem/wmem_list.c b/wsutil/wmem/wmem_list.c index c03ffe31..b5b4c52f 100644 --- a/wsutil/wmem/wmem_list.c +++ b/wsutil/wmem/wmem_list.c @@ -218,6 +218,56 @@ wmem_list_insert_sorted(wmem_list_t *list, void* data, GCompareFunc func) new_frame->next->prev = new_frame; } +void +wmem_list_append_sorted(wmem_list_t *list, void* data, GCompareFunc func) +{ + wmem_list_frame_t *new_frame; + wmem_list_frame_t *cur; + wmem_list_frame_t *next; + + new_frame = wmem_new(list->allocator, wmem_list_frame_t); + new_frame->data = data; + new_frame->next = NULL; + new_frame->prev = NULL; + + list->count++; + + if (!list->head) { + list->head = new_frame; + list->tail = new_frame; + return; + } + + cur = list->tail; + + /* best case scenario: append */ + if (func(cur->data, data) <= 0) { + cur->next = new_frame; + new_frame->prev = cur; + list->tail = new_frame; + return; + } + + do { + next = cur; + cur = cur->prev; + } while (cur && func(cur->data, data) >= 0); + + /* worst case scenario: prepend */ + if (!cur) { + next->prev = new_frame; + new_frame->next = next; + list->head = new_frame; + return; + } + + /* ordinary case: insert */ + new_frame->next = next; + new_frame->prev = cur; + new_frame->prev->next = new_frame; + new_frame->next->prev = new_frame; +} + wmem_list_t * wmem_list_new(wmem_allocator_t *allocator) { diff --git a/wsutil/wmem/wmem_list.h b/wsutil/wmem/wmem_list.h index fc0e5229..6b73e992 100644 --- a/wsutil/wmem/wmem_list.h +++ b/wsutil/wmem/wmem_list.h @@ -91,6 +91,13 @@ WS_DLL_PUBLIC void wmem_list_insert_sorted(wmem_list_t *list, void* data, GCompareFunc func); +/* + * Appender Insertion (start search from the tail) + */ +WS_DLL_PUBLIC +void +wmem_list_append_sorted(wmem_list_t *list, void* data, GCompareFunc func); + WS_DLL_PUBLIC wmem_list_t * diff --git a/wsutil/wmem/wmem_map.c b/wsutil/wmem/wmem_map.c index 047b8457..b3c581ae 100644 --- a/wsutil/wmem/wmem_map.c +++ b/wsutil/wmem/wmem_map.c @@ -484,19 +484,19 @@ wmem_strong_hash(const uint8_t *buf, const size_t len) } unsigned -wmem_str_hash(gconstpointer key) +wmem_str_hash(const void *key) { return wmem_strong_hash((const uint8_t *)key, strlen((const char *)key)); } unsigned -wmem_int64_hash(gconstpointer key) +wmem_int64_hash(const void *key) { return wmem_strong_hash((const uint8_t *)key, sizeof(uint64_t)); } unsigned -wmem_double_hash(gconstpointer key) +wmem_double_hash(const void *key) { return wmem_strong_hash((const uint8_t *)key, sizeof(double)); } diff --git a/wsutil/wmem/wmem_map.h b/wsutil/wmem/wmem_map.h index cb296fb4..6105aee9 100644 --- a/wsutil/wmem/wmem_map.h +++ b/wsutil/wmem/wmem_map.h @@ -207,21 +207,21 @@ wmem_strong_hash(const uint8_t *buf, const size_t len); */ WS_DLL_PUBLIC unsigned -wmem_str_hash(gconstpointer key); +wmem_str_hash(const void *key); /** An implementation of GHashFunc using wmem_strong_hash. Prefer this over * g_int64_hash when the data comes from an untrusted source. */ WS_DLL_PUBLIC unsigned -wmem_int64_hash(gconstpointer key); +wmem_int64_hash(const void *key); /** An implementation of GHashFunc using wmem_strong_hash. Prefer this over * g_double_hash when the data comes from an untrusted source. */ WS_DLL_PUBLIC unsigned -wmem_double_hash(gconstpointer key); +wmem_double_hash(const void *key); /** @} * @} */ diff --git a/wsutil/wmem/wmem_miscutl.c b/wsutil/wmem/wmem_miscutl.c index 14426447..6e3e2a3a 100644 --- a/wsutil/wmem/wmem_miscutl.c +++ b/wsutil/wmem/wmem_miscutl.c @@ -30,13 +30,13 @@ wmem_memdup(wmem_allocator_t *allocator, const void *source, const size_t size) } int -wmem_compare_int(gconstpointer a, gconstpointer b) +wmem_compare_int(const void *a, const void *b) { return GPOINTER_TO_INT(a) - GPOINTER_TO_INT(b); } int -wmem_compare_uint(gconstpointer a, gconstpointer b) +wmem_compare_uint(const void *a, const void *b) { return GPOINTER_TO_UINT(a) > GPOINTER_TO_UINT(b) ? 1 : (GPOINTER_TO_UINT(a) < GPOINTER_TO_UINT(b) ? -1 : 0); } diff --git a/wsutil/wmem/wmem_miscutl.h b/wsutil/wmem/wmem_miscutl.h index 714ee5cc..1d988878 100644 --- a/wsutil/wmem/wmem_miscutl.h +++ b/wsutil/wmem/wmem_miscutl.h @@ -38,17 +38,17 @@ extern "C" { WS_DLL_PUBLIC void * wmem_memdup(wmem_allocator_t *allocator, const void *source, const size_t size) -G_GNUC_MALLOC; +G_GNUC_ALLOC_SIZE(3); /** Generic GCompareFunc implementations to compare signed/unsigned integer */ WS_DLL_PUBLIC int -wmem_compare_int(gconstpointer a, gconstpointer b); +wmem_compare_int(const void *a, const void *b); WS_DLL_PUBLIC int -wmem_compare_uint(gconstpointer a, gconstpointer b); +wmem_compare_uint(const void *a, const void *b); /** @} * @} */ diff --git a/wsutil/wmem/wmem_strutl.c b/wsutil/wmem/wmem_strutl.c index 99f1f8c6..2ff3d5a7 100644 --- a/wsutil/wmem/wmem_strutl.c +++ b/wsutil/wmem/wmem_strutl.c @@ -111,7 +111,8 @@ wmem_strdup_vprintf(wmem_allocator_t *allocator, const char *fmt, va_list ap) /* Return the first occurrence of needle in haystack. * If not found, return NULL. - * If either haystack or needle has 0 length, return NULL.*/ + * If either haystack has 0 length, return NULL. + * If needle has 0 length, return pointer to haystack. */ const uint8_t * ws_memmem(const void *_haystack, size_t haystack_len, const void *_needle, size_t needle_len) @@ -126,7 +127,11 @@ ws_memmem(const void *_haystack, size_t haystack_len, const uint8_t *const last_possible = haystack + haystack_len - needle_len; if (needle_len == 0) { - return NULL; + return haystack; + } + + if (needle_len == 1) { + return memchr(haystack, needle[0], haystack_len); } if (needle_len > haystack_len) { @@ -134,9 +139,9 @@ ws_memmem(const void *_haystack, size_t haystack_len, } for (begin = haystack ; begin <= last_possible; ++begin) { - if (begin[0] == needle[0] && - !memcmp(&begin[1], needle + 1, - needle_len - 1)) { + begin = memchr(begin, needle[0], last_possible - begin + 1); + if (begin == NULL) break; + if (!memcmp(&begin[1], needle + 1, needle_len - 1)) { return begin; } } diff --git a/wsutil/wmem/wmem_strutl.h b/wsutil/wmem/wmem_strutl.h index ee3aed65..104a1eba 100644 --- a/wsutil/wmem/wmem_strutl.h +++ b/wsutil/wmem/wmem_strutl.h @@ -65,8 +65,8 @@ G_GNUC_MALLOC; * @param needle The string to look for * @param needle_len The length of the search string * @return A pointer to the first occurrence of "needle" in - * "haystack". If "needle" isn't found or is NULL, or if - * "needle_len" is 0, NULL is returned. + * "haystack". If "needle" isn't found or is NULL, NULL is returned. + * If "needle_len" is 0, a pointer to "haystack" is returned. */ WS_DLL_PUBLIC const uint8_t *ws_memmem(const void *haystack, size_t haystack_len, diff --git a/wsutil/wmem/wmem_test.c b/wsutil/wmem/wmem_test.c index 0dc908b7..65be3502 100644 --- a/wsutil/wmem/wmem_test.c +++ b/wsutil/wmem/wmem_test.c @@ -91,7 +91,7 @@ wmem_test_rand_string(wmem_allocator_t *allocator, int minlen, int maxlen) } static int -wmem_test_compare_guint32(const void *a, const void *b) +wmem_test_compare_uint32(const void *a, const void *b) { uint32_t l, r; @@ -692,7 +692,7 @@ wmem_test_array(void) } } - wmem_array_sort(array, wmem_test_compare_guint32); + wmem_array_sort(array, wmem_test_compare_uint32); for (i=0, k=0; i<8; i++) { for (j=0; j<=i; j++, k++) { val = *(uint32_t*)wmem_array_index(array, k); @@ -736,7 +736,7 @@ check_val_list(void * val, void * val_to_check) } static int -str_compare(gconstpointer a, gconstpointer b) +str_compare(const void *a, const void *b) { return strcmp((const char*)a, (const char*)b); } diff --git a/wsutil/wmem/wmem_tree.c b/wsutil/wmem/wmem_tree.c index 05fa638e..d982b3b0 100644 --- a/wsutil/wmem/wmem_tree.c +++ b/wsutil/wmem/wmem_tree.c @@ -23,7 +23,6 @@ #include "wmem_tree-int.h" #include "wmem_user_cb.h" - static wmem_tree_node_t * node_uncle(wmem_tree_node_t *node) { diff --git a/wsutil/ws_mempbrk.c b/wsutil/ws_mempbrk.c index f3f99b71..55334242 100644 --- a/wsutil/ws_mempbrk.c +++ b/wsutil/ws_mempbrk.c @@ -72,6 +72,21 @@ ws_mempbrk_exec(const uint8_t* haystack, size_t haystacklen, const ws_mempbrk_pa return ws_mempbrk_portable_exec(haystack, haystacklen, pattern, found_needle); } +WS_DLL_PUBLIC const uint8_t * +ws_memrpbrk_exec(const uint8_t* haystack, size_t haystacklen, const ws_mempbrk_pattern* pattern, unsigned char *found_needle) +{ + const uint8_t *haystack_end = haystack + haystacklen; + + while (haystack_end > haystack) { + if (pattern->patt[*(--haystack_end)]) { + if (found_needle) + *found_needle = *haystack_end; + return haystack_end; + } + } + + return NULL; +} /* * Editor modelines - https://www.wireshark.org/tools/modelines.html diff --git a/wsutil/ws_mempbrk.h b/wsutil/ws_mempbrk.h index 7aff505f..210fdfce 100644 --- a/wsutil/ws_mempbrk.h +++ b/wsutil/ws_mempbrk.h @@ -34,4 +34,9 @@ WS_DLL_PUBLIC void ws_mempbrk_compile(ws_mempbrk_pattern* pattern, const char *n */ WS_DLL_PUBLIC const uint8_t *ws_mempbrk_exec(const uint8_t* haystack, size_t haystacklen, const ws_mempbrk_pattern* pattern, unsigned char *found_needle); +/** Scan for the needles specified by the compiled pattern, starting at the + * end of the haystack and working backwards. + */ +WS_DLL_PUBLIC const uint8_t *ws_memrpbrk_exec(const uint8_t* haystack, size_t haystacklen, const ws_mempbrk_pattern* pattern, unsigned char *found_needle); + #endif /* __WS_MEMPBRK_H__ */ diff --git a/wsutil/ws_pipe.c b/wsutil/ws_pipe.c index 7689f933..2add60a9 100644 --- a/wsutil/ws_pipe.c +++ b/wsutil/ws_pipe.c @@ -29,12 +29,14 @@ #endif #endif +#if !GLIB_CHECK_VERSION(2, 58, 2) #ifdef __linux__ #define HAS_G_SPAWN_LINUX_THREAD_SAFETY_BUG #include <fcntl.h> #include <sys/syscall.h> /* for syscall and SYS_getdents64 */ #include <wsutil/file_util.h> /* for ws_open -> open to pacify checkAPIs.pl */ #endif +#endif #include "wsutil/filesystem.h" #include "wsutil/wslog.h" @@ -153,7 +155,7 @@ ws_pipe_create_overlapped_read(HANDLE *read_pipe_handle, HANDLE *write_pipe_hand *read_pipe_handle = read_pipe; *write_pipe_handle = write_pipe; g_free(wname); - return(true); + return true; } #endif @@ -221,7 +223,7 @@ convert_to_command_line(char **argv) g_free(quoted_arg); } #endif - return g_string_free(command_line, false); + return g_string_free(command_line, FALSE); } bool ws_pipe_spawn_sync(const char *working_directory, const char *command, int argc, char **args, char **command_output) @@ -455,7 +457,7 @@ bool ws_pipe_spawn_sync(const char *working_directory, const char *command, int status = false; } - local_output = g_string_free(output_string, false); + local_output = g_string_free(output_string, FALSE); CloseHandle(child_stdout_rd); CloseHandle(child_stderr_rd); diff --git a/wsutil/ws_strptime.c b/wsutil/ws_strptime.c index 3c55d93e..7a8a37f5 100644 --- a/wsutil/ws_strptime.c +++ b/wsutil/ws_strptime.c @@ -118,7 +118,7 @@ static const unsigned char *find_string(const unsigned char *, int *, const char #define HAVE_YEAR(s) (s & S_YEAR) #define HAVE_HOUR(s) (s & S_HOUR) -static char utc[] = { "UTC" }; +static const char utc[] = { "UTC" }; /* RFC-822/RFC-2822 */ static const char * const nast[5] = { "EST", "CST", "MST", "PST", "\0\0\0" diff --git a/wsutil/wsjson.c b/wsutil/wsjson.c index d2e55771..4a53e971 100644 --- a/wsutil/wsjson.c +++ b/wsutil/wsjson.c @@ -194,6 +194,43 @@ bool json_get_double(char *buf, jsmntok_t *parent, const char *name, double *val return false; } +bool json_get_boolean(char *buf, jsmntok_t *parent, const char *name, bool *val) +{ + int i; + size_t tok_len; + jsmntok_t *cur = parent+1; + + for (i = 0; i < parent->size; i++) { + if (cur->type == JSMN_STRING && + !strncmp(&buf[cur->start], name, cur->end - cur->start) + && strlen(name) == (size_t)(cur->end - cur->start) && + cur->size == 1 && (cur+1)->type == JSMN_PRIMITIVE) { + /* JSMN_STRICT guarantees that a primitive starts with the + * correct character. + */ + tok_len = (cur+1)->end - (cur+1)->start; + switch (buf[(cur+1)->start]) { + case 't': + if (tok_len == 4 && strncmp(&buf[(cur+1)->start], "true", tok_len) == 0) { + *val = true; + return true; + } + return false; + case 'f': + if (tok_len == 5 && strncmp(&buf[(cur+1)->start], "false", tok_len) == 0) { + *val = false; + return true; + } + return false; + default: + return false; + } + } + cur = json_get_next_object(cur); + } + return false; +} + bool json_decode_string_inplace(char *text) { diff --git a/wsutil/wsjson.h b/wsutil/wsjson.h index be232767..180c0fb1 100644 --- a/wsutil/wsjson.h +++ b/wsutil/wsjson.h @@ -70,6 +70,12 @@ WS_DLL_PUBLIC char *json_get_string(char *buf, jsmntok_t *parent, const char *na WS_DLL_PUBLIC bool json_get_double(char *buf, jsmntok_t *parent, const char *name, double *val); /** + * Get the value of a boolean belonging to parent object and named as the name variable. + * Returns false if not found. (Not the same as the boolean present but false.) + */ +WS_DLL_PUBLIC bool json_get_boolean(char *buf, jsmntok_t *parent, const char *name, bool *val); + +/** * Decode the contents of a JSON string value by overwriting the input data. * Returns true on success and false if invalid characters were encountered. */ diff --git a/wsutil/wslog.c b/wsutil/wslog.c index e181e5ed..4b35c294 100644 --- a/wsutil/wslog.c +++ b/wsutil/wslog.c @@ -87,40 +87,40 @@ typedef struct { * will be printed regardless of log level. This is a feature, not a bug. */ static enum ws_log_level current_log_level = LOG_LEVEL_NONE; -static bool stdout_color_enabled = false; +static bool stdout_color_enabled; -static bool stderr_color_enabled = false; +static bool stderr_color_enabled; /* Use stdout for levels "info" and below, for backward compatibility * with GLib. */ -static bool stdout_logging_enabled = false; +static bool stdout_logging_enabled; static const char *registered_progname = DEFAULT_PROGNAME; /* List of domains to filter. */ -static log_filter_t *domain_filter = NULL; +static log_filter_t *domain_filter; /* List of domains to output debug level unconditionally. */ -static log_filter_t *debug_filter = NULL; +static log_filter_t *debug_filter; /* List of domains to output noisy level unconditionally. */ -static log_filter_t *noisy_filter = NULL; +static log_filter_t *noisy_filter; /* List of domains that are fatal. */ -static log_filter_t *fatal_filter = NULL; +static log_filter_t *fatal_filter; -static ws_log_writer_cb *registered_log_writer = NULL; +static ws_log_writer_cb *registered_log_writer; -static void *registered_log_writer_data = NULL; +static void *registered_log_writer_data; -static ws_log_writer_free_data_cb *registered_log_writer_data_free = NULL; +static ws_log_writer_free_data_cb *registered_log_writer_data_free; -static FILE *custom_log = NULL; +static FILE *custom_log; static enum ws_log_level fatal_log_level = LOG_LEVEL_ERROR; #ifdef WS_DEBUG -static bool init_complete = false; +static bool init_complete; #endif ws_log_console_open_pref ws_log_console_open = LOG_CONSOLE_OPEN_NEVER; @@ -864,13 +864,8 @@ void ws_log_init(const char *progname, if ((fd = fileno(stderr)) >= 0) stderr_color_enabled = g_log_writer_supports_color(fd); - /* Set the GLib log handler for the default domain. */ - g_log_set_handler(NULL, G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, - glib_log_handler, NULL); - - /* Set the GLib log handler for GLib itself. */ - g_log_set_handler("GLib", G_LOG_LEVEL_MASK | G_LOG_FLAG_FATAL, - glib_log_handler, NULL); + /* Set ourselves as the default log handler for all GLib domains. */ + g_log_set_default_handler(glib_log_handler, NULL); #ifdef _WIN32 load_registry(); diff --git a/wsutil/wslog.h b/wsutil/wslog.h index 8044ad10..8f97a543 100644 --- a/wsutil/wslog.h +++ b/wsutil/wslog.h @@ -357,18 +357,19 @@ void ws_log_fatal_full(const char *domain, enum ws_log_level level, /** Logs with "message" level. * - * Accepts a format string and *does not* include the file and function - * name. This is the default log level. + * Accepts a format string and does not include the file and function + * name (use ws_log_full instead). This is the default log level. */ #define ws_message(...) \ _LOG_SIMPLE(true, LOG_LEVEL_MESSAGE, __VA_ARGS__) /** Logs with "info" level. * - * Accepts a format string and includes the file and function name. + * Accepts a format string and does not include the file and function + * name (use ws_log_full instead). */ #define ws_info(...) \ - _LOG_FULL(true, LOG_LEVEL_INFO, __VA_ARGS__) + _LOG_SIMPLE(true, LOG_LEVEL_INFO, __VA_ARGS__) /** Logs with "debug" level. * @@ -388,6 +389,8 @@ void ws_log_fatal_full(const char *domain, enum ws_log_level level, #define WS_DEBUG_HERE(...) \ _LOG_FULL(true, LOG_LEVEL_ECHO, __VA_ARGS__) +#define WS_NOT_IMPLEMENTED() \ + ws_error("Not implemented yet") WS_DLL_PUBLIC void ws_log_utf8_full(const char *domain, enum ws_log_level level, |