Hello community, here is the log from the commit of package libqb for openSUSE:Factory checked in at 2013-08-04 20:39:33 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/libqb (Old) and /work/SRC/openSUSE:Factory/.libqb.new (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "libqb" Changes: -------- --- /work/SRC/openSUSE:Factory/libqb/libqb.changes 2013-07-08 07:18:12.000000000 +0200 +++ /work/SRC/openSUSE:Factory/.libqb.new/libqb.changes 2013-08-04 23:52:27.000000000 +0200 @@ -1,0 +2,27 @@ +Fri Jul 26 01:19:30 UTC 2013 - [email protected] + +- Bump version to 0.16.0 +- ipc_socket.c: Detect EOF connection on connection STREAM socket +- ipc_socket.c: Handle the unlikely event of an EAGAIN or EINTR during dgram max size detection +- Fixes sem leak +- Fixes less-than-zero comparision of unsigned int +- Fixes double fd close +- Fixes fd leak +- Fixes use ater free in shm disconnect +- Fixes use after free during ipcs client disconnect +- ipcc: Add abilty to verify dgram kernel buffer size meets max msg value +- Upstream version cs: 75f7ed373758b3cb9087e89e4fae17379dd7b483 (v0.16.0) + +------------------------------------------------------------------- +Mon Jul 22 07:38:56 UTC 2013 - [email protected] + +- ringbuffer: Make max_size of ringbuffer accurate so shm ipc max msg size value is honored +- ipcs: For shm ipc, always retry outstanding notifications when next event is sent +- ipc_socket: In fbsd send() returns ENOBUFS when dgram queue is full, this should be treated similar to EAGAIN +- kqueue: Properly enable kqueue filter in poll loop +- ipcs: Attempt to resend outstanding event notifications during event send +- ipcs: Disconnect shm ipc connection when poll socket returns error on msg receive +- ipcs: Properly disconnect client connection on POLLNVAL or any other error causing connection removal from mainloop. +- Upstream version cs: 39e9ef542dc89893c7c5af4fbd539338266e8031 + +------------------------------------------------------------------- ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ libqb.spec ++++++ --- /var/tmp/diff_new_pack.11ZHls/_old 2013-08-04 23:52:28.000000000 +0200 +++ /var/tmp/diff_new_pack.11ZHls/_new 2013-08-04 23:52:28.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package libqb # -# Copyright (c) 2012 SUSE LINUX Products GmbH, Nuernberg, Germany. +# Copyright (c) 2013 SUSE LINUX Products GmbH, Nuernberg, Germany. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -17,12 +17,12 @@ Name: libqb -Version: 0.14.4 +Version: 0.16.0 Release: 0 Summary: An IPC library for high performance servers License: LGPL-2.1+ Group: System/Libraries -Url: http://www.libqb.org +Url: https://github.com/ClusterLabs/libqb Source0: %{name}.tar.bz2 BuildRoot: %{_tmppath}/%{name}-%{version}-build @@ -31,8 +31,8 @@ BuildRequires: check-devel BuildRequires: doxygen BuildRequires: libtool -BuildRequires: procps BuildRequires: pkgconfig +BuildRequires: procps # Need git so build-aux/git-version-gen can extract the version number and # commit hash during autogen run (not used currently) #BuildRequires: git @@ -44,7 +44,6 @@ %package -n libqb0 Summary: An IPC library for high performance servers -License: LGPL-2.1+ Group: System/Libraries Provides: %{name} = %{version} @@ -55,7 +54,6 @@ %package devel Summary: Development files for %{name} -License: LGPL-2.1+ Group: Development/Libraries/C and C++ Requires: %{name} = %{version}-%{release} Requires: pkgconfig @@ -69,7 +67,7 @@ %setup -q -n %{name} %build -#./autogen.sh +./autogen.sh %configure --disable-static make %{?_smp_mflags} ++++++ _service ++++++ --- /var/tmp/diff_new_pack.11ZHls/_old 2013-08-04 23:52:28.000000000 +0200 +++ /var/tmp/diff_new_pack.11ZHls/_new 2013-08-04 23:52:28.000000000 +0200 @@ -7,8 +7,8 @@ To update to a new release, change "revision" to the desired git commit hash and bump "version" if necessary --> - <param name="version">0.14.4</param> - <param name="revision">7c6e109046ec772a97a7fe2cdf61f84fc2155b7e</param> + <param name="version">0.16.0</param> + <param name="revision">75f7ed373758b3cb9087e89e4fae17379dd7b483</param> </service> <service name="recompress" mode="disabled"> ++++++ libqb.tar.bz2 ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/.tarball-version new/libqb/.tarball-version --- old/libqb/.tarball-version 2013-07-02 11:28:45.000000000 +0200 +++ new/libqb/.tarball-version 2013-07-26 03:10:21.000000000 +0200 @@ -1 +1 @@ -0.14.4.53-7c6e +0.16.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/.version new/libqb/.version --- old/libqb/.version 2012-06-07 11:27:48.000000000 +0200 +++ new/libqb/.version 2013-07-26 03:10:02.000000000 +0200 @@ -1 +1 @@ -0.13.0.51-e70e +0.16.0 diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/ChangeLog new/libqb/ChangeLog --- old/libqb/ChangeLog 2013-07-02 11:28:45.000000000 +0200 +++ new/libqb/ChangeLog 2013-07-26 03:10:21.000000000 +0200 @@ -1,7 +1,146 @@ -2013-06-29 David Vossel <[email protected]> +2013-07-26 David Vossel <[email protected]> - Merge pull request #73 from davidvossel/ref_count_cleanup - cleanup connection and service ref counting without changing behavior + Bump version to 0.16.0 ... do not use version 0.15.0 + The use of version-info conflicted with the naming + convention used to represent libqb version numbers. Because + of this the shared library file used for release 0.15.0 + did not properly match the release version. From now on + the version number will be manually set to guarantee consistency + between .so file and release version. + + Update release gpg sign key + +2013-07-25 David Vossel <[email protected]> + + Bump the version to 0.15.0 + +2013-07-24 David Vossel <[email protected]> + + Merge pull request #83 from davidvossel/master + socket ipc fixes + + Low: ipc_socket: Output send event failure as debug instead of error + + Low: ipcserver.c: Fix example server's glib mainloop implementation + + High: ipc_socket.c: Detect EOF connection on connection STREAM socket + +2013-07-23 David Vossel <[email protected]> + + Merge pull request #81 from davidvossel/dgram_max_msg + Added ability to estimate kernel's actual max dgram buffer size in a portable way. + + Low: tests: Add dgram max size detection test + + Low: ipc_socket.c: Handle the unlikely event of an EAGAIN or EINTR during dgram max size detection + + Merge pull request #82 from davidvossel/master + coverity fixes + + Fixes detect disconnect on send for tcp example + + Fixes sem leak + + Fixes less-than-zero comparision of unsigned int + + fixes double close + + Fixes double close + + Fixes double fd close + + Fixes fd leak + + Prevent use after free in benchmark util + + Fixes use ater free in shm disconnect + + Fixes use after free during ipcs client disconnect + + Remove dead code + +2013-07-20 David Vossel <[email protected]> + + Low: check_ipc.c: Verify dgram max size during tests + + High: ipcc: Add abilty to verify dgram kernel buffer size meets max msg value + + Fixes travis build error + +2013-07-19 David Vossel <[email protected]> + + Merge pull request #80 from davidvossel/master + Fixes travis build error + + Low: check_ipc.c: fix debug message to only display once. + + High: ringbuffer: Make max_size of ringbuffer accurate so shm ipc max msg size value is honored + + Low: ipcs: For shm ipc, always retry outstanding notifications when next event is sent + + Low: tests: Added test to verify sending ipc msg equal to max size succeeds + + Merge pull request #79 from davidvossel/master + fix shared memory ipc so max msg size is honored correctly + +2013-07-13 David Vossel <[email protected]> + + Merge pull request #78 from davidvossel/master + fixes travis compile time issue + + Fix: ipcs: Fixes compile time issue reported by travis + + Merge pull request #77 from davidvossel/stress_tests_fixes + Adds new ipc event stress test and fixes issues the new test exposed + + Low: loop_pool_kqueue: remove potentially noisy dbug statement + + Low: tests: rework bulk event msg ipc test + Some environments have very small dgram msg queues. In + these environments we have to be able to read off the event + queue before being able to send the rest of events for the + bulk event test. + + Account for fbsd ENOBUFS during stress test + + Low: tests: Adds ipc event stress test to testsuite + + Low: ipc_socket: In fbsd send() returns ENOBUFS when dgram queue is full, this should be treated similar to EAGAIN + + High: kqueue: Properly enable kqueue filter in poll loop + + Low: ipcs: Attempt to resend outstanding event notifications during event send + +2013-07-03 David Vossel <[email protected]> + + Merge pull request #75 from davidvossel/ref_count_cleanup + Low: qbipcs: update ipcs connection iterator documentation + + Low: qbipcs.h: update ipcs connection iterator documentation + + Merge pull request #74 from davidvossel/ref_count_cleanup + Properly disconnect clients when ipc dispatch fails. + +2013-07-02 David Vossel <[email protected]> + + Fix: ipcs: Disconnect shm ipc connection when poll socket returns error on msg receive + + Fix: ipcs: Properly disconnect client connection on POLLNVAL or any other error causing connection removal from mainloop. + qb_ipcs_dispatch_connection_request is a callback function registered with + mainloop, or whatever other looping thread implementation is in use. When + this callback is registered, a reference of the connection object is given + to the mainloop thread. If this callback ever returns something none zero + the callback (and corresponding fd) is unregistered from the loop automatically, + so we must decrement the reference in this instance. + + Since unregistering this callback from mainloop guarantees a disconnect + simply because requests on the fd are no longer processed, it is best + that we completely disconnect the connection (which will handle the unref) + when this callback returns an error... Otherwise since the fd is unregistered + from the mainloop thread, it may not be possible to detect a disconnect + in the future. + +2013-06-29 David Vossel <[email protected]> Simplify internal ipcs ref counting, add comments and document api behavior @@ -9,6 +148,9 @@ Low remove ref-count error in example ipcserver. + Merge pull request #73 from davidvossel/ref_count_cleanup + cleanup connection and service ref counting without changing behavior + Merge pull request #72 from davidvossel/master Fixes ref count leak in example ipcserver.c diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/build-aux/release.mk new/libqb/build-aux/release.mk --- old/libqb/build-aux/release.mk 2012-06-07 10:58:53.000000000 +0200 +++ new/libqb/build-aux/release.mk 2013-07-26 03:08:27.000000000 +0200 @@ -1,7 +1,7 @@ # to build official release tarballs, handle tagging and publish. # signing key -gpgsignkey=956EEFB5 +gpgsignkey=C38157D2 project=libqb diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/configure new/libqb/configure --- old/libqb/configure 2013-07-02 11:28:31.000000000 +0200 +++ new/libqb/configure 2013-07-26 03:09:25.000000000 +0200 @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for libqb 0.14.4.53-7c6e. +# Generated by GNU Autoconf 2.69 for libqb 0.16.0. # # Report bugs to <[email protected]>. # @@ -590,8 +590,8 @@ # Identity of this package. PACKAGE_NAME='libqb' PACKAGE_TARNAME='libqb' -PACKAGE_VERSION='0.14.4.53-7c6e' -PACKAGE_STRING='libqb 0.14.4.53-7c6e' +PACKAGE_VERSION='0.16.0' +PACKAGE_STRING='libqb 0.16.0' PACKAGE_BUGREPORT='[email protected]' PACKAGE_URL='' @@ -1374,7 +1374,7 @@ # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures libqb 0.14.4.53-7c6e to adapt to many kinds of systems. +\`configure' configures libqb 0.16.0 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1444,7 +1444,7 @@ if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of libqb 0.14.4.53-7c6e:";; + short | recursive ) echo "Configuration of libqb 0.16.0:";; esac cat <<\_ACEOF @@ -1568,7 +1568,7 @@ test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -libqb configure 0.14.4.53-7c6e +libqb configure 0.16.0 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -2345,7 +2345,7 @@ This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by libqb $as_me 0.14.4.53-7c6e, which was +It was created by libqb $as_me 0.16.0, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -4487,7 +4487,7 @@ # Define the identity of the package. PACKAGE='libqb' - VERSION='0.14.4.53-7c6e' + VERSION='0.16.0' cat >>confdefs.h <<_ACEOF @@ -19387,7 +19387,7 @@ # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by libqb $as_me 0.14.4.53-7c6e, which was +This file was extended by libqb $as_me 0.16.0, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -19453,7 +19453,7 @@ cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -libqb config.status 0.14.4.53-7c6e +libqb config.status 0.16.0 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/docs/Makefile.in new/libqb/docs/Makefile.in --- old/libqb/docs/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/docs/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -290,9 +290,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign docs/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu docs/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign docs/Makefile + $(AUTOMAKE) --gnu docs/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/docs/html.dox new/libqb/docs/html.dox --- old/libqb/docs/html.dox 2013-07-02 11:28:43.000000000 +0200 +++ new/libqb/docs/html.dox 2013-07-26 03:09:56.000000000 +0200 @@ -1,6 +1,6 @@ DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = libqb -PROJECT_NUMBER = 0.14.4.53-7c6e +PROJECT_NUMBER = 0.16.0 OUTPUT_DIRECTORY = . CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/docs/man.dox new/libqb/docs/man.dox --- old/libqb/docs/man.dox 2013-07-02 11:28:43.000000000 +0200 +++ new/libqb/docs/man.dox 2013-07-26 03:09:56.000000000 +0200 @@ -1,6 +1,6 @@ DOXYFILE_ENCODING = UTF-8 PROJECT_NAME = libqb -PROJECT_NUMBER = 0.14.4.53-7c6e +PROJECT_NUMBER = 0.16.0 OUTPUT_DIRECTORY = . CREATE_SUBDIRS = NO OUTPUT_LANGUAGE = English diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/examples/Makefile.in new/libqb/examples/Makefile.in --- old/libqb/examples/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/examples/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -325,9 +325,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign examples/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu examples/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign examples/Makefile + $(AUTOMAKE) --gnu examples/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/examples/ipcclient.c new/libqb/examples/ipcclient.c --- old/libqb/examples/ipcclient.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/examples/ipcclient.c 2013-07-25 08:36:33.000000000 +0200 @@ -53,7 +53,7 @@ _benchmark(qb_ipcc_connection_t *conn, int write_size) { struct iovec iov[2]; - unsigned int res; + ssize_t res; struct qb_ipc_request_header hdr; int write_count = 0; float secs; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/examples/ipcserver.c new/libqb/examples/ipcserver.c --- old/libqb/examples/ipcserver.c 2013-07-02 11:27:40.000000000 +0200 +++ new/libqb/examples/ipcserver.c 2013-07-25 08:36:33.000000000 +0200 @@ -181,8 +181,9 @@ #ifdef HAVE_GLIB struct gio_to_qb_poll { gboolean is_used; - GIOChannel *channel; int32_t events; + int32_t source; + int32_t fd; void *data; qb_ipcs_dispatch_fn_t fn; enum qb_loop_priority p; @@ -197,6 +198,16 @@ return (adaptor->fn(fd, condition, adaptor->data) == 0); } +static void +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; +} + 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) @@ -218,14 +229,19 @@ return -ENOMEM; } - adaptor->channel = channel; adaptor->fn = fn; adaptor->events = evts; adaptor->data = data; adaptor->p = p; adaptor->is_used = TRUE; + adaptor->fd = fd; + + adaptor->source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT, evts, gio_read_socket, adaptor, gio_poll_destroy); + + /* we are handing the channel off to be managed by mainloop now. + * remove our reference. */ + g_io_channel_unref(channel); - g_io_add_watch(channel, evts, gio_read_socket, adaptor); return 0; } @@ -241,7 +257,7 @@ { struct gio_to_qb_poll *adaptor; if (qb_array_index(gio_map, fd, (void **)&adaptor) == 0) { - g_io_channel_unref(adaptor->channel); + g_source_remove(adaptor->source); adaptor->is_used = FALSE; } return 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/examples/tcpserver.c new/libqb/examples/tcpserver.c --- old/libqb/examples/tcpserver.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/examples/tcpserver.c 2013-07-25 08:36:33.000000000 +0200 @@ -66,7 +66,10 @@ } else { printf("Recieved: %s\n", recv_data); snprintf(send_data, 1024, "ACK %d bytes", bytes_recieved); - send(fd, send_data, strlen(send_data), 0); + if (send(fd, send_data, strlen(send_data), 0) < 0) { + close(fd); + return QB_FALSE; + } } return QB_TRUE; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/include/Makefile.in new/libqb/include/Makefile.in --- old/libqb/include/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/include/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -289,9 +289,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign include/Makefile + $(AUTOMAKE) --gnu include/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/include/qb/Makefile.in new/libqb/include/qb/Makefile.in --- old/libqb/include/qb/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/include/qb/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -282,9 +282,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign include/qb/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu include/qb/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign include/qb/Makefile + $(AUTOMAKE) --gnu include/qb/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/include/qb/qbipcc.h new/libqb/include/qb/qbipcc.h --- old/libqb/include/qb/qbipcc.h 2012-06-07 10:58:53.000000000 +0200 +++ new/libqb/include/qb/qbipcc.h 2013-07-25 08:36:33.000000000 +0200 @@ -70,11 +70,34 @@ * @param name name of the service. * @param max_msg_size biggest msg size. * @return NULL (error: see errno) or a connection object. + * + * @note It is recommended to do a one time check on the + * max_msg_size value using qb_ipcc_verify_dgram_max_msg_size + * _BEFORE_ calling the connect function when IPC_SOCKET is in use. + * Some distributions while allow large message buffers to be + * set on the socket, but not actually honor them because of + * kernel state values. The qb_ipcc_verify_dgram_max_msg_size + * function both sets the socket buffer size and verifies it by + * doing a send/recv. */ qb_ipcc_connection_t* qb_ipcc_connect(const char *name, size_t max_msg_size); /** + * Test kernel dgram socket buffers to verify the largest size up + * to the max_msg_size value a single msg can be. Rounds down to the + * nearest 1k. + * + * @param max_msg_size biggest msg size. + * @return -1 if max size can not be detected, positive value + * representing the largest single msg up to max_msg_size + * that can successfully be sent over a unix dgram socket. + */ +int32_t +qb_ipcc_verify_dgram_max_msg_size(size_t max_msg_size); + + +/** * Disconnect an IPC connection. * * @param c connection instance diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/include/qb/qbipcs.h new/libqb/include/qb/qbipcs.h --- old/libqb/include/qb/qbipcs.h 2013-07-02 11:27:40.000000000 +0200 +++ new/libqb/include/qb/qbipcs.h 2013-07-22 08:51:47.000000000 +0200 @@ -388,7 +388,7 @@ /** * Get the first connection. * - * @note call qb_ipcs_connection_ref_dec() after using the connection. + * @note call qb_ipcs_connection_unref() after using the connection. * * @param pt service instance * @return first connection @@ -398,7 +398,7 @@ /** * Get the next connection. * - * @note call qb_ipcs_connection_ref_dec() after using the connection. + * @note call qb_ipcs_connection_unref() after using the connection. * * @param pt service instance * @param current current connection diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/Makefile.am new/libqb/lib/Makefile.am --- old/libqb/lib/Makefile.am 2013-06-08 07:44:23.000000000 +0200 +++ new/libqb/lib/Makefile.am 2013-07-26 03:08:27.000000000 +0200 @@ -29,38 +29,7 @@ lib_LTLIBRARIES = libqb.la -# From: http://sourceware.org/autobook/autobook/autobook_91.html -# (for my own sanity). -# -# 1) If you have changed any of the sources for this library, the revision -# number must be incremented. This is a new revision of the current -# interface. -# -# 2) If the interface has changed, then current must be incremented, and -# revision reset to `0'. This is the first revision of a new interface. -# -# 3) If the new interface is a superset of the previous interface -# (that is, if the previous interface has not been broken by the changes -# in this new release), then age must be incremented. This release is -# backwards compatible with the previous release. -# -# 4) If the new interface has removed elements with respect to the previous -# interface, then you have broken backward compatibility and age must be -# reset to `0'. This release has a new, but backwards incompatible -# interface. For example, if the next release of the library included -# some new commands for an existing socket protocol, you would use -# -version-info 1:0:1. This is the first revision of a new interface. -# This release is backwards compatible with the previous release. -# Later, you implement a faster way of handling part of the algorithm -# at the core of the library, and release it with -version-info 1:1:1. -# This is a new revision of the current interface. -# Unfortunately the speed of your new implementation can only be fully -# exploited by changing the API to access the structures at a lower level, -# which breaks compatibility with the previous interface, so you release -# it as -version-info 2:0:0. This release has a new, but backwards -# incompatible interface. -# -libqb_la_LDFLAGS = -version-info 14:4:14 +libqb_la_LDFLAGS = -version-number 0:16:0 source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \ array.c loop.c loop_poll.c loop_job.c \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/Makefile.in new/libqb/lib/Makefile.in --- old/libqb/lib/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/lib/Makefile.in 2013-07-26 03:09:26.000000000 +0200 @@ -333,39 +333,7 @@ AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include lib_LTLIBRARIES = libqb.la - -# From: http://sourceware.org/autobook/autobook/autobook_91.html -# (for my own sanity). -# -# 1) If you have changed any of the sources for this library, the revision -# number must be incremented. This is a new revision of the current -# interface. -# -# 2) If the interface has changed, then current must be incremented, and -# revision reset to `0'. This is the first revision of a new interface. -# -# 3) If the new interface is a superset of the previous interface -# (that is, if the previous interface has not been broken by the changes -# in this new release), then age must be incremented. This release is -# backwards compatible with the previous release. -# -# 4) If the new interface has removed elements with respect to the previous -# interface, then you have broken backward compatibility and age must be -# reset to `0'. This release has a new, but backwards incompatible -# interface. For example, if the next release of the library included -# some new commands for an existing socket protocol, you would use -# -version-info 1:0:1. This is the first revision of a new interface. -# This release is backwards compatible with the previous release. -# Later, you implement a faster way of handling part of the algorithm -# at the core of the library, and release it with -version-info 1:1:1. -# This is a new revision of the current interface. -# Unfortunately the speed of your new implementation can only be fully -# exploited by changing the API to access the structures at a lower level, -# which breaks compatibility with the previous interface, so you release -# it as -version-info 2:0:0. This release has a new, but backwards -# incompatible interface. -# -libqb_la_LDFLAGS = -version-info 14:4:14 +libqb_la_LDFLAGS = -version-number 0:16:0 source_to_lint = util.c hdb.c ringbuffer.c ringbuffer_helper.c \ array.c loop.c loop_poll.c loop_job.c \ loop_timerlist.c ipcc.c ipcs.c ipc_shm.c \ @@ -401,9 +369,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign lib/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu lib/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign lib/Makefile + $(AUTOMAKE) --gnu lib/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipc_int.h new/libqb/lib/ipc_int.h --- old/libqb/lib/ipc_int.h 2013-06-08 07:44:23.000000000 +0200 +++ new/libqb/lib/ipc_int.h 2013-07-25 08:36:33.000000000 +0200 @@ -196,7 +196,6 @@ int32_t qb_ipcc_us_sock_connect(const char *socket_name, int32_t * sock_pt); int32_t qb_ipcs_dispatch_connection_request(int32_t fd, int32_t revents, void *data); -int32_t qb_ipcs_dispatch_service_request(int32_t fd, int32_t revents, void *data); struct qb_ipcs_connection* qb_ipcs_connection_alloc(struct qb_ipcs_service *s); int32_t qb_ipcs_process_request(struct qb_ipcs_service *s, diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipc_setup.c new/libqb/lib/ipc_setup.c --- old/libqb/lib/ipc_setup.c 2013-03-27 09:16:31.000000000 +0100 +++ new/libqb/lib/ipc_setup.c 2013-07-22 08:51:47.000000000 +0200 @@ -122,7 +122,9 @@ int32_t qb_ipc_us_sock_error_is_disconnected(int err) { - if (err == -EAGAIN || + if (err >= 0) { + return QB_FALSE; + } else if (err == -EAGAIN || err == -ETIMEDOUT || err == -EINTR || #ifdef EWOULDBLOCK diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipc_shm.c new/libqb/lib/ipc_shm.c --- old/libqb/lib/ipc_shm.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/lib/ipc_shm.c 2013-07-25 08:36:33.000000000 +0200 @@ -229,8 +229,8 @@ if (c->setup.u.us.sock > 0) { qb_ipcc_us_sock_close(c->setup.u.us.sock); (void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock); - qb_ipcs_connection_unref(c); c->setup.u.us.sock = -1; + qb_ipcs_connection_unref(c); } } if (c->state == QB_IPCS_CONNECTION_SHUTTING_DOWN || diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipc_socket.c new/libqb/lib/ipc_socket.c --- old/libqb/lib/ipc_socket.c 2013-03-27 09:16:31.000000000 +0100 +++ new/libqb/lib/ipc_socket.c 2013-07-25 08:36:33.000000000 +0200 @@ -104,10 +104,16 @@ rc = getsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &optval, &optlen); - qb_util_log(LOG_DEBUG, "%d: getsockopt(%d, needed:%d) actual:%d", - rc, sockfd, max_msg_size, optval); + qb_util_log(LOG_TRACE, "%d: getsockopt(%d, needed:%d) actual:%d", + rc, sockfd, max_msg_size, optval); - if (rc == 0 && optval < max_msg_size) { + /* The optvat <= max_msg_size check is weird... + * during testing it was discovered in some instances if the + * default optval is exactly equal to our max_msg_size, we couldn't + * actually send a message that large unless we explicilty set + * it using setsockopt... there is no good explaination for this. Most + * likely this is hitting some sort of "off by one" error in the kernel. */ + if (rc == 0 && optval <= max_msg_size) { optval = max_msg_size; optlen = sizeof(optval); rc = setsockopt(sockfd, SOL_SOCKET, SO_SNDBUF, &optval, optlen); @@ -115,6 +121,86 @@ return rc; } +static int32_t +dgram_verify_msg_size(size_t max_msg_size) +{ + int32_t rc = -1; + int32_t sockets[2]; + int32_t tries = 0; + int32_t write_passed = 0; + int32_t read_passed = 0; + char buf[max_msg_size]; + + if (socketpair(AF_UNIX, SOCK_DGRAM, 0, sockets) < 0) { + goto cleanup_socks; + } + + if (set_sock_size(sockets[0], max_msg_size) != 0) { + goto cleanup_socks; + } + if (set_sock_size(sockets[1], max_msg_size) != 0) { + goto cleanup_socks; + } + + for (tries = 0; tries < 3; tries++) { + + if (write_passed == 0) { + rc = write(sockets[1], buf, max_msg_size); + + if (rc < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else if (rc == max_msg_size) { + write_passed = 1; + } else { + break; + } + } + + if (read_passed == 0) { + rc = read(sockets[0], buf, max_msg_size); + + if (rc < 0 && (errno == EAGAIN || errno == EINTR)) { + continue; + } else if (rc == max_msg_size) { + read_passed = 1; + } else { + break; + } + } + + if (read_passed && write_passed) { + rc = 0; + break; + } + } + + +cleanup_socks: + close(sockets[0]); + close(sockets[1]); + return rc; +} + +int32_t +qb_ipcc_verify_dgram_max_msg_size(size_t max_msg_size) +{ + int32_t i; + int32_t last = -1; + + if (dgram_verify_msg_size(max_msg_size) == 0) { + return max_msg_size; + } + + for (i = 1024; i < max_msg_size; i+=1024) { + if (dgram_verify_msg_size(i) != 0) { + break; + } + last = i; + } + + return last; +} + /* * bind to "base_name-local_name" * connect to "base_name-remote_name" @@ -219,8 +305,8 @@ rc = send(one_way->u.us.sock, msg_ptr, msg_len, MSG_NOSIGNAL); if (rc == -1) { rc = -errno; - if (errno != EAGAIN) { - qb_util_perror(LOG_ERR, "socket_send:send"); + if (errno != EAGAIN && errno != ENOBUFS) { + qb_util_perror(LOG_DEBUG, "socket_send:send"); } } qb_sigpipe_ctl(QB_SIGPIPE_DEFAULT); @@ -254,8 +340,8 @@ if (rc == -1) { rc = -errno; - if (errno != EAGAIN) { - qb_util_perror(LOG_ERR, "socket_sendv:writev %d", + if (errno != EAGAIN && errno != ENOBUFS) { + qb_util_perror(LOG_DEBUG, "socket_sendv:writev %d", one_way->u.us.sock); } } @@ -401,6 +487,7 @@ c->event.u.us.shared_data = shm_ptr + (2 * sizeof(struct ipc_us_control)); close(fd_hdr); + fd_hdr = -1; res = qb_ipc_dgram_sock_connect(r->response, "response", "request", r->max_msg_size, &c->request.u.us.sock); @@ -418,7 +505,9 @@ return 0; cleanup_hdr: - close(fd_hdr); + if (fd_hdr >= 0) { + close(fd_hdr); + } close(c->event.u.us.sock); close(c->request.u.us.sock); unlink(r->request); @@ -439,6 +528,7 @@ fd, revents, c->description); if (revents & POLLNVAL) { qb_util_log(LOG_DEBUG, "NVAL conn (%s)", c->description); + qb_ipcs_disconnect(c); return -EINVAL; } if (revents & POLLHUP) { @@ -446,6 +536,28 @@ qb_ipcs_disconnect(c); return -ESHUTDOWN; } + + /* If we actually get POLLIN for some reason here, it most + * certainly means EOF. Do a recv on the fd to detect eof and + * then disconnect */ + if (revents & POLLIN) { + char buf[10]; + int res; + + res = recv(fd, buf, sizeof(buf), MSG_DONTWAIT); + if (res < 0 && errno != EAGAIN && errno != EWOULDBLOCK) { + res = -errno; + } else if (res == 0) { + qb_util_log(LOG_DEBUG, "EOF conn (%s)", c->description); + res = -ESHUTDOWN; + } + + if (res < 0) { + qb_ipcs_disconnect(c); + return res; + } + } + return 0; } @@ -582,6 +694,7 @@ ctl->flow_control = 0; close(fd_hdr); + fd_hdr = -1; /* request channel */ res = qb_ipc_dgram_sock_setup(r->response, "request", @@ -617,7 +730,9 @@ free(c->response.u.us.sock_name); free(c->event.u.us.sock_name); - close(fd_hdr); + if (fd_hdr >= 0) { + close(fd_hdr); + } unlink(r->request); munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE); return res; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipcc.c new/libqb/lib/ipcc.c --- old/libqb/lib/ipcc.c 2013-03-27 09:16:31.000000000 +0100 +++ new/libqb/lib/ipcc.c 2013-07-22 08:51:47.000000000 +0200 @@ -110,7 +110,7 @@ poll_ms = 0; } res2 = qb_ipc_us_ready(one_way, &c->setup, poll_ms, events); - if (res2 < 0 && qb_ipc_us_sock_error_is_disconnected(res2)) { + if (qb_ipc_us_sock_error_is_disconnected(res2)) { errno = -res2; qb_util_perror(LOG_DEBUG, "%s %d %s", diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ipcs.c new/libqb/lib/ipcs.c --- old/libqb/lib/ipcs.c 2013-07-02 11:27:40.000000000 +0200 +++ new/libqb/lib/ipcs.c 2013-07-25 08:36:33.000000000 +0200 @@ -342,6 +342,10 @@ { ssize_t res = 0; + if (!c->service->needs_sock_for_poll) { + return res; + } + if (c->outstanding_notifiers > 0) { res = qb_ipc_us_send(&c->setup, c->receive_buf, c->outstanding_notifiers); @@ -349,6 +353,7 @@ if (res > 0) { c->outstanding_notifiers -= res; } + assert(c->outstanding_notifiers >= 0); if (c->outstanding_notifiers == 0) { c->poll_events = POLLIN | POLLPRI | POLLNVAL; @@ -369,6 +374,7 @@ assert(c->outstanding_notifiers >= 0); if (c->outstanding_notifiers > 0) { c->outstanding_notifiers++; + res = resend_event_notifications(c); } else { res = qb_ipc_us_send(&c->setup, &c->outstanding_notifiers, 1); if (res == -EAGAIN) { @@ -400,7 +406,7 @@ if (res == size) { c->stats.events++; resn = new_event_notification(c); - if (resn < 0 && resn != -EAGAIN) { + if (resn < 0 && resn != -EAGAIN && resn != -ENOBUFS) { errno = -resn; qb_util_perror(LOG_WARNING, "new_event_notification (%s)", @@ -409,6 +415,10 @@ } } else if (res == -EAGAIN || res == -ETIMEDOUT) { struct qb_ipc_one_way *ow = _event_sock_one_way_get(c); + + if (c->outstanding_notifiers > 0) { + resn = resend_event_notifications(c); + } if (ow) { resn = qb_ipc_us_ready(ow, &c->setup, 0, POLLOUT); if (resn < 0) { @@ -447,6 +457,10 @@ } } else if (res == -EAGAIN || res == -ETIMEDOUT) { struct qb_ipc_one_way *ow = _event_sock_one_way_get(c); + + if (c->outstanding_notifiers > 0) { + resn = resend_event_notifications(c); + } if (ow) { resn = qb_ipc_us_ready(ow, &c->setup, 0, POLLOUT); if (resn < 0) { @@ -677,9 +691,8 @@ } else if (size == 0 || hdr->id == QB_IPC_MSG_DISCONNECT) { qb_util_log(LOG_DEBUG, "client requesting a disconnect (%s)", c->description); - qb_ipcs_disconnect(c); - c = NULL; res = -ESHUTDOWN; + goto cleanup; } else { c->stats.requests++; res = c->service->serv_fns.msg_process(c, hdr, hdr->size); @@ -703,17 +716,6 @@ #define IPC_REQUEST_TIMEOUT 10 #define MAX_RECV_MSGS 50 -int32_t -qb_ipcs_dispatch_service_request(int32_t fd, int32_t revents, void *data) -{ - int32_t res = _process_request_((struct qb_ipcs_connection *)data, - IPC_REQUEST_TIMEOUT); - if (res > 0) { - return 0; - } - return res; -} - static ssize_t _request_q_len_get(struct qb_ipcs_connection *c) { @@ -741,22 +743,24 @@ { struct qb_ipcs_connection *c = (struct qb_ipcs_connection *)data; char bytes[MAX_RECV_MSGS]; - int32_t res; + int32_t res = 0; int32_t res2; int32_t recvd = 0; ssize_t avail; if (revents & POLLNVAL) { qb_util_log(LOG_DEBUG, "NVAL conn (%s)", c->description); - return -EINVAL; + res = -EINVAL; + goto dispatch_cleanup; } if (revents & POLLHUP) { qb_util_log(LOG_DEBUG, "HUP conn (%s)", c->description); - qb_ipcs_disconnect(c); - return -ESHUTDOWN; + res = -ESHUTDOWN; + goto dispatch_cleanup; } if (revents & POLLOUT) { + /* try resend events now that fd can write */ res = resend_event_notifications(c); if (res < 0 && res != -EAGAIN) { errno = -res; @@ -764,12 +768,15 @@ "resend_event_notifications (%s)", c->description); } + /* nothing to read */ if ((revents & POLLIN) == 0) { - return 0; + res = 0; + goto dispatch_cleanup; } } if (c->fc_enabled) { - return 0; + res = 0; + goto dispatch_cleanup; } avail = _request_q_len_get(c); @@ -779,18 +786,24 @@ errno = -res2; qb_util_perror(LOG_WARNING, "conn (%s) disconnected", c->description); - qb_ipcs_disconnect(c); - return -ESHUTDOWN; + res = -ESHUTDOWN; + goto dispatch_cleanup; } else { qb_util_log(LOG_WARNING, "conn (%s) Nothing in q but got POLLIN on fd:%d (res2:%d)", c->description, fd, res2); - return 0; + res = 0; + goto dispatch_cleanup; } } do { res = _process_request_(c, IPC_REQUEST_TIMEOUT); + + if (res == -ESHUTDOWN) { + goto dispatch_cleanup; + } + if (res > 0 || res == -ENOBUFS || res == -EINVAL) { recvd++; } @@ -801,11 +814,12 @@ if (c->service->needs_sock_for_poll && recvd > 0) { res2 = qb_ipc_us_recv(&c->setup, bytes, recvd, -1); - if (res2 < 0) { + if (qb_ipc_us_sock_error_is_disconnected(res2)) { errno = -res2; - qb_util_perror(LOG_ERR, - "error receiving from setup sock (%s)", - c->description); + qb_util_perror(LOG_ERR, "error receiving from setup sock (%s)", c->description); + + res = -ESHUTDOWN; + goto dispatch_cleanup; } } @@ -822,9 +836,12 @@ qb_util_perror(LOG_ERR, "request returned error (%s)", c->description); } - qb_ipcs_connection_unref(c); } +dispatch_cleanup: + if (res != 0) { + qb_ipcs_disconnect(c); + } return res; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/log_thread.c new/libqb/lib/log_thread.c --- old/libqb/lib/log_thread.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/lib/log_thread.c 2013-07-25 08:36:33.000000000 +0200 @@ -249,7 +249,7 @@ for (;;) { res = sem_getvalue(&logt_print_finished, &value); if (res != 0 || value == 0) { - return; + break; } sem_wait(&logt_print_finished); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/loop_poll_kqueue.c new/libqb/lib/loop_poll_kqueue.c --- old/libqb/lib/loop_poll_kqueue.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/lib/loop_poll_kqueue.c 2013-07-22 08:51:47.000000000 +0200 @@ -55,7 +55,7 @@ struct kevent ke; short filters = _poll_to_filter_(events); - EV_SET(&ke, fd, filters, EV_ADD, 0, 0, (intptr_t)pe); + EV_SET(&ke, fd, filters, EV_ADD | EV_ENABLE, 0, 0, (intptr_t)pe); res = kevent(s->epollfd, &ke, 1, NULL, 0, NULL); if (res == -1) { @@ -75,7 +75,7 @@ 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, 0, 0, (intptr_t)pe); + EV_SET(&ke[1], fd, new_filters, EV_ADD | EV_ENABLE, 0, 0, (intptr_t)pe); res = kevent(s->epollfd, ke, 2, NULL, 0, NULL); if (res == -1) { @@ -140,11 +140,13 @@ for (i = 0; i < event_count; i++) { revents = 0; pe = (struct qb_poll_entry *)events[i].udata; +#if 0 if (events[i].flags) { qb_util_log(LOG_TRACE, "got flags %d on fd %d.", events[i].flags, pe->ufd.fd); } +#endif if (events[i].flags & EV_ERROR) { qb_util_log(LOG_WARNING, "got EV_ERROR on fd %d.", pe->ufd.fd); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/ringbuffer.c new/libqb/lib/ringbuffer.c --- old/libqb/lib/ringbuffer.c 2013-07-02 11:27:40.000000000 +0200 +++ new/libqb/lib/ringbuffer.c 2013-07-25 08:36:33.000000000 +0200 @@ -141,7 +141,14 @@ #ifdef 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 + * to be reflective of the max size single write we can do to the + * ringbuffer. This means we have to add both the 'margin' space used + * to calculate if there is enough space for a new chunk as well as the '+1' that + * prevents overlap of the read/write pointers */ + size += QB_RB_CHUNK_MARGIN + 1; real_size = QB_ROUNDUP(size, page_size); + shared_size = sizeof(struct qb_ringbuffer_shared_s) + shared_user_data_size; @@ -228,6 +235,7 @@ "shm size:%zd; real_size:%zd; rb->word_size:%d", size, real_size, rb->shared_hdr->word_size); + /* this function closes fd_data */ error = qb_sys_circular_mmap(fd_data, &shm_addr, real_size); rb->shared_data = shm_addr; if (error != 0) { @@ -245,11 +253,9 @@ } close(fd_hdr); - close(fd_data); return rb; cleanup_data: - close(fd_data); if (flags & QB_RB_FLAG_CREATE) { unlink(rb->shared_hdr->data_path); } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/lib/unix.c new/libqb/lib/unix.c --- old/libqb/lib/unix.c 2013-06-08 07:44:23.000000000 +0200 +++ new/libqb/lib/unix.c 2013-07-25 08:36:33.000000000 +0200 @@ -141,7 +141,7 @@ unlink_exit: unlink(path); - if (fd > 0) { + if (fd >= 0) { close(fd); } return res; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/tests/Makefile.in new/libqb/tests/Makefile.in --- old/libqb/tests/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/tests/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -543,9 +543,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tests/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tests/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign tests/Makefile + $(AUTOMAKE) --gnu tests/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/tests/bms.c new/libqb/tests/bms.c --- old/libqb/tests/bms.c 2013-03-07 09:03:14.000000000 +0100 +++ new/libqb/tests/bms.c 2013-07-25 08:36:33.000000000 +0200 @@ -116,6 +116,7 @@ sizeof(response)); if (res < 0) { qb_perror(LOG_ERR, "qb_ipcs_response_send"); + return res; } } if (events) { @@ -123,6 +124,7 @@ sizeof(response)); if (res < 0) { qb_perror(LOG_ERR, "qb_ipcs_event_send"); + return res; } } return 0; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/tests/check_ipc.c new/libqb/tests/check_ipc.c --- old/libqb/tests/check_ipc.c 2013-07-02 11:27:40.000000000 +0200 +++ new/libqb/tests/check_ipc.c 2013-07-25 08:36:33.000000000 +0200 @@ -33,7 +33,21 @@ #include <qb/qbloop.h> static const char *ipc_name = "ipc_test"; -#define MAX_MSG_SIZE (8192*16) + +#define DEFAULT_MAX_MSG_SIZE (8192*16) +static int CALCULATED_DGRAM_MAX_MSG_SIZE = 0; + +#define DGRAM_MAX_MSG_SIZE \ + (CALCULATED_DGRAM_MAX_MSG_SIZE == 0 ? \ + CALCULATED_DGRAM_MAX_MSG_SIZE = qb_ipcc_verify_dgram_max_msg_size(DEFAULT_MAX_MSG_SIZE) : \ + CALCULATED_DGRAM_MAX_MSG_SIZE) + +#define MAX_MSG_SIZE (ipc_type == QB_IPC_SOCKET ? DGRAM_MAX_MSG_SIZE : DEFAULT_MAX_MSG_SIZE) + +/* The size the giant msg's data field needs to be to make + * this the largests msg we can successfully send. */ +#define GIANT_MSG_DATA_SIZE MAX_MSG_SIZE - sizeof(struct qb_ipc_response_header) - 8 + static qb_ipcc_connection_t *conn; static enum qb_ipc_type ipc_type; @@ -44,6 +58,8 @@ IPC_MSG_RES_DISPATCH, IPC_MSG_REQ_BULK_EVENTS, IPC_MSG_RES_BULK_EVENTS, + IPC_MSG_REQ_STRESS_EVENT, + IPC_MSG_RES_STRESS_EVENT, IPC_MSG_REQ_SERVER_FAIL, IPC_MSG_RES_SERVER_FAIL, IPC_MSG_REQ_SERVER_DISCONNECT, @@ -75,6 +91,7 @@ static int32_t send_event_on_created = QB_FALSE; 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; @@ -91,7 +108,7 @@ void *data, size_t size) { struct qb_ipc_request_header *req_pt = (struct qb_ipc_request_header *)data; - struct qb_ipc_response_header response; + struct qb_ipc_response_header response = { 0, }; ssize_t res; if (req_pt->id == IPC_MSG_REQ_TX_RX) { @@ -134,9 +151,26 @@ MAX_MSG_SIZE*10); ck_assert_int_eq(res, -EMSGSIZE); - for (m = 0; m < num_bulk_events; m++) { - res = qb_ipcs_event_send(c, &response, - sizeof(response)); + /* send one event before responding */ + res = qb_ipcs_event_send(c, &response, sizeof(response)); + ck_assert_int_eq(res, sizeof(response)); + response.id++; + + /* send response */ + response.id = IPC_MSG_RES_BULK_EVENTS; + res = qb_ipcs_response_send(c, &response, response.size); + ck_assert_int_eq(res, sizeof(response)); + + /* send the rest of the events after the response */ + for (m = 1; m < num_bulk_events; m++) { + res = qb_ipcs_event_send(c, &response, sizeof(response)); + + if (res == -EAGAIN || res == -ENOBUFS) { + /* retry */ + usleep(1000); + m--; + continue; + } ck_assert_int_eq(res, sizeof(response)); response.id++; } @@ -144,10 +178,49 @@ ck_assert_int_eq(stats->event_q_length - num, num_bulk_events); free(stats); - response.id = IPC_MSG_RES_BULK_EVENTS; + } else if (req_pt->id == IPC_MSG_REQ_STRESS_EVENT) { + struct { + struct qb_ipc_response_header hdr __attribute__ ((aligned(8))); + char data[GIANT_MSG_DATA_SIZE] __attribute__ ((aligned(8))); + uint32_t sent_msgs __attribute__ ((aligned(8))); + } __attribute__ ((aligned(8))) giant_event_send; + int32_t m; + + response.size = sizeof(struct qb_ipc_response_header); + response.error = 0; + + response.id = IPC_MSG_RES_STRESS_EVENT; res = qb_ipcs_response_send(c, &response, response.size); ck_assert_int_eq(res, sizeof(response)); + giant_event_send.hdr.error = 0; + giant_event_send.hdr.id = IPC_MSG_RES_STRESS_EVENT; + for (m = 0; m < num_stress_events; m++) { + size_t sent_len = sizeof(struct qb_ipc_response_header); + + if (((m+1) % 1000) == 0) { + sent_len = sizeof(giant_event_send); + giant_event_send.sent_msgs = m + 1; + } + giant_event_send.hdr.size = sent_len; + + res = qb_ipcs_event_send(c, &giant_event_send, sent_len); + if (res < 0) { + if (res == -EAGAIN || res == -ENOBUFS) { + /* yield to the receive process */ + usleep(1000); + m--; + continue; + } else { + qb_perror(LOG_DEBUG, "sending stress events"); + ck_assert_int_eq(res, sent_len); + } + } else if (((m+1) % 1000) == 0) { + qb_log(LOG_DEBUG, "SENT: %d stress events sent", m+1); + } + giant_event_send.hdr.id++; + } + } else if (req_pt->id == IPC_MSG_REQ_SERVER_FAIL) { exit(0); } else if (req_pt->id == IPC_MSG_REQ_SERVER_DISCONNECT) { @@ -635,6 +708,45 @@ static int32_t events_received; +static int32_t +count_stress_events(int32_t fd, int32_t revents, void *data) +{ + struct { + struct qb_ipc_response_header hdr __attribute__ ((aligned(8))); + char data[GIANT_MSG_DATA_SIZE] __attribute__ ((aligned(8))); + uint32_t sent_msgs __attribute__ ((aligned(8))); + } __attribute__ ((aligned(8))) giant_event_recv; + qb_loop_t *cl = (qb_loop_t*)data; + int32_t res; + + res = qb_ipcc_event_recv(conn, &giant_event_recv, + sizeof(giant_event_recv), + -1); + if (res > 0) { + events_received++; + + if ((events_received % 1000) == 0) { + qb_log(LOG_DEBUG, "RECV: %d stress events processed", events_received); + if (res != sizeof(giant_event_recv)) { + qb_log(LOG_DEBUG, "Unexpected recv size, expected %d got %d", + res, sizeof(giant_event_recv)); + } else if (giant_event_recv.sent_msgs != events_received) { + qb_log(LOG_DEBUG, "Server event mismatch. Server thinks we got %d msgs, but we only received %d", + giant_event_recv.sent_msgs, events_received); + } + } + } else if (res != -EAGAIN) { + qb_perror(LOG_DEBUG, "count_stress_events"); + qb_loop_stop(cl); + return -1; + } + + if (events_received >= num_stress_events) { + qb_loop_stop(cl); + return -1; + } + return 0; +} static int32_t count_bulk_events(int32_t fd, int32_t revents, void *data) @@ -719,6 +831,78 @@ stop_process(pid); } +static void +test_ipc_stress_test(void) +{ + struct qb_ipc_request_header req_header; + struct qb_ipc_response_header res_header; + struct iovec iov[1]; + int32_t c = 0; + int32_t j = 0; + pid_t pid; + int32_t res; + qb_loop_t *cl; + int32_t fd; + + pid = run_function_in_new_process(run_ipc_server); + fail_if(pid == -1); + sleep(1); + + do { + conn = qb_ipcc_connect(ipc_name, MAX_MSG_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); + + qb_log(LOG_DEBUG, "Testing %d iterations of EVENT msg passing.", num_stress_events); + + events_received = 0; + cl = qb_loop_create(); + res = qb_ipcc_fd_get(conn, &fd); + ck_assert_int_eq(res, 0); + res = qb_loop_poll_add(cl, QB_LOOP_MED, + fd, POLLIN, + cl, count_stress_events); + ck_assert_int_eq(res, 0); + + res = send_and_check(IPC_MSG_REQ_STRESS_EVENT, 0, recv_timeout, QB_TRUE); + + qb_loop_run(cl); + ck_assert_int_eq(events_received, num_stress_events); + + req_header.id = IPC_MSG_REQ_SERVER_FAIL; + req_header.size = sizeof(struct qb_ipc_request_header); + + iov[0].iov_len = req_header.size; + iov[0].iov_base = &req_header; + res = qb_ipcc_sendv_recv(conn, iov, 1, + &res_header, + sizeof(struct qb_ipc_response_header), -1); + if (res != -ECONNRESET && res != -ENOTCONN) { + qb_log(LOG_ERR, "id:%d size:%d", res_header.id, res_header.size); + ck_assert_int_eq(res, -ENOTCONN); + } + + qb_ipcc_disconnect(conn); + stop_process(pid); +} + +START_TEST(test_ipc_stress_test_us) +{ + qb_enter(); + send_event_on_created = QB_FALSE; + ipc_type = QB_IPC_SOCKET; + ipc_name = __func__; + test_ipc_stress_test(); + qb_leave(); +} +END_TEST + START_TEST(test_ipc_bulk_events_us) { qb_enter(); @@ -918,6 +1102,17 @@ } END_TEST +START_TEST(test_ipc_stress_test_shm) +{ + qb_enter(); + send_event_on_created = QB_FALSE; + ipc_type = QB_IPC_SHM; + ipc_name = __func__; + test_ipc_stress_test(); + qb_leave(); +} +END_TEST + START_TEST(test_ipc_bulk_events_shm) { qb_enter(); @@ -1000,6 +1195,37 @@ } END_TEST +static void test_max_dgram_size(void) +{ + /* most implementations will not let you set a dgram buffer + * of 1 million bytes. This test verifies that the we can detect + * the max dgram buffersize regardless, and that the value we detect + * is consistent. */ + int32_t init; + int32_t i; + + qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_REMOVE, + QB_LOG_FILTER_FILE, "*", LOG_TRACE); + + init = qb_ipcc_verify_dgram_max_msg_size(1000000); + fail_if(init <= 0); + for (i = 0; i < 100; i++) { + int try = qb_ipcc_verify_dgram_max_msg_size(1000000); + ck_assert_int_eq(init, try); + } + + qb_log_filter_ctl(QB_LOG_STDERR, QB_LOG_FILTER_ADD, + QB_LOG_FILTER_FILE, "*", LOG_TRACE); +} + +START_TEST(test_ipc_max_dgram_size) +{ + qb_enter(); + test_max_dgram_size(); + qb_leave(); +} +END_TEST + static Suite * make_shm_suite(void) { @@ -1031,6 +1257,11 @@ tcase_set_timeout(tc, 16); suite_add_tcase(s, tc); + tc = tcase_create("ipc_stress_test_shm"); + tcase_add_test(tc, test_ipc_stress_test_shm); + tcase_set_timeout(tc, 16); + suite_add_tcase(s, tc); + tc = tcase_create("ipc_bulk_events_shm"); tcase_add_test(tc, test_ipc_bulk_events_shm); tcase_set_timeout(tc, 16); @@ -1059,6 +1290,11 @@ Suite *s = suite_create("socket"); TCase *tc; + tc = tcase_create("ipc_max_dgram_size"); + tcase_add_test(tc, test_ipc_max_dgram_size); + tcase_set_timeout(tc, 30); + suite_add_tcase(s, tc); + tc = tcase_create("ipc_server_fail_soc"); tcase_add_test(tc, test_ipc_server_fail_soc); tcase_set_timeout(tc, 6); @@ -1089,6 +1325,11 @@ tcase_set_timeout(tc, 16); suite_add_tcase(s, tc); + tc = tcase_create("ipc_stress_test_us"); + tcase_add_test(tc, test_ipc_stress_test_us); + tcase_set_timeout(tc, 60); + suite_add_tcase(s, tc); + tc = tcase_create("ipc_bulk_events_us"); tcase_add_test(tc, test_ipc_bulk_events_us); tcase_set_timeout(tc, 16); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/libqb/tools/Makefile.in new/libqb/tools/Makefile.in --- old/libqb/tools/Makefile.in 2013-07-02 11:28:30.000000000 +0200 +++ new/libqb/tools/Makefile.in 2013-07-25 10:58:37.000000000 +0200 @@ -282,9 +282,9 @@ exit 1;; \ esac; \ done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign tools/Makefile'; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu tools/Makefile'; \ $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign tools/Makefile + $(AUTOMAKE) --gnu tools/Makefile .PRECIOUS: Makefile Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status @case '$?' in \ -- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
