mirror of
https://salsa.debian.org/ha-team/libqb
synced 2026-08-14 18:24:28 +00:00
Imported Upstream version 0.17.2
This commit is contained in:
parent
2b262fd5db
commit
37c156628d
2
.gitignore
vendored
2
.gitignore
vendored
@ -6,6 +6,7 @@
|
||||
*.so.*
|
||||
*.3
|
||||
*.rpm
|
||||
*.swp
|
||||
*.pc
|
||||
*.log
|
||||
Makefile
|
||||
@ -27,3 +28,4 @@ abi_dumps
|
||||
TAGS
|
||||
*~
|
||||
test-driver
|
||||
tests/*.trs
|
||||
|
||||
15
.travis.yml
15
.travis.yml
@ -1,13 +1,10 @@
|
||||
language: c
|
||||
compiler:
|
||||
- gcc
|
||||
before_install: sudo apt-get install check splint
|
||||
install:
|
||||
# Deal with issue on Travis builders
|
||||
# https://github.com/travis-ci/travis-cookbooks/issues/155
|
||||
- "sudo rm -rf /dev/shm && sudo ln -s /run/shm /dev/shm"
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- check
|
||||
- splint
|
||||
script: ./autogen.sh && ./configure && make check && make distcheck
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- quarterback-devel@lists.fedorahosted.org
|
||||
sudo: false
|
||||
|
||||
@ -1,17 +1,18 @@
|
||||
# libqb
|
||||
|
||||
## What is libqb?
|
||||
libqb is a library with the primary purpose of providing high performance
|
||||
client server reusable features. It provides high performance logging,
|
||||
tracing, ipc, and poll.
|
||||
libqb is a library with the primary purpose of providing high-performance,
|
||||
reusable features for client-server architecture, such as logging,
|
||||
tracing, inter-process communication (IPC), and polling.
|
||||
|
||||
We don't intend be an all encompassing library, but instead provide very
|
||||
specially focused APIs that are highly tuned for maximum performance for client/server applications.
|
||||
libqb is not intended to be an all-encompassing library, but instead provide
|
||||
focused APIs that are highly tuned for maximum performance for client-server
|
||||
applications.
|
||||
|
||||
[](https://travis-ci.org/ClusterLabs/libqb)
|
||||
|
||||
## For more information look at:
|
||||
* [Our wiki](https://github.com/clusterlabs/libqb/wiki)
|
||||
## For more information, see:
|
||||
* [libqb wiki](https://github.com/clusterlabs/libqb/wiki)
|
||||
* [Issues/Bugs](https://github.com/clusterlabs/libqb/issues)
|
||||
* [The doxygen generated manual](http://clusterlabs.github.io/libqb/0.16.0/doxygen/)
|
||||
* You can build it yourself with the following commands:
|
||||
@ -42,8 +43,7 @@ If you find this project useful, you may want to consider supporting its future
|
||||
There are a number of ways to support the project.
|
||||
|
||||
* Test and report issues.
|
||||
* Help others on the [mailing list](https://fedorahosted.org/mailman/listinfo/quarterback-devel).
|
||||
* Help others on the [developers@clusterlabs.org mailing list](http://clusterlabs.org/mailman/listinfo/developers).
|
||||
* Contribute documentation, examples and test cases.
|
||||
* Contribute patches.
|
||||
* Spread the word.
|
||||
|
||||
|
||||
@ -78,7 +78,7 @@ AM_CONDITIONAL(HAVE_SPLINT, test -n "${SPLINT}")
|
||||
# args. Global CFLAGS are ignored during this test.
|
||||
cc_supports_flag() {
|
||||
BACKUP="$CPPFLAGS"
|
||||
CPPFLAGS="$CPPFLAGS $@"
|
||||
CPPFLAGS="$CPPFLAGS $@ -Werror"
|
||||
AC_MSG_CHECKING([whether $CC supports "$@"])
|
||||
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
|
||||
[RC=0; AC_MSG_RESULT([yes])],
|
||||
@ -253,10 +253,14 @@ case $host_cpu in
|
||||
nongcc_memory_barrier_needed=yes
|
||||
;;
|
||||
arm*)
|
||||
AC_MSG_RESULT([ia64])
|
||||
AC_MSG_RESULT([arm])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_ARM], [1], [arm])
|
||||
arch_force_shmlba=yes
|
||||
;;
|
||||
hppa*)
|
||||
AC_MSG_RESULT([hppa])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_HPPA], [1], [hppa])
|
||||
;;
|
||||
mips*)
|
||||
AC_MSG_RESULT([ia64])
|
||||
AC_DEFINE_UNQUOTED([QB_ARCH_MIPS], [1], [mips])
|
||||
|
||||
@ -32,12 +32,12 @@ dist_man_MANS += man3/qbipcc.h.3 man3/qbipcs.h.3 man3/qbatomic.h.3 \
|
||||
|
||||
|
||||
$(dist_man_MANS): man.dox $(dependant_headers)
|
||||
@mkdir -p man3
|
||||
@doxygen man.dox
|
||||
mkdir -p man3
|
||||
doxygen man.dox
|
||||
|
||||
doxygen: html.dox
|
||||
@mkdir -p html
|
||||
@doxygen html.dox
|
||||
mkdir -p html
|
||||
doxygen html.dox
|
||||
|
||||
else
|
||||
doxygen:
|
||||
|
||||
@ -32,7 +32,6 @@ IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
@ -108,7 +107,6 @@ HTML_HEADER =
|
||||
HTML_FOOTER =
|
||||
HTML_TIMESTAMP = NO
|
||||
HTML_STYLESHEET =
|
||||
HTML_ALIGN_MEMBERS = YES
|
||||
HTML_DYNAMIC_SECTIONS = NO
|
||||
GENERATE_DOCSET = NO
|
||||
DOCSET_FEEDNAME = "Doxygen generated docs"
|
||||
@ -131,7 +129,6 @@ QHG_LOCATION =
|
||||
DISABLE_INDEX = NO
|
||||
ENUM_VALUES_PER_LINE = 4
|
||||
GENERATE_TREEVIEW = NO
|
||||
USE_INLINE_TREES = NO
|
||||
TREEVIEW_WIDTH = 250
|
||||
FORMULA_FONTSIZE = 10
|
||||
SEARCHENGINE = YES
|
||||
@ -188,7 +185,7 @@ CLASS_DIAGRAMS = YES
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = YES
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTNAME =
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = YES
|
||||
|
||||
@ -32,7 +32,6 @@ IDL_PROPERTY_SUPPORT = NO
|
||||
DISTRIBUTE_GROUP_DOC = YES
|
||||
SUBGROUPING = NO
|
||||
TYPEDEF_HIDES_STRUCT = YES
|
||||
SYMBOL_CACHE_SIZE = 0
|
||||
EXTRACT_ALL = YES
|
||||
EXTRACT_PRIVATE = NO
|
||||
EXTRACT_STATIC = YES
|
||||
@ -136,7 +135,7 @@ CLASS_DIAGRAMS = NO
|
||||
MSCGEN_PATH =
|
||||
HIDE_UNDOC_RELATIONS = YES
|
||||
HAVE_DOT = NO
|
||||
DOT_FONTNAME = FreeSans
|
||||
DOT_FONTNAME =
|
||||
DOT_FONTSIZE = 10
|
||||
DOT_FONTPATH =
|
||||
CLASS_GRAPH = NO
|
||||
|
||||
@ -182,7 +182,7 @@ show_usage(const char *name)
|
||||
|
||||
#ifdef HAVE_GLIB
|
||||
struct gio_to_qb_poll {
|
||||
gboolean is_used;
|
||||
int32_t is_used;
|
||||
int32_t events;
|
||||
int32_t source;
|
||||
int32_t fd;
|
||||
@ -205,14 +205,17 @@ gio_poll_destroy(gpointer data)
|
||||
{
|
||||
struct gio_to_qb_poll *adaptor = (struct gio_to_qb_poll *)data;
|
||||
|
||||
qb_log(LOG_DEBUG, "fd %d adaptor destroyed\n", adaptor->fd);
|
||||
adaptor->is_used = QB_FALSE;
|
||||
adaptor->fd = 0;
|
||||
adaptor->is_used--;
|
||||
if (adaptor->is_used == 0) {
|
||||
qb_log(LOG_DEBUG, "fd %d adaptor destroyed\n", adaptor->fd);
|
||||
adaptor->fd = 0;
|
||||
adaptor->source = 0;
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
my_g_dispatch_update(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn, gboolean is_new)
|
||||
{
|
||||
struct gio_to_qb_poll *adaptor;
|
||||
GIOChannel *channel;
|
||||
@ -222,8 +225,12 @@ my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
if (res < 0) {
|
||||
return res;
|
||||
}
|
||||
if (adaptor->is_used) {
|
||||
return -EEXIST;
|
||||
if (adaptor->is_used && adaptor->source) {
|
||||
if (is_new) {
|
||||
return -EEXIST;
|
||||
}
|
||||
g_source_remove(adaptor->source);
|
||||
adaptor->source = 0;
|
||||
}
|
||||
|
||||
channel = g_io_channel_unix_new(fd);
|
||||
@ -235,7 +242,7 @@ my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
adaptor->events = evts;
|
||||
adaptor->data = data;
|
||||
adaptor->p = p;
|
||||
adaptor->is_used = TRUE;
|
||||
adaptor->is_used++;
|
||||
adaptor->fd = fd;
|
||||
|
||||
adaptor->source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, evts, gio_read_socket, adaptor, gio_poll_destroy);
|
||||
@ -247,11 +254,18 @@ my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_add(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
return my_g_dispatch_update(p, fd, evts, data, fn, TRUE);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
my_g_dispatch_mod(enum qb_loop_priority p, int32_t fd, int32_t evts,
|
||||
void *data, qb_ipcs_dispatch_fn_t fn)
|
||||
{
|
||||
return 0;
|
||||
return my_g_dispatch_update(p, fd, evts, data, fn, FALSE);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
@ -260,7 +274,7 @@ my_g_dispatch_del(int32_t fd)
|
||||
struct gio_to_qb_poll *adaptor;
|
||||
if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) {
|
||||
g_source_remove(adaptor->source);
|
||||
adaptor->is_used = FALSE;
|
||||
adaptor->source = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -52,7 +52,7 @@ extern "C" {
|
||||
* You must not directly read integers or pointers concurrently
|
||||
* accessed by multiple threads, but use the atomic accessor functions
|
||||
* instead. That is, always use qb_atomic_int_get() and qb_atomic_pointer_get()
|
||||
* for read outs. They provide the neccessary synchonization mechanisms
|
||||
* for read outs. They provide the necessary synchonization mechanisms
|
||||
* like memory barriers to access memory locations concurrently.
|
||||
*
|
||||
* If you are using those functions for anything apart from
|
||||
|
||||
@ -31,6 +31,11 @@ extern "C" {
|
||||
#endif
|
||||
/* *INDENT-ON* */
|
||||
|
||||
/**
|
||||
* @file qbipc_common.h
|
||||
* common types and definitions
|
||||
*/
|
||||
|
||||
struct qb_ipc_request_header {
|
||||
int32_t id __attribute__ ((aligned(8)));
|
||||
int32_t size __attribute__ ((aligned(8)));
|
||||
|
||||
@ -237,7 +237,7 @@ int32_t qb_ipcs_run(qb_ipcs_service_t* s);
|
||||
void qb_ipcs_destroy(qb_ipcs_service_t* s);
|
||||
|
||||
/**
|
||||
* Limit the incomming request rate.
|
||||
* Limit the incoming request rate.
|
||||
* @param s service instance
|
||||
* @param rl the new rate
|
||||
*/
|
||||
@ -245,7 +245,7 @@ void qb_ipcs_request_rate_limit(qb_ipcs_service_t* s,
|
||||
enum qb_ipcs_rate_limit rl);
|
||||
|
||||
/**
|
||||
* Send a response to a incomming request.
|
||||
* Send a response to a incoming request.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param data the message to send
|
||||
@ -260,7 +260,7 @@ ssize_t qb_ipcs_response_send(qb_ipcs_connection_t *c, const void *data,
|
||||
size_t size);
|
||||
|
||||
/**
|
||||
* Send a response to a incomming request.
|
||||
* Send a response to a incoming request.
|
||||
*
|
||||
* @param c connection instance
|
||||
* @param iov the iovec struct that points to the message to send
|
||||
|
||||
@ -363,18 +363,30 @@ void qb_log_from_external_source_va(const char *function,
|
||||
*/
|
||||
#define qb_log(priority, fmt, args...) qb_logt(priority, 0, fmt, ##args)
|
||||
|
||||
/* Define the character used to mark the beginning of "extended" information;
|
||||
* a string equivalent is also defined so clients can use it like:
|
||||
* qb_log(level, "blah blah "QB_XS" yada yada", __func__);
|
||||
*/
|
||||
#define QB_XC '\a'
|
||||
#define QB_XS "\a"
|
||||
|
||||
/**
|
||||
* This is similar to perror except it goes into the logging system.
|
||||
*
|
||||
* @param priority this takes syslog priorities.
|
||||
* @param fmt usual printf style format specifiers
|
||||
* @param args usual printf style args
|
||||
*
|
||||
* @note Because qb_perror() adds the system error message and error number onto
|
||||
* the end of the given fmt, that information will become extended
|
||||
* information if QB_XS is used inside fmt and will not show up in any
|
||||
* logs that strip extended information.
|
||||
*/
|
||||
#ifndef S_SPLINT_S
|
||||
#define qb_perror(priority, fmt, args...) do { \
|
||||
char _perr_buf_[QB_LOG_STRERROR_MAX_LEN]; \
|
||||
const char *_perr_str_ = qb_strerror_r(errno, _perr_buf_, sizeof(_perr_buf_)); \
|
||||
qb_logt(priority, 0, fmt ": %s (%d)", ##args, _perr_str_, errno); \
|
||||
qb_logt(priority, 0, fmt ": %s (%d)", ##args, _perr_str_, errno); \
|
||||
} while(0)
|
||||
#else
|
||||
#define qb_perror
|
||||
@ -405,6 +417,7 @@ enum qb_log_conf {
|
||||
QB_LOG_CONF_PRIORITY_BUMP,
|
||||
QB_LOG_CONF_STATE_GET,
|
||||
QB_LOG_CONF_FILE_SYNC,
|
||||
QB_LOG_CONF_EXTENDED,
|
||||
};
|
||||
|
||||
enum qb_log_filter_type {
|
||||
|
||||
@ -36,10 +36,10 @@ extern "C" {
|
||||
|
||||
/**
|
||||
* @file qbutil.h
|
||||
* @author Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* These are some convience functions used throughout libqb.
|
||||
*
|
||||
* @author Angus Salkeld <asalkeld@redhat.com>
|
||||
*
|
||||
* @par Locking
|
||||
* - qb_thread_lock_create()
|
||||
* - qb_thread_lock()
|
||||
|
||||
@ -29,7 +29,7 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include
|
||||
|
||||
lib_LTLIBRARIES = libqb.la
|
||||
|
||||
libqb_la_LDFLAGS = -version-number 0:17:1
|
||||
libqb_la_LDFLAGS = -version-info 17:2:17
|
||||
|
||||
source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \
|
||||
array.c loop.c loop_poll.c loop_job.c \
|
||||
|
||||
@ -159,7 +159,7 @@ enum qb_ipcs_connection_state {
|
||||
QB_IPCS_CONNECTION_SHUTTING_DOWN,
|
||||
};
|
||||
|
||||
#define CONNECTION_DESCRIPTION (16)
|
||||
#define CONNECTION_DESCRIPTION (34) /* INT_MAX length + 3 */
|
||||
|
||||
struct qb_ipcs_connection_auth {
|
||||
uid_t uid;
|
||||
|
||||
239
lib/ipc_setup.c
239
lib/ipc_setup.c
@ -48,6 +48,24 @@ struct ipc_auth_ugp {
|
||||
pid_t pid;
|
||||
};
|
||||
|
||||
struct ipc_auth_data {
|
||||
int32_t sock;
|
||||
struct qb_ipcs_service *s;
|
||||
struct qb_ipc_connection_request msg;
|
||||
struct msghdr msg_recv;
|
||||
struct iovec iov_recv;
|
||||
struct ipc_auth_ugp ugp;
|
||||
|
||||
size_t processed;
|
||||
size_t len;
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
char *cmsg_cred;
|
||||
#endif
|
||||
|
||||
};
|
||||
|
||||
|
||||
static int32_t qb_ipcs_us_connection_acceptor(int fd, int revent, void *data);
|
||||
|
||||
ssize_t
|
||||
@ -83,20 +101,21 @@ retry_send:
|
||||
}
|
||||
|
||||
static ssize_t
|
||||
qb_ipc_us_recv_msghdr(int32_t s, struct msghdr *hdr, char *msg, size_t len)
|
||||
qb_ipc_us_recv_msghdr(struct ipc_auth_data *data)
|
||||
{
|
||||
char *msg = (char *) &data->msg;
|
||||
int32_t result;
|
||||
int32_t processed = 0;
|
||||
|
||||
qb_sigpipe_ctl(QB_SIGPIPE_IGNORE);
|
||||
|
||||
retry_recv:
|
||||
hdr->msg_iov->iov_base = &msg[processed];
|
||||
hdr->msg_iov->iov_len = len - processed;
|
||||
data->msg_recv.msg_iov->iov_base = &msg[data->processed];
|
||||
data->msg_recv.msg_iov->iov_len = data->len - data->processed;
|
||||
|
||||
result = recvmsg(s, hdr, MSG_NOSIGNAL | MSG_WAITALL);
|
||||
result = recvmsg(data->sock, &data->msg_recv, MSG_NOSIGNAL | MSG_WAITALL);
|
||||
if (result == -1 && errno == EAGAIN) {
|
||||
goto retry_recv;
|
||||
qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
|
||||
return -EAGAIN;
|
||||
}
|
||||
if (result == -1) {
|
||||
qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
|
||||
@ -105,18 +124,18 @@ retry_recv:
|
||||
if (result == 0) {
|
||||
qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
|
||||
qb_util_log(LOG_DEBUG,
|
||||
"recv(fd %d) got 0 bytes assuming ENOTCONN", s);
|
||||
"recv(fd %d) got 0 bytes assuming ENOTCONN", data->sock);
|
||||
return -ENOTCONN;
|
||||
}
|
||||
|
||||
processed += result;
|
||||
if (processed != len) {
|
||||
data->processed += result;
|
||||
if (data->processed != data->len) {
|
||||
goto retry_recv;
|
||||
}
|
||||
qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT);
|
||||
assert(processed == len);
|
||||
assert(data->processed == data->len);
|
||||
|
||||
return processed;
|
||||
return data->processed;
|
||||
}
|
||||
|
||||
int32_t
|
||||
@ -434,6 +453,7 @@ qb_ipcs_us_withdraw(struct qb_ipcs_service * s)
|
||||
(void)s->poll_fns.dispatch_del(s->server_sock);
|
||||
shutdown(s->server_sock, SHUT_RDWR);
|
||||
close(s->server_sock);
|
||||
s->server_sock = -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -541,45 +561,56 @@ send_response:
|
||||
return res;
|
||||
}
|
||||
|
||||
static int32_t
|
||||
qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
|
||||
struct ipc_auth_ugp *ugp)
|
||||
static void
|
||||
destroy_ipc_auth_data(struct ipc_auth_data *data)
|
||||
{
|
||||
if (data->s) {
|
||||
qb_ipcs_unref(data->s);
|
||||
}
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
free(data->cmsg_cred);
|
||||
#endif
|
||||
free(data);
|
||||
}
|
||||
|
||||
static int32_t
|
||||
process_auth(int32_t fd, int32_t revents, void *d)
|
||||
{
|
||||
struct ipc_auth_data *data = (struct ipc_auth_data *) d;
|
||||
|
||||
int32_t res = 0;
|
||||
struct msghdr msg_recv;
|
||||
struct iovec iov_recv;
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
char cmsg_cred[CMSG_SPACE(sizeof(struct ucred))];
|
||||
int off = 0;
|
||||
int on = 1;
|
||||
#endif
|
||||
msg_recv.msg_iov = &iov_recv;
|
||||
msg_recv.msg_iovlen = 1;
|
||||
msg_recv.msg_name = 0;
|
||||
msg_recv.msg_namelen = 0;
|
||||
#ifdef SO_PASSCRED
|
||||
msg_recv.msg_control = (void *)cmsg_cred;
|
||||
msg_recv.msg_controllen = sizeof(cmsg_cred);
|
||||
#endif
|
||||
#ifdef QB_SOLARIS
|
||||
msg_recv.msg_accrights = 0;
|
||||
msg_recv.msg_accrightslen = 0;
|
||||
#else
|
||||
msg_recv.msg_flags = 0;
|
||||
#endif /* QB_SOLARIS */
|
||||
|
||||
iov_recv.iov_base = msg;
|
||||
iov_recv.iov_len = len;
|
||||
#ifdef SO_PASSCRED
|
||||
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
res = qb_ipc_us_recv_msghdr(sock, &msg_recv, msg, len);
|
||||
if (res < 0) {
|
||||
if (data->s->server_sock == -1) {
|
||||
qb_util_log(LOG_DEBUG, "Closing fd (%d) for server shutdown", fd);
|
||||
res = -ESHUTDOWN;
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
if (res != len) {
|
||||
|
||||
if (revents & POLLNVAL) {
|
||||
qb_util_log(LOG_DEBUG, "NVAL conn fd (%d)", fd);
|
||||
res = -EINVAL;
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
if (revents & POLLHUP) {
|
||||
qb_util_log(LOG_DEBUG, "HUP conn fd (%d)", fd);
|
||||
res = -ESHUTDOWN;
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
if ((revents & POLLIN) == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = qb_ipc_us_recv_msghdr(data);
|
||||
if (res == -EAGAIN) {
|
||||
/* yield to mainloop, Let mainloop call us again */
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (res != data->len) {
|
||||
res = -EIO;
|
||||
goto cleanup_and_return;
|
||||
}
|
||||
@ -595,11 +626,11 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
|
||||
{
|
||||
ucred_t *uc = NULL;
|
||||
|
||||
if (getpeerucred(sock, &uc) == 0) {
|
||||
if (getpeerucred(data->sock, &uc) == 0) {
|
||||
res = 0;
|
||||
ugp->uid = ucred_geteuid(uc);
|
||||
ugp->gid = ucred_getegid(uc);
|
||||
ugp->pid = ucred_getpid(uc);
|
||||
data->ugp.uid = ucred_geteuid(uc);
|
||||
data->ugp.gid = ucred_getegid(uc);
|
||||
data->ugp.pid = ucred_getpid(uc);
|
||||
ucred_free(uc);
|
||||
} else {
|
||||
res = -errno;
|
||||
@ -614,7 +645,7 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
|
||||
* TODO get the peer's pid.
|
||||
* c->pid = ?;
|
||||
*/
|
||||
if (getpeereid(sock, &ugp->uid, &ugp->gid) == 0) {
|
||||
if (getpeereid(data->sock, &data->ugp.uid, &data->ugp.gid) == 0) {
|
||||
res = 0;
|
||||
} else {
|
||||
res = -errno;
|
||||
@ -630,33 +661,105 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, void *msg, size_t len,
|
||||
struct cmsghdr *cmsg;
|
||||
|
||||
res = -EINVAL;
|
||||
for (cmsg = CMSG_FIRSTHDR(&msg_recv); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&msg_recv, cmsg)) {
|
||||
for (cmsg = CMSG_FIRSTHDR(&data->msg_recv); cmsg != NULL;
|
||||
cmsg = CMSG_NXTHDR(&data->msg_recv, cmsg)) {
|
||||
if (cmsg->cmsg_type != SCM_CREDENTIALS)
|
||||
continue;
|
||||
|
||||
memcpy(&cred, CMSG_DATA(cmsg), sizeof(struct ucred));
|
||||
res = 0;
|
||||
ugp->pid = cred.pid;
|
||||
ugp->uid = cred.uid;
|
||||
ugp->gid = cred.gid;
|
||||
data->ugp.pid = cred.pid;
|
||||
data->ugp.uid = cred.uid;
|
||||
data->ugp.gid = cred.gid;
|
||||
break;
|
||||
}
|
||||
}
|
||||
#else /* no credentials */
|
||||
ugp->pid = 0;
|
||||
ugp->uid = 0;
|
||||
ugp->gid = 0;
|
||||
data->ugp.pid = 0;
|
||||
data->ugp.uid = 0;
|
||||
data->ugp.gid = 0;
|
||||
res = -ENOTSUP;
|
||||
#endif /* no credentials */
|
||||
|
||||
cleanup_and_return:
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
|
||||
setsockopt(data->sock, SOL_SOCKET, SO_PASSCRED, &off, sizeof(off));
|
||||
#endif
|
||||
|
||||
return res;
|
||||
(void)data->s->poll_fns.dispatch_del(data->sock);
|
||||
|
||||
if (res < 0) {
|
||||
close(data->sock);
|
||||
} else if (data->msg.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
|
||||
(void)handle_new_connection(data->s, res, data->sock, &data->msg, data->len, &data->ugp);
|
||||
} else {
|
||||
close(data->sock);
|
||||
}
|
||||
destroy_ipc_auth_data(data);
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static void
|
||||
qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s)
|
||||
{
|
||||
int res = 0;
|
||||
struct ipc_auth_data *data = NULL;
|
||||
#ifdef SO_PASSCRED
|
||||
int on = 1;
|
||||
#endif
|
||||
|
||||
data = calloc(1, sizeof(struct ipc_auth_data));
|
||||
if (data == NULL) {
|
||||
close(sock);
|
||||
/* -ENOMEM */
|
||||
return;
|
||||
}
|
||||
|
||||
data->s = s;
|
||||
qb_ipcs_ref(data->s);
|
||||
|
||||
data->msg_recv.msg_iov = &data->iov_recv;
|
||||
data->msg_recv.msg_iovlen = 1;
|
||||
data->msg_recv.msg_name = 0;
|
||||
data->msg_recv.msg_namelen = 0;
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
data->cmsg_cred = calloc(1,CMSG_SPACE(sizeof(struct ucred)));
|
||||
if (data->cmsg_cred == NULL) {
|
||||
close(sock);
|
||||
destroy_ipc_auth_data(data);
|
||||
/* -ENOMEM */
|
||||
return;
|
||||
}
|
||||
data->msg_recv.msg_control = (void *)data->cmsg_cred;
|
||||
data->msg_recv.msg_controllen = CMSG_SPACE(sizeof(struct ucred));
|
||||
#endif
|
||||
#ifdef QB_SOLARIS
|
||||
data->msg_recv.msg_accrights = 0;
|
||||
data->msg_recv.msg_accrightslen = 0;
|
||||
#else
|
||||
data->msg_recv.msg_flags = 0;
|
||||
#endif /* QB_SOLARIS */
|
||||
|
||||
data->len = sizeof(struct qb_ipc_connection_request);
|
||||
data->iov_recv.iov_base = &data->msg;
|
||||
data->iov_recv.iov_len = data->len;
|
||||
data->sock = sock;
|
||||
|
||||
#ifdef SO_PASSCRED
|
||||
setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on));
|
||||
#endif
|
||||
|
||||
res = s->poll_fns.dispatch_add(QB_LOOP_MED,
|
||||
data->sock,
|
||||
POLLIN | POLLPRI | POLLNVAL,
|
||||
data, process_auth);
|
||||
if (res < 0) {
|
||||
qb_util_log(LOG_DEBUG, "Failed to process AUTH for fd (%d)", data->sock);
|
||||
close(sock);
|
||||
destroy_ipc_auth_data(data);
|
||||
}
|
||||
}
|
||||
|
||||
static int32_t
|
||||
@ -666,8 +769,6 @@ qb_ipcs_us_connection_acceptor(int fd, int revent, void *data)
|
||||
int32_t new_fd;
|
||||
struct qb_ipcs_service *s = (struct qb_ipcs_service *)data;
|
||||
int32_t res;
|
||||
struct qb_ipc_connection_request setup_msg;
|
||||
struct ipc_auth_ugp ugp;
|
||||
socklen_t addrlen = sizeof(struct sockaddr_un);
|
||||
|
||||
if (revent & (POLLNVAL | POLLHUP | POLLERR)) {
|
||||
@ -707,22 +808,6 @@ retry_accept:
|
||||
return 0;
|
||||
}
|
||||
|
||||
res = qb_ipcs_uc_recv_and_auth(new_fd, &setup_msg, sizeof(setup_msg),
|
||||
&ugp);
|
||||
if (res < 0) {
|
||||
close(new_fd);
|
||||
/* This is an error, but -1 would indicate disconnect
|
||||
* from the poll loop
|
||||
*/
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (setup_msg.hdr.id == QB_IPC_MSG_AUTHENTICATE) {
|
||||
(void)handle_new_connection(s, res, new_fd, &setup_msg,
|
||||
sizeof(setup_msg), &ugp);
|
||||
} else {
|
||||
close(new_fd);
|
||||
}
|
||||
|
||||
qb_ipcs_uc_recv_and_auth(new_fd, s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -287,8 +287,36 @@ _finish_connecting(struct qb_ipc_one_way *one_way)
|
||||
static void
|
||||
qb_ipcc_us_disconnect(struct qb_ipcc_connection *c)
|
||||
{
|
||||
#if !(defined(QB_LINUX) || defined(QB_CYGWIN))
|
||||
struct sockaddr_un un_addr;
|
||||
socklen_t un_addr_len = sizeof(struct sockaddr_un);
|
||||
char *base_name;
|
||||
char sock_name[PATH_MAX];
|
||||
size_t length;
|
||||
#endif
|
||||
|
||||
munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE);
|
||||
unlink(c->request.u.us.shared_file_name);
|
||||
|
||||
#if !(defined(QB_LINUX) || defined(QB_CYGWIN))
|
||||
if (getsockname(c->response.u.us.sock, (struct sockaddr *)&un_addr, &un_addr_len) == 0) {
|
||||
length = strlen(un_addr.sun_path);
|
||||
base_name = strndup(un_addr.sun_path,length-8);
|
||||
qb_util_log(LOG_DEBUG, "unlinking socket bound files with base_name=%s length=%d",base_name,length);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"request");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"event");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"event-tx");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"response");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
}
|
||||
#endif
|
||||
qb_ipcc_us_sock_close(c->event.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->request.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
@ -629,12 +657,38 @@ _sock_rm_from_mainloop(struct qb_ipcs_connection *c)
|
||||
static void
|
||||
qb_ipcs_us_disconnect(struct qb_ipcs_connection *c)
|
||||
{
|
||||
#if !(defined(QB_LINUX) || defined(QB_CYGWIN))
|
||||
struct sockaddr_un un_addr;
|
||||
socklen_t un_addr_len = sizeof(struct sockaddr_un);
|
||||
char *base_name;
|
||||
char sock_name[PATH_MAX];
|
||||
size_t length;
|
||||
#endif
|
||||
qb_enter();
|
||||
|
||||
if (c->state == QB_IPCS_CONNECTION_ESTABLISHED ||
|
||||
c->state == QB_IPCS_CONNECTION_ACTIVE) {
|
||||
_sock_rm_from_mainloop(c);
|
||||
|
||||
#if !(defined(QB_LINUX) || defined(QB_CYGWIN))
|
||||
if (getsockname(c->response.u.us.sock, (struct sockaddr *)&un_addr, &un_addr_len) == 0) {
|
||||
length = strlen(un_addr.sun_path);
|
||||
base_name = strndup(un_addr.sun_path,length-8);
|
||||
qb_util_log(LOG_DEBUG, "unlinking socket bound files with base_name=%s length=%d",base_name,length);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"request");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"event");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"event-tx");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
snprintf(sock_name,PATH_MAX,"%s-%s",base_name,"response");
|
||||
qb_util_log(LOG_DEBUG, "unlink sock_name=%s",sock_name);
|
||||
unlink(sock_name);
|
||||
}
|
||||
#endif
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->request.u.us.sock);
|
||||
qb_ipcc_us_sock_close(c->event.u.us.sock);
|
||||
|
||||
@ -81,7 +81,9 @@ qb_ipcc_connect(const char *name, size_t max_msg_size)
|
||||
return c;
|
||||
|
||||
disconnect_and_cleanup:
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
if (c->setup.u.us.sock >= 0) {
|
||||
qb_ipcc_us_sock_close(c->setup.u.us.sock);
|
||||
}
|
||||
free(c->receive_buf);
|
||||
free(c);
|
||||
errno = -res;
|
||||
|
||||
120
lib/log.c
120
lib/log.c
@ -29,6 +29,7 @@
|
||||
#include <dlfcn.h>
|
||||
#endif /* HAVE_DLFCN_H */
|
||||
#include <stdarg.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <qb/qbdefs.h>
|
||||
#include <qb/qblist.h>
|
||||
@ -157,14 +158,38 @@ _cs_matches_filter_(struct qb_log_callsite *cs,
|
||||
return match;
|
||||
}
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Format a log message into a string buffer
|
||||
*
|
||||
* @param[out] str Destination buffer to contain formatted string
|
||||
* @param[in] cs Callsite containing format to use
|
||||
* @param[in] ap Variable arguments for format
|
||||
*/
|
||||
static inline void
|
||||
cs_format(char *str, struct qb_log_callsite *cs, va_list ap)
|
||||
{
|
||||
va_list ap_copy;
|
||||
int len;
|
||||
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf(str, QB_LOG_MAX_LEN, cs->format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
if (len > QB_LOG_MAX_LEN) {
|
||||
len = QB_LOG_MAX_LEN;
|
||||
}
|
||||
if (str[len - 1] == '\n') {
|
||||
str[len - 1] = '\0';
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
qb_log_real_va_(struct qb_log_callsite *cs, va_list ap)
|
||||
{
|
||||
int32_t found_threaded;
|
||||
int32_t found_threaded = QB_FALSE;
|
||||
struct qb_log_target *t;
|
||||
struct timespec tv;
|
||||
int32_t pos;
|
||||
int len;
|
||||
int32_t formatted = QB_FALSE;
|
||||
char buf[QB_LOG_MAX_LEN];
|
||||
char *str = buf;
|
||||
@ -175,20 +200,15 @@ qb_log_real_va_(struct qb_log_callsite *cs, va_list ap)
|
||||
}
|
||||
in_logger = QB_TRUE;
|
||||
|
||||
if (old_internal_log_fn) {
|
||||
if (qb_bit_is_set(cs->tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
|
||||
if (!formatted) {
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf(str, QB_LOG_MAX_LEN, cs->format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
if (len > QB_LOG_MAX_LEN)
|
||||
len = QB_LOG_MAX_LEN;
|
||||
if (str[len - 1] == '\n') str[len - 1] = '\0';
|
||||
formatted = QB_TRUE;
|
||||
}
|
||||
old_internal_log_fn(cs->filename, cs->lineno,
|
||||
cs->priority, str);
|
||||
if (old_internal_log_fn &&
|
||||
qb_bit_is_set(cs->tags, QB_LOG_TAG_LIBQB_MSG_BIT)) {
|
||||
if (formatted == QB_FALSE) {
|
||||
cs_format(str, cs, ap);
|
||||
formatted = QB_TRUE;
|
||||
}
|
||||
qb_do_extended(str, QB_TRUE,
|
||||
old_internal_log_fn(cs->filename, cs->lineno,
|
||||
cs->priority, str));
|
||||
}
|
||||
|
||||
qb_util_timespec_from_epoch_get(&tv);
|
||||
@ -197,45 +217,31 @@ qb_log_real_va_(struct qb_log_callsite *cs, va_list ap)
|
||||
* 1 if we can find a threaded target that needs this log then post it
|
||||
* 2 foreach non-threaded target call it's logger function
|
||||
*/
|
||||
found_threaded = QB_FALSE;
|
||||
|
||||
for (pos = 0; pos <= conf_active_max; pos++) {
|
||||
t = &conf[pos];
|
||||
if (t->state != QB_LOG_STATE_ENABLED) {
|
||||
continue;
|
||||
}
|
||||
if (t->threaded) {
|
||||
if (!found_threaded
|
||||
&& qb_bit_is_set(cs->targets, t->pos)) {
|
||||
found_threaded = QB_TRUE;
|
||||
if (!formatted) {
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf(str, QB_LOG_MAX_LEN, cs->format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
if (len > QB_LOG_MAX_LEN)
|
||||
len = QB_LOG_MAX_LEN;
|
||||
if (str[len - 1] == '\n') str[len - 1] = '\0';
|
||||
formatted = QB_TRUE;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (qb_bit_is_set(cs->targets, t->pos)) {
|
||||
if (t->vlogger) {
|
||||
va_copy(ap_copy, ap);
|
||||
t->vlogger(t->pos, cs, tv.tv_sec, ap_copy);
|
||||
va_end(ap_copy);
|
||||
} else if (t->logger) {
|
||||
if (!formatted) {
|
||||
va_copy(ap_copy, ap);
|
||||
len = vsnprintf(str, QB_LOG_MAX_LEN, cs->format, ap_copy);
|
||||
va_end(ap_copy);
|
||||
if (len > QB_LOG_MAX_LEN)
|
||||
len = QB_LOG_MAX_LEN;
|
||||
if (str[len - 1] == '\n') str[len - 1] = '\0';
|
||||
if ((t->state == QB_LOG_STATE_ENABLED)
|
||||
&& qb_bit_is_set(cs->targets, pos)) {
|
||||
if (t->threaded) {
|
||||
if (!found_threaded) {
|
||||
found_threaded = QB_TRUE;
|
||||
if (formatted == QB_FALSE) {
|
||||
cs_format(str, cs, ap);
|
||||
formatted = QB_TRUE;
|
||||
}
|
||||
t->logger(t->pos, cs, tv.tv_sec, str);
|
||||
}
|
||||
|
||||
} else if (t->vlogger) {
|
||||
va_copy(ap_copy, ap);
|
||||
t->vlogger(t->pos, cs, tv.tv_sec, ap_copy);
|
||||
va_end(ap_copy);
|
||||
|
||||
} else if (t->logger) {
|
||||
if (formatted == QB_FALSE) {
|
||||
cs_format(str, cs, ap);
|
||||
formatted = QB_TRUE;
|
||||
}
|
||||
qb_do_extended(str, t->extended,
|
||||
t->logger(t->pos, cs, tv.tv_sec, str));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -265,14 +271,10 @@ qb_log_thread_log_write(struct qb_log_callsite *cs,
|
||||
|
||||
for (pos = 0; pos <= conf_active_max; pos++) {
|
||||
t = &conf[pos];
|
||||
if (t->state != QB_LOG_STATE_ENABLED) {
|
||||
continue;
|
||||
}
|
||||
if (!t->threaded) {
|
||||
continue;
|
||||
}
|
||||
if (qb_bit_is_set(cs->targets, t->pos)) {
|
||||
t->logger(t->pos, cs, timestamp, buffer);
|
||||
if ((t->state == QB_LOG_STATE_ENABLED) && t->threaded
|
||||
&& qb_bit_is_set(cs->targets, t->pos)) {
|
||||
qb_do_extended(buffer, t->extended,
|
||||
t->logger(t->pos, cs, timestamp, buffer));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -810,6 +812,7 @@ qb_log_init(const char *name, int32_t facility, uint8_t priority)
|
||||
conf[i].pos = i;
|
||||
conf[i].debug = QB_FALSE;
|
||||
conf[i].file_sync = QB_FALSE;
|
||||
conf[i].extended = QB_TRUE;
|
||||
conf[i].state = QB_LOG_STATE_UNUSED;
|
||||
(void)strlcpy(conf[i].name, name, PATH_MAX);
|
||||
conf[i].facility = facility;
|
||||
@ -1064,6 +1067,9 @@ qb_log_ctl(int32_t t, enum qb_log_conf c, int32_t arg)
|
||||
case QB_LOG_CONF_THREADED:
|
||||
conf[t].threaded = arg;
|
||||
break;
|
||||
case QB_LOG_CONF_EXTENDED:
|
||||
conf[t].extended = arg;
|
||||
break;
|
||||
|
||||
default:
|
||||
rc = -EINVAL;
|
||||
|
||||
@ -460,12 +460,22 @@ qb_vsnprintf_serialize(char *serialize, size_t max_len,
|
||||
{
|
||||
char *format;
|
||||
char *p;
|
||||
char *qb_xc;
|
||||
int type_long = QB_FALSE;
|
||||
int type_longlong = QB_FALSE;
|
||||
int sformat_length = 0;
|
||||
int sformat_precision = QB_FALSE;
|
||||
uint32_t location = my_strlcpy(serialize, fmt, max_len) + 1;
|
||||
|
||||
/* Assume serialized output always wants extended information
|
||||
* (@todo: add variant of this function that takes argument for whether
|
||||
* to print extended information, and make this a macro with that
|
||||
* argument set to QB_TRUE, so callers can honor extended setting)
|
||||
*/
|
||||
if ((qb_xc = strchr(serialize, QB_XC)) != NULL) {
|
||||
*qb_xc = *(qb_xc + 1)? '|' : '\0';
|
||||
}
|
||||
|
||||
format = (char *)fmt;
|
||||
for (;;) {
|
||||
type_long = QB_FALSE;
|
||||
|
||||
@ -38,6 +38,7 @@ struct qb_log_target {
|
||||
int32_t priority_bump;
|
||||
int32_t file_sync;
|
||||
int32_t debug;
|
||||
int32_t extended;
|
||||
size_t size;
|
||||
char *format;
|
||||
int32_t threaded;
|
||||
@ -70,6 +71,36 @@ struct qb_log_record {
|
||||
|
||||
#define TIME_STRING_SIZE 64
|
||||
|
||||
/**
|
||||
* @internal
|
||||
* @brief Call a log function, handling any extended information marker
|
||||
*
|
||||
* If the string to be passed to the log function contains an extended
|
||||
* information marker, temporarily modify the string to strip the extended
|
||||
* information if appropriate. Special cases: if a marker occurs with nothing
|
||||
* after it, it will always be stripped; if only extended information is
|
||||
* present, stmt will be called only if extended is true.
|
||||
*
|
||||
* @param[in] str Null-terminated log message
|
||||
* @param[in] extended QB_TRUE if extended information should be printed
|
||||
* @param[in] stmt Code block to call log function
|
||||
*
|
||||
* @note Because this is a macro, none of the arguments other than stmt should
|
||||
* have side effects.
|
||||
*/
|
||||
#define qb_do_extended(str, extended, stmt) do { \
|
||||
char *qb_xc = strchr((str), QB_XC); \
|
||||
if (qb_xc) { \
|
||||
if ((qb_xc != (str)) || (extended)) { \
|
||||
*qb_xc = ((extended) && *(qb_xc + 1))? '|' : '\0'; \
|
||||
stmt; \
|
||||
*qb_xc = QB_XC; \
|
||||
} \
|
||||
} else { \
|
||||
stmt; \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
struct qb_log_target * qb_log_target_alloc(void);
|
||||
void qb_log_target_free(struct qb_log_target *t);
|
||||
struct qb_log_target * qb_log_target_get(int32_t pos);
|
||||
|
||||
@ -110,7 +110,7 @@ _poll_dispatch_and_take_back_(struct qb_loop_item *item,
|
||||
pe->item.user_data);
|
||||
if (res < 0) {
|
||||
_poll_entry_mark_deleted_(pe);
|
||||
} else {
|
||||
} else if (pe->state != QB_POLL_ENTRY_DELETED) {
|
||||
pe->state = QB_POLL_ENTRY_ACTIVE;
|
||||
pe->ufd.revents = 0;
|
||||
}
|
||||
|
||||
@ -55,7 +55,7 @@ _add(struct qb_poll_source *s, struct qb_poll_entry *pe, int32_t fd, int32_t eve
|
||||
struct kevent ke;
|
||||
short filters = _poll_to_filter_(events);
|
||||
|
||||
EV_SET(&ke, fd, filters, EV_ADD | EV_ENABLE, 0, 0, (intptr_t)pe);
|
||||
EV_SET(&ke, fd, filters, EV_ADD | EV_ENABLE, 0, 0, pe);
|
||||
|
||||
res = kevent(s->epollfd, &ke, 1, NULL, 0, NULL);
|
||||
if (res == -1) {
|
||||
@ -74,8 +74,8 @@ _mod(struct qb_poll_source *s, struct qb_poll_entry *pe, int32_t fd, int32_t eve
|
||||
short new_filters = _poll_to_filter_(events);
|
||||
short old_filters = _poll_to_filter_(pe->ufd.events);
|
||||
|
||||
EV_SET(&ke[0], fd, old_filters, EV_DELETE, 0, 0, (intptr_t)pe);
|
||||
EV_SET(&ke[1], fd, new_filters, EV_ADD | EV_ENABLE, 0, 0, (intptr_t)pe);
|
||||
EV_SET(&ke[0], fd, old_filters, EV_DELETE, 0, 0, pe);
|
||||
EV_SET(&ke[1], fd, new_filters, EV_ADD | EV_ENABLE, 0, 0, pe);
|
||||
|
||||
res = kevent(s->epollfd, ke, 2, NULL, 0, NULL);
|
||||
if (res == -1) {
|
||||
@ -92,7 +92,7 @@ _del(struct qb_poll_source *s, struct qb_poll_entry *pe, int32_t fd, int32_t eve
|
||||
struct kevent ke;
|
||||
short filters = _poll_to_filter_(events);
|
||||
|
||||
EV_SET(&ke, fd, filters, EV_DELETE, 0, 0, (intptr_t)pe);
|
||||
EV_SET(&ke, fd, filters, EV_DELETE, 0, 0, pe);
|
||||
|
||||
res = kevent(s->epollfd, &ke, 1, NULL, 0, NULL);
|
||||
if (res == -1 && errno == ENOENT) {
|
||||
@ -170,7 +170,7 @@ retry_poll:
|
||||
* empty/deleted
|
||||
*/
|
||||
EV_SET(&events[i], events[i].ident, events[i].filter,
|
||||
EV_DELETE, 0, 0, (intptr_t)pe);
|
||||
EV_DELETE, 0, 0, pe);
|
||||
(void)kevent(s->epollfd, &events[i], 1, NULL, 0, NULL);
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -138,7 +138,9 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags,
|
||||
void *shm_addr;
|
||||
long page_size = sysconf(_SC_PAGESIZE);
|
||||
|
||||
#ifdef QB_FORCE_SHM_ALIGN
|
||||
#ifdef QB_ARCH_HPPA
|
||||
page_size = QB_MAX(page_size, 0x00400000); /* align to page colour */
|
||||
#elif defined(QB_FORCE_SHM_ALIGN)
|
||||
page_size = QB_MAX(page_size, 16 * 1024);
|
||||
#endif /* QB_FORCE_SHM_ALIGN */
|
||||
/* The user of this api expects the 'size' parameter passed into this function
|
||||
|
||||
14
lib/unix.c
14
lib/unix.c
@ -170,6 +170,19 @@ qb_sys_circular_mmap(int32_t fd, void **buf, size_t bytes)
|
||||
flags |= MAP_PRIVATE;
|
||||
#endif /* QB_FORCE_SHM_ALIGN */
|
||||
|
||||
#if defined(QB_ARCH_HPPA)
|
||||
/* map twice the size we want to make sure we have already mapped
|
||||
the second memory location behind it too. Otherwise the Linux
|
||||
kernel may map it in the upper memory so that we can't map
|
||||
the second part afterwards since it will conflict. */
|
||||
addr = mmap(NULL, 2*bytes, PROT_READ | PROT_WRITE,
|
||||
MAP_SHARED, fd, 0);
|
||||
|
||||
if (addr == MAP_FAILED)
|
||||
return -errno;
|
||||
|
||||
addr_orig = addr;
|
||||
#else
|
||||
addr_orig = mmap(NULL, bytes << 1, PROT_NONE, flags, -1, 0);
|
||||
|
||||
if (addr_orig == MAP_FAILED) {
|
||||
@ -178,6 +191,7 @@ qb_sys_circular_mmap(int32_t fd, void **buf, size_t bytes)
|
||||
|
||||
addr = mmap(addr_orig, bytes, PROT_READ | PROT_WRITE,
|
||||
MAP_FIXED | MAP_SHARED, fd, 0);
|
||||
#endif
|
||||
|
||||
if (addr != addr_orig) {
|
||||
res = -errno;
|
||||
|
||||
@ -16,8 +16,9 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
|
||||
BuildRequires: autoconf automake libtool doxygen procps check-devel
|
||||
|
||||
%description
|
||||
libqb provides high performance client server reusable features.
|
||||
Initially these are IPC and poll.
|
||||
libqb provides high-performance, reusable features for client-server
|
||||
architecture, such as logging, tracing, inter-process communication (IPC),
|
||||
and polling.
|
||||
|
||||
%prep
|
||||
%setup -q -n %{name}-%{version}%{?numcomm:.%{numcomm}}%{?alphatag:-%{alphatag}}%{?dirty:-%{dirty}}
|
||||
|
||||
@ -32,7 +32,7 @@
|
||||
#include <qb/qbipcs.h>
|
||||
#include <qb/qbloop.h>
|
||||
|
||||
static const char *ipc_name = "ipc_test";
|
||||
static char ipc_name[256];
|
||||
|
||||
#define DEFAULT_MAX_MSG_SIZE (8192*16)
|
||||
static int CALCULATED_DGRAM_MAX_MSG_SIZE = 0;
|
||||
@ -94,6 +94,7 @@ static int32_t disconnect_after_created = QB_FALSE;
|
||||
static int32_t num_bulk_events = 10;
|
||||
static int32_t num_stress_events = 30000;
|
||||
static int32_t reference_count_test = QB_FALSE;
|
||||
static int32_t multiple_connections = QB_FALSE;
|
||||
|
||||
|
||||
static int32_t
|
||||
@ -104,6 +105,18 @@ exit_handler(int32_t rsignal, void *data)
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
set_ipc_name(const char *prefix)
|
||||
{
|
||||
/* We have to give the server name a random postfix because
|
||||
* some build systems attempt to generate packages for libqb
|
||||
* in parallel. These unit tests are run during the package
|
||||
* build process. Two builds executing on the same machine
|
||||
* can stomp on each other's unit tests if the ipc server
|
||||
* names aren't unique... This was very confusing to debug */
|
||||
snprintf(ipc_name, 256, "%s-%d", prefix, (int32_t)random());
|
||||
}
|
||||
|
||||
static int32_t
|
||||
s1_msg_process_fn(qb_ipcs_connection_t *c,
|
||||
void *data, size_t size)
|
||||
@ -227,6 +240,7 @@ s1_msg_process_fn(qb_ipcs_connection_t *c,
|
||||
} else if (req_pt->id == IPC_MSG_REQ_SERVER_FAIL) {
|
||||
exit(0);
|
||||
} else if (req_pt->id == IPC_MSG_REQ_SERVER_DISCONNECT) {
|
||||
multiple_connections = QB_FALSE;
|
||||
qb_ipcs_disconnect(c);
|
||||
}
|
||||
return 0;
|
||||
@ -263,6 +277,9 @@ my_dispatch_del(int32_t fd)
|
||||
static int32_t
|
||||
s1_connection_closed(qb_ipcs_connection_t *c)
|
||||
{
|
||||
if (multiple_connections) {
|
||||
return 0;
|
||||
}
|
||||
qb_enter();
|
||||
qb_leave();
|
||||
return 0;
|
||||
@ -301,6 +318,10 @@ outq_flush (void *data)
|
||||
static void
|
||||
s1_connection_destroyed(qb_ipcs_connection_t *c)
|
||||
{
|
||||
if (multiple_connections) {
|
||||
return;
|
||||
}
|
||||
|
||||
qb_enter();
|
||||
if (reference_count_test) {
|
||||
struct cs_ipcs_conn_context *cnx;
|
||||
@ -316,6 +337,9 @@ static void
|
||||
s1_connection_created(qb_ipcs_connection_t *c)
|
||||
{
|
||||
uint32_t max = MAX_MSG_SIZE;
|
||||
if (multiple_connections) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (send_event_on_created) {
|
||||
struct qb_ipc_response_header response;
|
||||
@ -698,7 +722,7 @@ START_TEST(test_ipc_exit_us)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = 5000;
|
||||
test_ipc_exit();
|
||||
qb_leave();
|
||||
@ -709,7 +733,7 @@ START_TEST(test_ipc_exit_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = 1000;
|
||||
test_ipc_exit();
|
||||
qb_leave();
|
||||
@ -720,7 +744,7 @@ START_TEST(test_ipc_txrx_shm_timeout)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_txrx_timeout();
|
||||
qb_leave();
|
||||
}
|
||||
@ -730,7 +754,7 @@ START_TEST(test_ipc_txrx_us_timeout)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_txrx_timeout();
|
||||
qb_leave();
|
||||
}
|
||||
@ -741,7 +765,7 @@ START_TEST(test_ipc_txrx_shm_tmo)
|
||||
qb_enter();
|
||||
turn_on_fc = QB_FALSE;
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = 1000;
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
@ -753,7 +777,7 @@ START_TEST(test_ipc_txrx_shm_block)
|
||||
qb_enter();
|
||||
turn_on_fc = QB_FALSE;
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = -1;
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
@ -766,7 +790,7 @@ START_TEST(test_ipc_fc_shm)
|
||||
turn_on_fc = QB_TRUE;
|
||||
ipc_type = QB_IPC_SHM;
|
||||
recv_timeout = 500;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
}
|
||||
@ -777,7 +801,7 @@ START_TEST(test_ipc_txrx_us_block)
|
||||
qb_enter();
|
||||
turn_on_fc = QB_FALSE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = -1;
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
@ -789,7 +813,7 @@ START_TEST(test_ipc_txrx_us_tmo)
|
||||
qb_enter();
|
||||
turn_on_fc = QB_FALSE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
recv_timeout = 1000;
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
@ -802,7 +826,7 @@ START_TEST(test_ipc_fc_us)
|
||||
turn_on_fc = QB_TRUE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
recv_timeout = 500;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_txrx();
|
||||
qb_leave();
|
||||
}
|
||||
@ -857,7 +881,7 @@ START_TEST(test_ipc_disp_us)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_dispatch();
|
||||
qb_leave();
|
||||
}
|
||||
@ -933,6 +957,60 @@ count_bulk_events(int32_t fd, int32_t revents, void *data)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
test_ipc_stress_connections(void)
|
||||
{
|
||||
int32_t c = 0;
|
||||
int32_t j = 0;
|
||||
uint32_t max_size = MAX_MSG_SIZE;
|
||||
int32_t connections = 0;
|
||||
pid_t pid;
|
||||
|
||||
multiple_connections = QB_TRUE;
|
||||
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_CLEAR_ALL,
|
||||
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, "*", LOG_INFO);
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
|
||||
pid = run_function_in_new_process(run_ipc_server);
|
||||
fail_if(pid == -1);
|
||||
sleep(1);
|
||||
|
||||
for (connections = 1; connections < 70000; connections++) {
|
||||
if (conn) {
|
||||
qb_ipcc_disconnect(conn);
|
||||
conn = NULL;
|
||||
}
|
||||
do {
|
||||
conn = qb_ipcc_connect(ipc_name, max_size);
|
||||
if (conn == NULL) {
|
||||
j = waitpid(pid, NULL, WNOHANG);
|
||||
ck_assert_int_eq(j, 0);
|
||||
sleep(1);
|
||||
c++;
|
||||
}
|
||||
} while (conn == NULL && c < 5);
|
||||
fail_if(conn == NULL);
|
||||
|
||||
if (((connections+1) % 1000) == 0) {
|
||||
qb_log(LOG_INFO, "%d ipc connections made", connections+1);
|
||||
}
|
||||
}
|
||||
multiple_connections = QB_FALSE;
|
||||
|
||||
request_server_exit();
|
||||
verify_graceful_stop(pid);
|
||||
qb_ipcc_disconnect(conn);
|
||||
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_CLEAR_ALL,
|
||||
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
||||
qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD,
|
||||
QB_LOG_FILTER_FILE, "*", LOG_TRACE);
|
||||
qb_log_ctl(QB_LOG_STDERR, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
test_ipc_bulk_events(void)
|
||||
{
|
||||
@ -1070,18 +1148,28 @@ START_TEST(test_ipc_stress_test_us)
|
||||
qb_enter();
|
||||
send_event_on_created = QB_FALSE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_stress_test();
|
||||
qb_leave();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ipc_stress_connections_us)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_stress_connections();
|
||||
qb_leave();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ipc_bulk_events_us)
|
||||
{
|
||||
qb_enter();
|
||||
send_event_on_created = QB_FALSE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_bulk_events();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1137,7 +1225,7 @@ START_TEST(test_ipc_event_on_created_us)
|
||||
qb_enter();
|
||||
send_event_on_created = QB_TRUE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_event_on_created();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1199,7 +1287,7 @@ START_TEST(test_ipc_disconnect_after_created_us)
|
||||
qb_enter();
|
||||
disconnect_after_created = QB_TRUE;
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_disconnect_after_created();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1238,7 +1326,7 @@ START_TEST(test_ipc_server_fail_soc)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_server_fail();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1248,7 +1336,7 @@ START_TEST(test_ipc_disp_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_dispatch();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1259,17 +1347,27 @@ START_TEST(test_ipc_stress_test_shm)
|
||||
qb_enter();
|
||||
send_event_on_created = QB_FALSE;
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_stress_test();
|
||||
qb_leave();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ipc_stress_connections_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_stress_connections();
|
||||
qb_leave();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_ipc_bulk_events_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_bulk_events();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1280,7 +1378,7 @@ START_TEST(test_ipc_event_on_created_shm)
|
||||
qb_enter();
|
||||
send_event_on_created = QB_TRUE;
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_event_on_created();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1290,7 +1388,7 @@ START_TEST(test_ipc_server_fail_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_server_fail();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1331,7 +1429,7 @@ START_TEST(test_ipc_service_ref_count_shm)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SHM;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_service_ref_count();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1341,7 +1439,7 @@ START_TEST(test_ipc_service_ref_count_us)
|
||||
{
|
||||
qb_enter();
|
||||
ipc_type = QB_IPC_SOCKET;
|
||||
ipc_name = __func__;
|
||||
set_ipc_name(__func__);
|
||||
test_ipc_service_ref_count();
|
||||
qb_leave();
|
||||
}
|
||||
@ -1439,6 +1537,11 @@ make_shm_suite(void)
|
||||
tcase_set_timeout(tc, 10);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("ipc_stress_connections_shm");
|
||||
tcase_add_test(tc, test_ipc_stress_connections_shm);
|
||||
tcase_set_timeout(tc, 200);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1513,6 +1616,11 @@ make_soc_suite(void)
|
||||
tcase_set_timeout(tc, 10);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("ipc_stress_connections_us");
|
||||
tcase_add_test(tc, test_ipc_stress_connections_us);
|
||||
tcase_set_timeout(tc, 200);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
@ -1524,6 +1632,7 @@ main(void)
|
||||
Suite *s;
|
||||
int32_t do_shm_tests = QB_TRUE;
|
||||
|
||||
set_ipc_name("ipc_test");
|
||||
#ifdef DISABLE_IPC_SHM
|
||||
do_shm_tests = QB_FALSE;
|
||||
#endif /* DISABLE_IPC_SHM */
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2011 Red Hat, Inc.
|
||||
* Copyright (c) 2011-2015 Red Hat, Inc.
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
@ -708,6 +708,63 @@ START_TEST(test_threaded_logging)
|
||||
}
|
||||
END_TEST
|
||||
|
||||
START_TEST(test_extended_information)
|
||||
{
|
||||
int32_t t;
|
||||
int32_t rc;
|
||||
int extended;
|
||||
|
||||
qb_log_init("test", LOG_USER, LOG_DEBUG);
|
||||
qb_log_ctl(QB_LOG_SYSLOG, QB_LOG_CONF_ENABLED, QB_FALSE);
|
||||
|
||||
t = qb_log_custom_open(_test_logger, NULL, NULL, NULL);
|
||||
_ck_assert_int(t, >, QB_LOG_STDOUT);
|
||||
qb_log_format_set(t, "%b");
|
||||
rc = qb_log_filter_fn_set(NULL);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FILE,
|
||||
"*", LOG_TRACE);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_CLEAR_ALL, QB_LOG_FILTER_FORMAT,
|
||||
"*", LOG_TRACE);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
rc = qb_log_filter_ctl(t, QB_LOG_FILTER_ADD, QB_LOG_FILTER_FORMAT,
|
||||
"*", LOG_TRACE);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
rc = qb_log_ctl(t, QB_LOG_CONF_ENABLED, QB_TRUE);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
|
||||
for (extended = QB_FALSE; extended <= QB_TRUE; ++extended) {
|
||||
rc = qb_log_ctl(t, QB_LOG_CONF_EXTENDED, extended);
|
||||
ck_assert_int_eq(rc, 0);
|
||||
|
||||
num_msgs = 0;
|
||||
|
||||
memset(test_buf, 0, sizeof(test_buf));
|
||||
qb_log(LOG_ERR, "message with no extended information");
|
||||
ck_assert_str_eq(test_buf, "message with no extended information");
|
||||
|
||||
memset(test_buf, 0, sizeof(test_buf));
|
||||
qb_log(LOG_ERR, "message with empty extended information "QB_XS);
|
||||
ck_assert_str_eq(test_buf, "message with empty extended information ");
|
||||
|
||||
memset(test_buf, 0, sizeof(test_buf));
|
||||
qb_log(LOG_ERR, QB_XS" message with only extended information");
|
||||
ck_assert_str_eq(test_buf, extended?
|
||||
"| message with only extended information" : "");
|
||||
|
||||
memset(test_buf, 0, sizeof(test_buf));
|
||||
qb_log(LOG_ERR, "message with extended information "QB_XS" (namely this)");
|
||||
ck_assert_str_eq(test_buf, extended?
|
||||
"message with extended information | (namely this)"
|
||||
: "message with extended information ");
|
||||
|
||||
ck_assert_int_eq(num_msgs, (extended? 4 : 3));
|
||||
}
|
||||
qb_log_fini();
|
||||
}
|
||||
END_TEST
|
||||
|
||||
static Suite *
|
||||
log_suite(void)
|
||||
{
|
||||
@ -751,6 +808,10 @@ log_suite(void)
|
||||
tcase_add_test(tc, test_threaded_logging);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
tc = tcase_create("extended_information");
|
||||
tcase_add_test(tc, test_extended_information);
|
||||
suite_add_tcase(s, tc);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user