Compare commits

...

21 Commits

Author SHA1 Message Date
Jan Vidar Krey
c7d40dc6e0 Add missing file (Stub) 2019-01-22 18:29:06 +01:00
Jan Vidar Krey
9ac1a378d0 WIP 2019-01-17 18:57:19 +01:00
Jan Vidar Krey
de01486c0f Fix plug-in API header files. 2018-11-27 13:20:41 +01:00
Jan Vidar Krey
c383a53105 Fix crash if unable to load plugin. 2018-11-21 11:00:20 +01:00
Kcchouette
f0b67ea4cd Update config.xml 2018-11-20 11:56:07 +01:00
Kcchouette
ac96ace7df Finish adding bots to uhub-passwd
Related to https://github.com/janvidar/uhub/pull/28
2018-11-18 20:32:00 +01:00
Kcchouette
7970f80114 Update getstarted.txt 2018-11-18 20:31:37 +01:00
Kcchouette
62216a7afe Update issue url (#48)
* Update issue url

* Update uhub.1

* update bugs URL
2018-11-18 20:30:23 +01:00
Felix Brucker
99711a5c6e Allow many large messages 2018-10-11 23:29:32 +02:00
Felix Brucker
e43aea35cc Use localtime instead of utc 2018-10-11 23:29:32 +02:00
makefu
d54d723c59 add aarch64 to supported architectures
closes #46
2018-10-11 23:24:11 +02:00
Jan Vidar Krey
c813231c8d Merge pull request #44 from Kcchouette/patch-1
Update plugins.conf
2018-04-30 15:23:43 +02:00
Kcchouette
debbca572f Update plugins.conf 2018-04-30 15:22:42 +02:00
Jan Vidar Krey
a8ee6e7f60 Bump version to 0.5.1 2018-02-26 14:13:21 +00:00
Jan Vidar Krey
f0e9b2ffd9 Add support for OpenSSL 1.1 2018-02-26 10:58:41 +00:00
Jan Vidar Krey
ba19048ebc Rename the test binary to autotest-bin, to avoid naming conflicts for the reserved 'test' target. 2018-02-19 11:59:34 +01:00
Jan Vidar Krey
fd05f13fe4 Make error message if sqlite3 is not found! 2018-02-19 11:44:43 +01:00
Jan Vidar Krey
11538d6909 Mute debug log messages for net_send() that were incorrectly classified as error messages. 2018-01-15 17:00:56 +00:00
Yorhel
90d05c9a19 mod_logging: Fix inverted if statement in syslog config check 2016-07-11 09:26:34 +00:00
Jan Vidar Krey
ed5a59b16c Merge pull request #35 from CoiLock/master
Fixed compilation on systemd > 210
2016-03-07 18:17:07 +01:00
CoiLock
70f2a43f67 Fixed compilation on systemd > 210 2016-03-07 17:54:07 +01:00
20 changed files with 157 additions and 56 deletions

3
BUGS
View File

@@ -1,2 +1 @@
Bugs are tracked on: http://bugs.extatic.org/
Bugs are tracked on: https://github.com/janvidar/uhub/issues

View File

@@ -1,6 +1,6 @@
##
## Makefile for uhub
## Copyright (C) 2007-2013, Jan Vidar Krey <janvidar@extatic.org>
## Copyright (C) 2007-2019, Jan Vidar Krey <janvidar@extatic.org>
#
cmake_minimum_required (VERSION 2.8.2)
@@ -10,7 +10,7 @@ enable_language(C)
set (UHUB_VERSION_MAJOR 0)
set (UHUB_VERSION_MINOR 5)
set (UHUB_VERSION_PATCH 0)
set (UHUB_VERSION_PATCH 1)
set (PROJECT_SOURCE_DIR "${CMAKE_SOURCE_DIR}/src")
set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/Modules)
@@ -54,10 +54,13 @@ if (SSL_SUPPORT)
endif()
endif()
if (NOT SQLITE3_FOUND)
message(FATAL_ERROR "SQLite3 is not found!")
endif()
if (SYSTEMD_SUPPORT)
INCLUDE(FindPkgConfig)
pkg_search_module(SD_DAEMON REQUIRED libsystemd-daemon)
pkg_search_module(SD_JOURNAL REQUIRED libsystemd-journal)
pkg_search_module(SD REQUIRED libsystemd)
endif()
if (MSVC)
@@ -104,7 +107,7 @@ add_dependencies(adc utils)
add_dependencies(network utils)
add_executable(uhub ${PROJECT_SOURCE_DIR}/core/main.c ${uhub_SOURCES} )
add_executable(test ${CMAKE_SOURCE_DIR}/autotest/test.c ${uhub_SOURCES} )
add_executable(autotest-bin ${CMAKE_SOURCE_DIR}/autotest/test.c ${uhub_SOURCES} )
add_executable(uhub-passwd ${PROJECT_SOURCE_DIR}/tools/uhub-passwd.c)
add_library(mod_example MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_example.c)
@@ -117,10 +120,11 @@ add_library(mod_chat_only MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_chat_only.c)
add_library(mod_topic MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_topic.c)
add_library(mod_no_guest_downloads MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_no_guest_downloads.c)
add_library(mod_auth_sqlite MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_auth_sqlite.c)
add_library(mod_require_tls MODULE ${PROJECT_SOURCE_DIR}/plugins/mod_require_tls.c)
if(WIN32)
target_link_libraries(uhub ws2_32)
target_link_libraries(test ws2_32)
target_link_libraries(autotest-bin ws2_32)
target_link_libraries(mod_logging ws2_32)
target_link_libraries(mod_welcome ws2_32)
endif()
@@ -136,11 +140,12 @@ set_target_properties(
mod_chat_only
mod_no_guest_downloads
mod_topic
mod_require_tls
PROPERTIES PREFIX "")
target_link_libraries(uhub ${CMAKE_DL_LIBS} adc network utils)
target_link_libraries(uhub-passwd ${SQLITE3_LIBRARIES} utils)
target_link_libraries(test ${CMAKE_DL_LIBS} adc network utils)
target_link_libraries(autotest-bin ${CMAKE_DL_LIBS} adc network utils)
target_link_libraries(mod_example utils)
target_link_libraries(mod_welcome utils)
target_link_libraries(mod_auth_simple utils)
@@ -151,6 +156,7 @@ target_link_libraries(mod_no_guest_downloads utils)
target_link_libraries(mod_chat_only utils)
target_link_libraries(mod_logging utils)
target_link_libraries(mod_topic utils)
target_link_libraries(mod_require_tls utils)
target_link_libraries(utils network)
target_link_libraries(mod_welcome network)
target_link_libraries(mod_logging network)
@@ -161,7 +167,7 @@ if(UNIX)
add_executable(uhub-admin ${PROJECT_SOURCE_DIR}/tools/admin.c)
target_link_libraries(uhub-admin adcclient adc network utils pthread)
target_link_libraries(uhub pthread)
target_link_libraries(test pthread)
target_link_libraries(autotest-bin pthread)
if (ADC_STRESS)
add_executable(adcrush ${PROJECT_SOURCE_DIR}/tools/adcrush.c ${adcclient_SOURCES})
@@ -200,7 +206,7 @@ endif()
if(SSL_SUPPORT)
target_link_libraries(uhub ${SSL_LIBS})
target_link_libraries(test ${SSL_LIBS})
target_link_libraries(autotest-bin ${SSL_LIBS})
if(UNIX)
target_link_libraries(uhub-admin ${SSL_LIBS})
endif()
@@ -212,14 +218,11 @@ if(SSL_SUPPORT)
endif()
if (SYSTEMD_SUPPORT)
target_link_libraries(uhub ${SD_DAEMON_LIBRARIES})
target_link_libraries(uhub ${SD_JOURNAL_LIBRARIES})
target_link_libraries(test ${SD_DAEMON_LIBRARIES})
target_link_libraries(test ${SD_JOURNAL_LIBRARIES})
target_link_libraries(uhub-passwd ${SD_JOURNAL_LIBRARIES})
target_link_libraries(uhub-admin ${SD_JOURNAL_LIBRARIES})
include_directories(${SD_DAEMON_INCLUDE_DIRS})
include_directories(${SD_JOURNAL_INCLUDE_DIRS})
target_link_libraries(uhub ${SD_LIBRARIES})
target_link_libraries(autotest-bin ${SD_LIBRARIES})
target_link_libraries(uhub-passwd ${SD_LIBRARIES})
target_link_libraries(uhub-admin ${SD_LIBRARIES})
include_directories(${SD_INCLUDE_DIRS})
add_definitions(-DSYSTEMD)
endif()

View File

@@ -34,8 +34,8 @@ cmake ${CMAKEOPTS} \
make VERBOSE=1
make VERBOSE=1 test
./test
make VERBOSE=1 autotest-bin
./autotest-bin
sudo make install

View File

@@ -1,8 +1,6 @@
Getting started guide
---------------------
(This document is maintained at http://www.extatic.org/uhub/getstarted.html )
Unpack your binaries
Example:
@@ -17,6 +15,7 @@ Create configuration files.
If no configuration files are created, uhub will use the default parameters, so you can skip this step if you are in a hurry to see it run.
As root, or use sudo.
% mkdir /etc/uhub
% cp doc/uhub.conf /etc/uhub
% cp doc/users.conf /etc/uhub
@@ -32,8 +31,11 @@ NOTE: It is important to use the "adc://" prefix, and the port number when using
If you modify the configuration files in /etc/uhub you will have to notify uhub by sending a HUP signal.
% ps aux | grep uhub
% kill -HUP <pid of uhub>
Or, for the lazy people
% killall -HUP uhub
In order to run uhub as a daemon, start it with the -f switch which will make it fork into the background.
@@ -41,8 +43,8 @@ In addition, use the -l to specify a log file instead of stdout. One can also sp
if one wishes to run uhub as a specific user using the -u and -g switches.
Example:
% uhub -f -l mylog.txt -u nobody -g nogroup
% uhub -f -l mylog.txt -u nobody -g nogroup
If you are planning to more than 1024 users on hub, you must increase the max number of file descriptors allowed.
This limit needs to be higher than the configured max_users in uhub.conf.
@@ -52,6 +54,14 @@ In linux can add the following lines to /etc/security/limits.conf (allows for ~4
* hard nofile 4096
Or, you can use (as root):
% ulimit -n 4096
You can interact with uhub in your hub main chat using the `!` prefix, followed by a command:
Example :
* to display help and the command you can use:
!help
Your mileage may vary -- Good luck!

View File

@@ -41,7 +41,7 @@ plugin /usr/lib/uhub/mod_logging.so "file=/var/log/uhub.log"
#
# Parameters:
# motd: path/filename for the welcome message (message of the day)
# rules: path/filenam for the rules file
# rules: path/filename for the rules file
#
# NOTE: The files MUST exist, however if you do not wish to provide one then these parameters can be omitted.
#
@@ -69,4 +69,3 @@ plugin /usr/lib/uhub/mod_welcome.so "motd=/etc/uhub/motd.txt rules=/etc/uhub/rul
# history_default: when !history is provided without arguments, then this default number of messages are returned.
# history_connect: the number of chat history messages to send when users connect (0 = do not send any history)
plugin /usr/lib/uhub/mod_chat_history.so "history_max=200 history_default=10 history_connect=5"

View File

@@ -39,4 +39,4 @@ is one of 'admin', 'super', 'op', 'user'
This program was written by Jan Vidar Krey <janvidar@extatic.org>
.SH "BUG REPORTS"
If you find a bug in uhub please report it to
.B http://bugs.extatic.org/
.B https://github.com/janvidar/uhub/issues

View File

@@ -69,4 +69,4 @@ To run uhub as a daemon, and log to a file:
This program was written by Jan Vidar Krey <janvidar@extatic.org>
.SH "BUG REPORTS"
If you find a bug in uhub please report it to
.B http://bugs.extatic.org/
.B https://github.com/janvidar/uhub/issues

View File

@@ -111,7 +111,7 @@
<option name="register_self" type="boolean" default="0">
<short>Allow users to register themselves on the hub.</short>
<description><![CDATA[
If this is enabled guests can register their nickname on the hub.
If this is enabled guests can register their nickname on the hub using !register command.
Otherwise only operators can register users.
]]></description>
<since>0.4.0</since>

View File

@@ -96,6 +96,29 @@ static int cbfunc_user_disconnect(struct plugin_handle* plugin, struct plugin_us
return 0;
}
static int cbfunc_user_redirect(struct plugin_handle* plugin, struct plugin_user* user, const char* address)
{
char* buffer = adc_msg_escape(address);
struct adc_message* command = adc_msg_construct(ADC_CMD_IQUI, strlen(buffer) + 10);
adc_msg_add_named_argument(command, ADC_QUI_FLAG_REDIRECT, buffer);
route_to_user(plugin_get_hub(plugin), convert_user_type(user), command);
adc_msg_free(command);
hub_free(buffer);
hub_disconnect_user(plugin_get_hub(plugin), convert_user_type(user), quit_disconnected);
return 0;
}
static int cbfunc_user_is_tls_connected(struct plugin_handle* plugin, struct plugin_user* user)
{
#ifdef SSL_SUPPORT
struct hub_user* u = convert_user_type(user);
return net_con_is_ssl(u->connection);
#else
return 0;
#endif
}
static int cbfunc_command_add(struct plugin_handle* plugin, struct plugin_command_handle* cmdh)
{
struct plugin_callback_data* data = get_callback_data(plugin);
@@ -203,6 +226,8 @@ void plugin_register_callback_functions(struct plugin_handle* handle)
handle->hub.send_broadcast_message = cbfunc_send_broadcast;
handle->hub.send_status_message = cbfunc_send_status;
handle->hub.user_disconnect = cbfunc_user_disconnect;
handle->hub.user_redirect = cbfunc_user_redirect;
handle->hub.user_is_tls_connected = cbfunc_user_is_tls_connected;
handle->hub.command_add = cbfunc_command_add;
handle->hub.command_del = cbfunc_command_del;
handle->hub.command_arg_reset = cbfunc_command_arg_reset;

View File

@@ -102,7 +102,6 @@ struct plugin_handle* plugin_load(const char* filename, const char* config, stru
int ret;
struct plugin_handle* handle = (struct plugin_handle*) hub_malloc_zero(sizeof(struct plugin_handle));
struct uhub_plugin* plugin = plugin_open(filename);
struct plugin_hub_internals* internals = (struct plugin_hub_internals*) plugin->internals;
if (!plugin)
return NULL;
@@ -118,6 +117,7 @@ struct plugin_handle* plugin_load(const char* filename, const char* config, stru
unregister_f = plugin_lookup_symbol(plugin, "plugin_unregister");
// register hub internals
struct plugin_hub_internals* internals = (struct plugin_hub_internals*) plugin->internals;
internals->unregister = unregister_f;
internals->hub = hub;
internals->callback_data = plugin_callback_data_create();

View File

@@ -91,7 +91,9 @@ int net_ssl_library_init()
int net_ssl_library_shutdown()
{
ERR_clear_error();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
ERR_remove_state(0);
#endif
ENGINE_cleanup();
CONF_modules_unload(1);
@@ -106,16 +108,24 @@ int net_ssl_library_shutdown()
static void add_io_stats(struct net_ssl_openssl* handle)
{
if (handle->bio->num_read > handle->bytes_rx)
#if OPENSSL_VERSION_NUMBER < 0x10100000L
unsigned long num_read = handle->bio->num_read;
unsigned long num_write = handle->bio->num_write;
#else
unsigned long num_read = BIO_number_read(handle->bio);
unsigned long num_write = BIO_number_written(handle->bio);
#endif
if (num_read > handle->bytes_rx)
{
net_stats_add_rx(handle->bio->num_read - handle->bytes_rx);
handle->bytes_rx = handle->bio->num_read;
net_stats_add_rx(num_read - handle->bytes_rx);
handle->bytes_rx = num_read;
}
if (handle->bio->num_write > handle->bytes_tx)
if (num_write > handle->bytes_tx)
{
net_stats_add_tx(handle->bio->num_write - handle->bytes_tx);
handle->bytes_tx = handle->bio->num_write;
net_stats_add_tx(num_write - handle->bytes_tx);
handle->bytes_tx = num_write;
}
}
@@ -127,6 +137,7 @@ static const SSL_METHOD* get_ssl_method(const char* tls_version)
return 0;
}
#if OPENSSL_VERSION_NUMBER < 0x10100000L
if (!strcmp(tls_version, "1.0"))
return TLSv1_method();
if (!strcmp(tls_version, "1.1"))
@@ -136,6 +147,10 @@ static const SSL_METHOD* get_ssl_method(const char* tls_version)
LOG_ERROR("Unable to recognize tls_version.");
return 0;
#else
LOG_WARN("tls_version is obsolete, and should not be used.");
return TLS_method();
#endif
}
/**
@@ -333,7 +348,7 @@ ssize_t net_ssl_send(struct net_connection* con, const void* buf, size_t len)
{
struct net_ssl_openssl* handle = get_handle(con);
LOG_ERROR("net_ssl_send(), state=%d", (int) handle->state);
LOG_TRACE("net_ssl_send(), state=%d", (int) handle->state);
if (handle->state == tls_st_error)
return -2;

View File

@@ -35,6 +35,16 @@ struct plugin_command
struct linked_list* args;
};
enum plugin_command_arg_type
{
plugin_cmd_arg_type_integer,
plugin_cmd_arg_type_string,
plugin_cmd_arg_type_user,
plugin_cmd_arg_type_address,
plugin_cmd_arg_type_range,
plugin_cmd_arg_type_credentials,
};
struct plugin_command_arg_data
{
enum plugin_command_arg_type type;

View File

@@ -28,6 +28,7 @@
#include "util/credentials.h"
#include "network/ipcalc.h"
#include "plugin_api/types.h"
#include "plugin_api/command_api.h"
typedef void (*on_connection_accepted_t)(struct plugin_handle*, struct ip_addr_encap*);
typedef void (*on_connection_refused_t)(struct plugin_handle*, struct ip_addr_encap*);
@@ -113,6 +114,8 @@ typedef int (*hfunc_send_message)(struct plugin_handle*, struct plugin_user* use
typedef int (*hfunc_send_broadcast_message)(struct plugin_handle*, const char* message);
typedef int (*hfunc_send_status)(struct plugin_handle*, struct plugin_user* to, int code, const char* message);
typedef int (*hfunc_user_disconnect)(struct plugin_handle*, struct plugin_user* user);
typedef int (*hfunc_user_redirect)(struct plugin_handle*, struct plugin_user* user, const char* address);
typedef int (*hfunc_user_is_tls_connected)(struct plugin_handle*, struct plugin_user* user);
typedef int (*hfunc_command_add)(struct plugin_handle*, struct plugin_command_handle*);
typedef int (*hfunc_command_del)(struct plugin_handle*, struct plugin_command_handle*);
@@ -136,6 +139,8 @@ struct plugin_hub_funcs
hfunc_send_broadcast_message send_broadcast_message;
hfunc_send_status send_status_message;
hfunc_user_disconnect user_disconnect;
hfunc_user_redirect user_redirect;
hfunc_user_is_tls_connected user_is_tls_connected;
hfunc_command_add command_add;
hfunc_command_del command_del;
hfunc_command_arg_reset command_arg_reset;

View File

@@ -93,15 +93,6 @@ struct ban_info
time_t expiry; /* Time when the ban record expires */
};
enum plugin_command_arg_type
{
plugin_cmd_arg_type_integer,
plugin_cmd_arg_type_string,
plugin_cmd_arg_type_user,
plugin_cmd_arg_type_address,
plugin_cmd_arg_type_range,
plugin_cmd_arg_type_credentials,
};
#endif /* HAVE_UHUB_PLUGIN_TYPES_H */

View File

@@ -26,7 +26,7 @@
#include "util/list.h"
#include "util/cbuffer.h"
#define MAX_HISTORY_SIZE 16384
#define MAX_HISTORY_SIZE 614400
struct chat_history_data
{
@@ -142,7 +142,7 @@ void user_login(struct plugin_handle* plugin, struct plugin_user* user)
struct cbuffer* buf = NULL;
struct linked_list* found = (struct linked_list*) list_create();
sql_execute(data, get_messages_callback, found, "SELECT * FROM chat_history ORDER BY time DESC LIMIT 0,%d;", (int) data->history_connect);
sql_execute(data, get_messages_callback, found, "SELECT from_nick,message, datetime(time, 'localtime') as time FROM chat_history ORDER BY time DESC LIMIT 0,%d;", (int) data->history_connect);
if (data->history_connect > 0 && list_size(found) > 0)
{
@@ -180,7 +180,7 @@ static int command_history(struct plugin_handle* plugin, struct plugin_user* use
else
maxlines = data->history_default;
sql_execute(data, get_messages_callback, found, "SELECT * FROM chat_history ORDER BY time DESC LIMIT 0,%d;", maxlines);
sql_execute(data, get_messages_callback, found, "SELECT from_nick,message, datetime(time, 'localtime') as time FROM chat_history ORDER BY time DESC LIMIT 0,%d;", maxlines);
size_t linecount = list_size(found);

View File

@@ -102,7 +102,7 @@ static struct log_data* parse_config(const char* line, struct plugin_handle* plu
else if (strcmp(cfg_settings_get_key(setting), "syslog") == 0)
{
int use_syslog = 0;
if (!string_to_boolean(cfg_settings_get_value(setting), &use_syslog))
if (string_to_boolean(cfg_settings_get_value(setting), &use_syslog))
{
data->logmode = (use_syslog) ? mode_syslog : mode_file;
}

View File

@@ -0,0 +1,41 @@
/*
* uhub - A tiny ADC p2p connection hub
* Copyright (C) 2007-2018, Jan Vidar Krey
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*
*/
#include "plugin_api/handle.h"
#include "plugin_api/command_api.h"
#include "util/memory.h"
struct example_plugin_data
{
struct plugin_command_handle* redirect;
};
int plugin_register(struct plugin_handle* plugin, const char* config)
{
PLUGIN_INITIALIZE(plugin, "TLS redirect plugin", "1.0", "A simple redirect to TLS plug-in");
return 0;
}
int plugin_unregister(struct plugin_handle* plugin)
{
return 0;
}

View File

@@ -197,6 +197,10 @@
#define CPUINFO "ARM"
#endif
#if defined(__aarch64__)
#define CPUINFO "AArch64"
#endif
#if defined(__i386__) || defined(__i386) || defined(i386) || defined(_M_IX86) || defined(__X86__) || defined(_X86_) || defined(__I86__) || defined(__INTEL__) || defined(__THW_INTEL__)
#define CPUINFO "i386"
#endif

View File

@@ -375,7 +375,7 @@ void main_usage(const char* binary)
" 'filename' is a database file\n"
" 'username' is a nickname (UTF-8, up to %i bytes)\n"
" 'password' is a password (UTF-8, up to %i bytes)\n"
" 'credentials' is one of 'admin', 'super', 'op', 'user'\n"
" 'credentials' is one of 'bot', 'ubot', 'opbot', 'opubot', 'admin', 'super', 'op' or 'user'\n"
"\n"
, binary, MAX_NICK_LEN, MAX_PASS_LEN);
}
@@ -403,5 +403,3 @@ int main(int argc, char** argv)
main_usage(argv[0]);
return 1;
}

View File

@@ -20,6 +20,7 @@
#include "uhub.h"
#define CBUF_FLAG_CONST_BUFFER 0x01
#define MAX_MSG_LEN 16384
struct cbuffer
{
@@ -86,19 +87,19 @@ void cbuf_append(struct cbuffer* buf, const char* msg)
void cbuf_append_format(struct cbuffer* buf, const char* format, ...)
{
static char tmp[1024];
static char tmp[MAX_MSG_LEN];
va_list args;
int bytes;
uhub_assert(buf->flags == 0);
va_start(args, format);
bytes = vsnprintf(tmp, 1024, format, args);
bytes = vsnprintf(tmp, sizeof(tmp), format, args);
va_end(args);
cbuf_append_bytes(buf, tmp, bytes);
}
void cbuf_append_strftime(struct cbuffer* buf, const char* format, const struct tm* tm)
{
static char tmp[1024];
static char tmp[MAX_MSG_LEN];
int bytes;
uhub_assert(buf->flags == 0);
bytes = strftime(tmp, sizeof(tmp), format, tm);