Imported Upstream version 0.17.2

This commit is contained in:
Christoph Berg 2015-09-07 15:07:05 +02:00
parent 2b262fd5db
commit 37c156628d
28 changed files with 625 additions and 219 deletions

2
.gitignore vendored
View File

@ -6,6 +6,7 @@
*.so.*
*.3
*.rpm
*.swp
*.pc
*.log
Makefile
@ -27,3 +28,4 @@ abi_dumps
TAGS
*~
test-driver
tests/*.trs

View File

@ -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

View File

@ -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.
[![Build Status](https://travis-ci.org/ClusterLabs/libqb.png)](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.

View File

@ -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])

View File

@ -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:

View File

@ -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

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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)));

View File

@ -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

View File

@ -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 {

View File

@ -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()

View File

@ -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 \

View File

@ -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;

View File

@ -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;
}

View File

@ -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);

View File

@ -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
View File

@ -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;

View File

@ -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;

View File

@ -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);

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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

View File

@ -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;

View File

@ -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}}

View File

@ -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 */

View File

@ -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;
}